diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index d8feb10757f806eac14beb9c2e9b1cff8fe05d27..5d414df5d674a23aed6d533d19e7071526456008 100644
--- a/indra/llmath/v3dmath.h
+++ b/indra/llmath/v3dmath.h
@@ -405,5 +405,14 @@ inline BOOL are_parallel(const LLVector3d &a, const LLVector3d &b, const F64 eps
 		return TRUE;
 	}
 	return FALSE;
+
 }
+
+inline LLVector3d projected_vec(const LLVector3d &a, const LLVector3d &b)
+{
+	LLVector3d project_axis = b;
+	project_axis.normVec();
+	return project_axis * (a * project_axis);
+}
+
 #endif // LL_V3DMATH_H
diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp
index 3b054d2fec8b05c9469aea7dee18f41756f801a1..fde27132e64741717457c4c1486104826a5f7b40 100644
--- a/indra/llui/llcheckboxctrl.cpp
+++ b/indra/llui/llcheckboxctrl.cpp
@@ -274,8 +274,6 @@ LLView* LLCheckBoxCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto
 	LLString label("");
 	node->getAttributeString("label", label);
 
-	BOOL initial_value = FALSE;
-	
 	LLFontGL* font = LLView::selectFont(node);
 
 	BOOL radio_style = FALSE;
@@ -297,9 +295,12 @@ LLView* LLCheckBoxCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto
 		font,
 		callback,
 		NULL,
-		initial_value,
+		FALSE,
 		radio_style); // if true, draw radio button style icons
 
+	BOOL initial_value = checkbox->getValue().asBoolean();
+	node->getAttributeBOOL("initial_value", initial_value);
+
 	LLColor4 color;
 	color = LLUI::sColorsGroup->getColor( "LabelTextColor" );
 	LLUICtrlFactory::getAttributeColor(node,"text_enabled_color", color);
@@ -309,6 +310,8 @@ LLView* LLCheckBoxCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto
 	LLUICtrlFactory::getAttributeColor(node,"text_disabled_color", color);
 	checkbox->setDisabledColor(color);
 
+	checkbox->setValue(initial_value);
+
 	checkbox->initFromXML(node, parent);
 
 	return checkbox;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 41049fdf1fcb16abf5375144f3fbf50dbc2ef14c..46d66b3cd4c1597eb3c648525cb13e7671f74ac6 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -72,6 +72,7 @@ public:
 		ed->mSelectionStart = mSelectionStart;
 		ed->mSelectionEnd = mSelectionEnd;
 		ed->mText = mText;
+		ed->mPrevText = mText;
 	}
 
 	LLString getText()   { return mText; }
@@ -110,6 +111,7 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
 		mBorderLeft(0),
 		mBorderRight(0),
 		mCommitOnFocusLost( TRUE ),
+		mRevertOnEsc( TRUE ),
 		mKeystrokeCallback( keystroke_callback ),
 		mFocusLostCallback( focus_lost_callback ),
 		mIsSelecting( FALSE ),
@@ -151,7 +153,7 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
 	mScrollTimer.reset();
 
 	setText(default_text);
-
+	
 	setCursor(mText.length());
 
 	// Scalable UI somehow made these rectangles off-by-one.
@@ -195,7 +197,7 @@ void LLLineEditor::onFocusLost()
 		mFocusLostCallback( this, mCallbackUserData );
 	}
 	
-	if( mCommitOnFocusLost ) 
+	if( mCommitOnFocusLost && mText.getString() != mPrevText) 
 	{
 		onCommit();
 	}
@@ -281,6 +283,7 @@ void LLLineEditor::setText(const LLString &new_text)
 		deselect();
 	}
 	setCursor(llmin((S32)mText.length(), getCursor()));
+	mPrevText = mText;
 }
 
 
@@ -1064,6 +1067,14 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
 		}
 		break;
 
+	case KEY_ESCAPE:
+	    if (mRevertOnEsc && mText.getString() != mPrevText)
+		{
+			setText(mPrevText);
+			// Note, don't set handled, still want to loose focus (won't commit becase text is now unchanged)
+		}
+		break;
+		
 	default:
 		break;
 	}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 1df5dd88f718c6486cd9b156158d648252ab1195..ef2f43a1d3a78144a80be37ab87c3c4830407b7f 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -127,9 +127,10 @@ public:
 	void			setSelection(S32 start, S32 end);
 	
 	void			setCommitOnFocusLost( BOOL b )	{ mCommitOnFocusLost = b; }
+	void			setRevertOnEsc( BOOL b )		{ mRevertOnEsc = b; }
 
 	void setCursorColor(const LLColor4& c)			{ mCursorColor = c; }
-	const LLColor4& getCursorColor() const		{ return mCursorColor; }
+	const LLColor4& getCursorColor() const			{ return mCursorColor; }
 
 	void setFgColor( const LLColor4& c )			{ mFgColor = c; }
 	void setReadOnlyFgColor( const LLColor4& c )	{ mReadOnlyFgColor = c; }
@@ -202,6 +203,7 @@ protected:
 
 protected:
 	LLUIString		mText;					// The string being edited.
+	LLString		mPrevText;				// Saved string for 'ESC' revert
 	LLUIString		mLabel;					// text label that is visible when no user text provided
 
 	LLViewBorder* mBorder;
@@ -217,6 +219,7 @@ protected:
 	S32			mBorderRight;
 
 	BOOL		mCommitOnFocusLost;
+	BOOL		mRevertOnEsc;
 
 	void		(*mKeystrokeCallback)( LLLineEditor* caller, void* userdata );
 	void		(*mFocusLostCallback)( LLLineEditor* caller, void* userdata );
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index f8fcefd11dacb7b9fc96c47412a67a04d579f5ca..650596c7f746a398b870b13db1e50a718373fb99 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -90,7 +90,9 @@ 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 );
 BOOL LLMenuItemGL::sDropShadowText = TRUE;
+
 LLColor4 LLMenuGL::sDefaultBackgroundColor( 0.25f, 0.25f, 0.25f, 0.75f );
+BOOL LLMenuGL::sKeyboardMode = FALSE;
 
 LLViewHandle LLMenuHolderGL::sItemLastSelectedHandle;
 LLFrameTimer LLMenuHolderGL::sItemActivationTimer;
@@ -379,41 +381,65 @@ void LLMenuItemGL::buildDrawLabel( void )
 	mDrawAccelLabel = st;
 }
 
+void LLMenuItemGL::doIt( void )
+{
+	// close all open menus by default
+	// if parent menu is actually visible (and we are not triggering menu item via accelerator)
+	if (!getMenu()->getTornOff() && getMenu()->getVisible())
+	{
+		((LLMenuHolderGL*)getMenu()->getParent())->hideMenus();
+	}
+}
+
 // set the hover status (called by it's menu)
  void LLMenuItemGL::setHighlight( BOOL highlight )
 {
+	if (highlight)
+	{
+		getMenu()->clearHoverItem();
+	}
 	mHighlight = highlight;
 }
 
-// determine if this object is active
+// determine if this object represents an active sub-menu
 BOOL LLMenuItemGL::isActive( void ) const
 {
 	return FALSE;
 }
 
+// determine if this object represents an open sub-menu
+BOOL LLMenuItemGL::isOpen( void ) const
+{
+	return FALSE;
+}
+
 BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 {
-	if (mHighlight && 
-		getMenu()->getVisible() &&
-		(!getMenu()->getTornOff() || ((LLFloater*)getMenu()->getParent())->hasFocus()))
+	if (getHighlight() && 
+		getMenu()->isOpen())
 	{
 		if (key == KEY_UP)
 		{
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
 			getMenu()->highlightPrevItem(this);
 			return TRUE;
 		}
 		else if (key == KEY_DOWN)
 		{
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
 			getMenu()->highlightNextItem(this);
 			return TRUE;
 		}
 		else if (key == KEY_RETURN && mask == MASK_NONE)
 		{
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
 			doIt();
-			if (!getMenu()->getTornOff())
-			{
-				((LLMenuHolderGL*)getMenu()->getParent())->hideMenus();
-			}
 			return TRUE;
 		}
 	}
@@ -427,8 +453,11 @@ BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK )
 	//	<< llendl;
 	if (mEnabled)
 	{
+		// switch to mouse navigation mode
+		LLMenuGL::setKeyboardMode(FALSE);
+
 		doIt();
-		mHighlight = FALSE;
+		setHighlight(FALSE);
 		make_ui_sound("UISndClickRelease");
 		return TRUE;
 	}
@@ -444,7 +473,8 @@ void LLMenuItemGL::draw( void )
 	// that until the functionality is finalized.
 
 	// HACK: Brief items don't highlight.  Pie menu takes care of it.  JC
-	if( mHighlight && !mBriefItem)
+	// let disabled items be highlighted, just don't draw them as such
+	if( getEnabled() && getHighlight() && !mBriefItem)
 	{
 		glColor4fv( sHighlightBackground.mV );
 		gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0 );
@@ -458,7 +488,7 @@ void LLMenuItemGL::draw( void )
 		font_style |= LLFontGL::DROP_SHADOW;
 	}
 
-	if ( mHighlight )
+	if ( getEnabled() && getHighlight() )
 	{
 		color = sHighlightForeground;
 	}
@@ -498,11 +528,8 @@ void LLMenuItemGL::draw( void )
 		}
 	}
 
-	// underline navigation key
-	BOOL draw_jump_key = gKeyboard->currentMask(FALSE) == MASK_ALT && 
-								(!getMenu()->getHighlightedItem() || !getMenu()->getHighlightedItem()->isActive()) &&
-								(!getMenu()->getTornOff());
-	if (draw_jump_key)
+	// underline "jump" key
+	if (getMenu()->jumpKeysActive())
 	{
 		LLString upper_case_label = mLabel.getString();
 		LLString::toUpper(upper_case_label);
@@ -666,8 +693,6 @@ void LLMenuItemTearOffGL::doIt()
 			getMenu()->highlightNextItem(this);
 		}
 
-		// grab menu holder before this menu is parented to a floater
-		LLMenuHolderGL* menu_holder = ((LLMenuHolderGL*)getMenu()->getParent());
 		getMenu()->arrange();
 
 		LLFloater* parent_floater = LLFloater::getFloaterByHandle(mParentHandle);
@@ -677,22 +702,17 @@ void LLMenuItemTearOffGL::doIt()
 			parent_floater->addDependentFloater(tear_off_menu, FALSE);
 		}
 
-		// hide menus
-		// only do it if the menu is open, not being triggered via accelerator
-		if (getMenu()->getVisible())
-		{
-			menu_holder->hideMenus();
-		}
-
 		// give focus to torn off menu because it will have been taken away
 		// when parent menu closes
 		tear_off_menu->setFocus(TRUE);
 	}
+	LLMenuItemGL::doIt();
 }
 
 void LLMenuItemTearOffGL::draw()
 {
-	if( mHighlight && !mBriefItem)
+	// disabled items can be highlighted, but shouldn't render as such
+	if( getEnabled() && getHighlight() && !mBriefItem)
 	{
 		glColor4fv( sHighlightBackground.mV );
 		gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0 );
@@ -910,6 +930,7 @@ void LLMenuItemCallGL::doIt( void )
 	}
 	LLPointer<LLEvent> fired_event = new LLEvent(this);
 	fireEvent(fired_event, "on_click");
+	LLMenuItemGL::doIt();
 }
 
 EWidgetType LLMenuItemCallGL::getWidgetType() const 
@@ -1118,6 +1139,7 @@ void LLMenuItemToggleGL::doIt( void )
 	//llinfos << "LLMenuItemToggleGL::doIt " << mLabel.c_str() << llendl;
 	*mToggle = !(*mToggle);
 	buildDrawLabel();
+	LLMenuItemGL::doIt();
 }
 
 
@@ -1159,6 +1181,7 @@ public:
 	virtual void doIt( void );
 
 	virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
 
 	// set the hover status (called by it's menu) and if the object is
 	// active. This is used for behavior transfer.
@@ -1166,7 +1189,9 @@ public:
 
 	virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
 
-	virtual BOOL isActive() const	{ return !mBranch->getTornOff() && mBranch->getVisible(); }
+	virtual BOOL isActive() const;
+
+	virtual BOOL isOpen() const;
 
 	LLMenuGL *getBranch() const { return mBranch; }
 
@@ -1178,6 +1203,8 @@ public:
 	virtual void draw();
 
 	virtual void setEnabledSubMenus(BOOL enabled);
+
+	virtual void openMenu();
 };
 
 LLMenuItemBranchGL::LLMenuItemBranchGL( const LLString& name, const LLString& label, LLMenuGL* branch,
@@ -1215,6 +1242,9 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask)
 {
 	if (mEnabled)
 	{
+		// switch to mouse navigation mode
+		LLMenuGL::setKeyboardMode(FALSE);
+
 		doIt();
 		make_ui_sound("UISndClickRelease");
 	}
@@ -1269,50 +1299,14 @@ void LLMenuItemBranchGL::buildDrawLabel( void )
 // doIt() - do the primary functionality of the menu item.
 void LLMenuItemBranchGL::doIt( void )
 {
-	if (mBranch->getTornOff())
+	openMenu();
+
+	// keyboard navigation automatically propagates highlight to sub-menu
+	// to facilitate fast menu control via jump keys
+	if (LLMenuGL::getKeyboardMode() && !mBranch->getHighlightedItem())
 	{
-		gFloaterView->bringToFront((LLFloater*)mBranch->getParent());
-		// this might not be necessary, as torn off branches don't get focus and hence no highligth
 		mBranch->highlightNextItem(NULL);
 	}
-	else if( !mBranch->getVisible() )
-	{
-		mBranch->arrange();
-
-		LLRect rect = mBranch->getRect();
-		// calculate root-view relative position for branch menu
-		S32 left = mRect.mRight;
-		S32 top = mRect.mTop - mRect.mBottom;
-
-		localPointToOtherView(left, top, &left, &top, mBranch->getParent());
-
-		rect.setLeftTopAndSize( left, top,
-								rect.getWidth(), rect.getHeight() );
-
-		if (mBranch->getCanTearOff())
-		{
-			rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
-		}
-		mBranch->setRect( rect );
-		S32 x = 0;
-		S32 y = 0;
-		mBranch->localPointToOtherView( 0, 0, &x, &y, mBranch->getParent() ); 
-		S32 delta_x = 0;
-		S32 delta_y = 0;
-		if( y < 0 )
-		{
-			delta_y = -y;
-		}
-
-		S32 window_width = mBranch->getParent()->getRect().getWidth();
-		if( x > window_width - rect.getWidth() )
-		{
-			// move sub-menu over to left side
-			delta_x = llmax(-x, (-1 * (rect.getWidth() + mRect.getWidth())));
-		}
-		mBranch->translate( delta_x, delta_y );
-		mBranch->setVisible( TRUE );
-	}
 }
 
 BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
@@ -1331,9 +1325,34 @@ BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return handled;
 }
 
+BOOL LLMenuItemBranchGL::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
+{
+	BOOL handled = FALSE;
+	if (called_from_parent)
+	{
+		handled = mBranch->handleUnicodeChar(uni_char, TRUE);
+	}
+
+	if (!handled)
+	{
+		handled = LLMenuItemGL::handleUnicodeChar(uni_char, called_from_parent);
+	}
+
+	return handled;
+}
+
+
 // set the hover status (called by it's menu)
 void LLMenuItemBranchGL::setHighlight( BOOL highlight )
 {
+	if (highlight == getHighlight()) return;
+
+	// make sure only yourself is highlighted
+	if (highlight)
+	{
+		getMenu()->clearHoverItem();
+	}
+
 	BOOL auto_open = mEnabled && (!mBranch->getVisible() || mBranch->getTornOff());
 	// torn off menus don't open sub menus on hover unless they have focus
 	if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus())
@@ -1351,7 +1370,7 @@ void LLMenuItemBranchGL::setHighlight( BOOL highlight )
 	{
 		if(auto_open)
 		{
-			doIt();
+			openMenu();
 		}
 	}
 	else
@@ -1378,10 +1397,22 @@ void LLMenuItemBranchGL::draw()
 	LLMenuItemGL::draw();
 	if (mBranch->getVisible() && !mBranch->getTornOff())
 	{
-		mHighlight = TRUE;
+		setHighlight(TRUE);
 	}
 }
 
+// determine if this object is active
+// which, for branching menus, means the branch is open and has "focus"
+BOOL LLMenuItemBranchGL::isActive( void ) const
+{
+	return isOpen() && mBranch->getHighlightedItem();
+}
+
+BOOL LLMenuItemBranchGL::isOpen( void ) const
+{
+	return mBranch->isOpen();
+}
+
 void LLMenuItemBranchGL::updateBranchParent(LLView* parentp)
 {
 	if (mBranch->getParent() == NULL)
@@ -1403,7 +1434,14 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_par
 {
 	if (getMenu()->getVisible() && mBranch->getVisible() && key == KEY_LEFT)
 	{
+		// switch to keyboard navigation mode
+		LLMenuGL::setKeyboardMode(TRUE);
+
 		BOOL handled = mBranch->clearHoverItem();
+		if (mBranch->getTornOff())
+		{
+			((LLFloater*)mBranch->getParent())->setFocus(FALSE);
+		}
 		if (handled && getMenu()->getTornOff())
 		{
 			((LLFloater*)getMenu()->getParent())->setFocus(TRUE);
@@ -1411,12 +1449,14 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_par
 		return handled;
 	}
 
-	if (mHighlight && 
-		getMenu()->getVisible() &&
-		// ignore keystrokes on background torn-off menus
-		(!getMenu()->getTornOff() || ((LLFloater*)getMenu()->getParent())->hasFocus()) &&
+	if (getEnabled() &&
+		getHighlight() && 
+		getMenu()->isOpen() && 
 		key == KEY_RIGHT && !mBranch->getHighlightedItem())
 	{
+		// switch to keyboard navigation mode
+		LLMenuGL::setKeyboardMode(TRUE);
+
 		LLMenuItemGL* itemp = mBranch->highlightNextItem(NULL);
 		if (itemp)
 		{
@@ -1427,6 +1467,54 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_par
 	return LLMenuItemGL::handleKeyHere(key, mask, called_from_parent);
 }
 
+void LLMenuItemBranchGL::openMenu()
+{
+	if (mBranch->getTornOff())
+	{
+		gFloaterView->bringToFront((LLFloater*)mBranch->getParent());
+		// this might not be necessary, as torn off branches don't get focus and hence no highligth
+		mBranch->highlightNextItem(NULL);
+	}
+	else if( !mBranch->getVisible() )
+	{
+		mBranch->arrange();
+
+		LLRect rect = mBranch->getRect();
+		// calculate root-view relative position for branch menu
+		S32 left = mRect.mRight;
+		S32 top = mRect.mTop - mRect.mBottom;
+
+		localPointToOtherView(left, top, &left, &top, mBranch->getParent());
+
+		rect.setLeftTopAndSize( left, top,
+								rect.getWidth(), rect.getHeight() );
+
+		if (mBranch->getCanTearOff())
+		{
+			rect.translate(0, TEAROFF_SEPARATOR_HEIGHT_PIXELS);
+		}
+		mBranch->setRect( rect );
+		S32 x = 0;
+		S32 y = 0;
+		mBranch->localPointToOtherView( 0, 0, &x, &y, mBranch->getParent() ); 
+		S32 delta_x = 0;
+		S32 delta_y = 0;
+		if( y < 0 )
+		{
+			delta_y = -y;
+		}
+
+		S32 window_width = mBranch->getParent()->getRect().getWidth();
+		if( x > window_width - rect.getWidth() )
+		{
+			// move sub-menu over to left side
+			delta_x = llmax(-x, (-1 * (rect.getWidth() + mRect.getWidth())));
+		}
+		mBranch->translate( delta_x, delta_y );
+		mBranch->setVisible( TRUE );
+	}
+}
+
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLMenuItemBranchDownGL
@@ -1456,14 +1544,13 @@ public:
 	// called to rebuild the draw label
 	virtual void buildDrawLabel( void );
 
-	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void );
+	// handles opening, positioning, and arranging the menu branch associated with this item
+	virtual void openMenu( void );
 
 	// set the hover status (called by it's menu) and if the object is
 	// active. This is used for behavior transfer.
 	virtual void setHighlight( BOOL highlight );
 
-	// determine if this object is active
 	virtual BOOL isActive( void ) const;
 
 	// LLView functionality
@@ -1502,8 +1589,7 @@ void LLMenuItemBranchDownGL::buildDrawLabel( void )
 	mDrawAccelLabel = st;
 }
 
-// doIt() - do the primary funcationality of the menu item.
-void LLMenuItemBranchDownGL::doIt( void )
+void LLMenuItemBranchDownGL::openMenu( void )
 {
 	if( mBranch->getVisible() && !mBranch->getTornOff() )
 	{
@@ -1544,21 +1630,23 @@ void LLMenuItemBranchDownGL::doIt( void )
 			}
 			mBranch->translate( delta_x, 0 );
 
-			// *TODO: get menuholder lookup working more generically
-			// hide existing menus
-			if (!mBranch->getTornOff())
-			{
-				((LLMenuHolderGL*)mBranch->getParent())->hideMenus();
-			}
-
+			setHighlight(TRUE);
 			mBranch->setVisible( TRUE );
 		}
+
+
 	}
 }
 
 // set the hover status (called by it's menu)
 void LLMenuItemBranchDownGL::setHighlight( BOOL highlight )
 {
+	if (highlight == getHighlight()) return;
+
+	if (highlight)
+	{
+		getMenu()->clearHoverItem();
+	}
 	mHighlight = highlight;
 	if( !highlight)
 	{
@@ -1574,22 +1662,18 @@ void LLMenuItemBranchDownGL::setHighlight( BOOL highlight )
 	}
 }
 
-// determine if this object is active
-// which, for branching menus, means the branch is open and has "focus"
-BOOL LLMenuItemBranchDownGL::isActive( void ) const
+BOOL LLMenuItemBranchDownGL::isActive() const
 {
-	if (mBranch->getTornOff())
-	{
-		return ((LLFloater*)mBranch->getParent())->hasFocus();
-	}
-	else
-	{
-		return mBranch->getVisible();
-	}
+	// for top level menus, being open is sufficient to be considered 
+	// active, because clicking on them with the mouse will open
+	// them, without moving keyboard focus to them
+	return isOpen();
 }
 
 BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask )
 {
+	// switch to mouse control mode
+	LLMenuGL::setKeyboardMode(FALSE);
 	doIt();
 	make_ui_sound("UISndClick");
 	return TRUE;
@@ -1611,12 +1695,17 @@ BOOL LLMenuItemBranchDownGL::handleAcceleratorKey(KEY key, MASK mask)
 
 BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
 {
-	if (mHighlight && getMenu()->getVisible() && mBranch->getVisible())
+	BOOL menu_open = mBranch->getVisible();
+	if (getHighlight() && getMenu()->getVisible())
 	{
 		if (key == KEY_LEFT)
 		{
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
 			LLMenuItemGL* itemp = getMenu()->highlightPrevItem(this);
-			if (itemp)
+			// open new menu only if previous menu was open
+			if (itemp && itemp->getEnabled() && menu_open)
 			{
 				itemp->doIt();
 			}
@@ -1625,8 +1714,12 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_
 		}
 		else if (key == KEY_RIGHT)
 		{
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
 			LLMenuItemGL* itemp = getMenu()->highlightNextItem(this);
-			if (itemp)
+			// open new menu only if previous menu was open
+			if (itemp && itemp->getEnabled() && menu_open)
 			{
 				itemp->doIt();
 			}
@@ -1635,18 +1728,24 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_
 		}
 		else if (key == KEY_DOWN)
 		{
-			if (!mBranch->getTornOff())
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
+			if (getEnabled() && !isActive())
 			{
-				mBranch->setVisible(TRUE);
+				doIt();
 			}
 			mBranch->highlightNextItem(NULL);
 			return TRUE;
 		}
 		else if (key == KEY_UP)
 		{
-			if (!mBranch->getTornOff())
+			// switch to keyboard navigation mode
+			LLMenuGL::setKeyboardMode(TRUE);
+
+			if (getEnabled() && !isActive())
 			{
-				mBranch->setVisible(TRUE);
+				doIt();
 			}
 			mBranch->highlightPrevItem(NULL);
 			return TRUE;
@@ -1658,7 +1757,13 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_
 
 void LLMenuItemBranchDownGL::draw( void )
 {
-	if( mHighlight )
+	//FIXME: try removing this
+	if (mBranch->getVisible() && !mBranch->getTornOff())
+	{
+		setHighlight(TRUE);
+	}
+
+	if( getHighlight() )
 	{
 		glColor4fv( sHighlightBackground.mV );
 		gl_rect_2d( 0, mRect.getHeight(), mRect.getWidth(), 0 );
@@ -1671,7 +1776,7 @@ void LLMenuItemBranchDownGL::draw( void )
 	}
 
 	LLColor4 color;
-	if (mHighlight)
+	if (getHighlight())
 	{
 		color = sHighlightForeground;
 	}
@@ -1685,18 +1790,10 @@ void LLMenuItemBranchDownGL::draw( void )
 	}
 	mFont->render( mLabel.getWString(), 0, (F32)mRect.getWidth() / 2.f, (F32)LABEL_BOTTOM_PAD_PIXELS, color,
 				   LLFontGL::HCENTER, LLFontGL::BOTTOM, font_style );
-	// if branching menu is closed clear out highlight
-	if (mHighlight && ((!mBranch->getVisible() /*|| mBranch->getTornOff()*/) && !mGotHover))
-	{
-		setHighlight(FALSE);
-	}
 
-	// underline navigation key
-	BOOL draw_jump_key = gKeyboard->currentMask(FALSE) == MASK_ALT && 
-								(!getMenu()->getHighlightedItem() || !getMenu()->getHighlightedItem()->isActive()) &&
-								(!getMenu()->getTornOff()); // torn off menus don't use jump keys, too complicated
 
-	if (draw_jump_key)
+	// underline navigation key
+	if (getMenu()->jumpKeysActive())
 	{
 		LLString upper_case_label = mLabel.getString();
 		LLString::toUpper(upper_case_label);
@@ -2078,7 +2175,8 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory
 				}
 				item = new_item;
 				item->setLabel(item_label);
-				item->setJumpKey(jump_key);
+				if (jump_key != KEY_NONE)
+					item->setJumpKey(jump_key);
 			}
 
 			if (item != NULL)
@@ -2089,6 +2187,50 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory
 	}
 }
 
+// are we the childmost active menu and hence our jump keys should be enabled?
+// or are we a free-standing torn-off menu (which uses jump keys too)
+BOOL LLMenuGL::jumpKeysActive()
+{
+	LLMenuItemGL* highlighted_item = getHighlightedItem();
+	BOOL active = getVisible() && getEnabled();
+	if (getTornOff())
+	{
+		// activation of jump keys on torn off menus controlled by keyboard focus
+		active = active && ((LLFloater*)getParent())->hasFocus();
+
+	}
+	else
+	{
+		// Are we the terminal active menu?
+		// Yes, if parent menu item deems us to be active (just being visible is sufficient for top-level menus)
+		// and we don't have a highlighted menu item pointing to an active sub-menu
+		active = active && (!getParentMenuItem() || getParentMenuItem()->isActive()) // I have a parent that is active...
+		                && (!highlighted_item || !highlighted_item->isActive()); //... but no child that is active
+	}
+	return active;
+}
+
+BOOL LLMenuGL::isOpen()
+{
+	if (getTornOff())
+	{
+		LLMenuItemGL* itemp = getHighlightedItem();
+		// if we have an open sub-menu, then we are considered part of 
+		// the open menu chain even if we don't have focus
+		if (itemp && itemp->isOpen())
+		{
+			return TRUE;
+		}
+		// otherwise we are only active if we have keyboard focus
+		return ((LLFloater*)getParent())->hasFocus();
+	}
+	else
+	{
+		// normally, menus are hidden as soon as the user focuses
+		// on another menu, so just use the visibility criterion
+		return getVisible();
+	}
+}
 // static
 LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
 {
@@ -2456,21 +2598,27 @@ void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom)
 	arrange();
 }
 
-void LLMenuGL::handleJumpKey(KEY key)
+BOOL LLMenuGL::handleJumpKey(KEY key)
 {
+	// must perform case-insensitive comparison, so just switch to uppercase input key
+	key = toupper(key);
 	navigation_key_map_t::iterator found_it = mJumpKeys.find(key);
 	if(found_it != mJumpKeys.end() && found_it->second->getEnabled())
 	{
-		clearHoverItem();
+		// 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();
-		if (!found_it->second->isActive() && !getTornOff())
-		{
-			// parent is a menu holder, because this is not a menu bar
-			((LLMenuHolderGL*)getParent())->hideMenus();
-		}
+
 	}
+	// if we are navigating the menus, we need to eat the keystroke
+	// so rest of UI doesn't handle it
+	return TRUE;
 }
 
 
@@ -2723,10 +2871,6 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa
 		// skip separators and disabled items
 		if ((*prev_item_iter)->getEnabled() && (*prev_item_iter)->getName() != SEPARATOR_NAME)
 		{
-			if (cur_item)
-			{
-				cur_item->setHighlight(FALSE);
-			}
 			(*prev_item_iter)->setHighlight(TRUE);
 			return (*prev_item_iter);
 		}
@@ -2821,17 +2965,11 @@ BOOL LLMenuGL::handleAcceleratorKey(KEY key, MASK mask)
 	return FALSE;
 }
 
-BOOL LLMenuGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
+BOOL LLMenuGL::handleUnicodeCharHere( llwchar uni_char, BOOL called_from_parent )
 {
-	if (key < KEY_SPECIAL && getVisible() && getEnabled() && mask == MASK_ALT)
+	if (jumpKeysActive())
 	{
-		if (getTornOff())
-		{
-			// torn off menus do not handle jump keys (for now, the interaction is complex)
-			return FALSE;
-		}
-		handleJumpKey(key);
-		return TRUE;
+		return handleJumpKey((KEY)uni_char);
 	}
 	return FALSE;
 }
@@ -2839,8 +2977,9 @@ BOOL LLMenuGL::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
 {
 	// leave submenu in place if slope of mouse < MAX_MOUSE_SLOPE_SUB_MENU
-	S32 mouse_delta_x = x - mLastMouseX;
-	S32 mouse_delta_y = y - mLastMouseY;
+	BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0;
+	S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX;
+	S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY;
 	LLVector2 mouse_dir((F32)mouse_delta_x, (F32)mouse_delta_y);
 	mouse_dir.normVec();
 	LLVector2 mouse_avg_dir((F32)mMouseVelX, (F32)mMouseVelY);
@@ -2852,8 +2991,7 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
 	mLastMouseY = y;
 
 	// don't change menu focus unless mouse is moving or alt key is not held down
-	if ((gKeyboard->currentMask(FALSE) != MASK_ALT || 
-			llabs(mMouseVelX) > 0 || 
+	if ((llabs(mMouseVelX) > 0 || 
 			llabs(mMouseVelY) > 0) &&
 		(!mHasSelection ||
 		//(mouse_delta_x == 0 && mouse_delta_y == 0) ||
@@ -2883,7 +3021,9 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
 			//RN: always call handleHover to track mGotHover status
 			// but only set highlight when mouse is moving
 			if( viewp->getVisible() && 
-				viewp->getEnabled() &&
+				//RN: allow disabled items to be highlighted to preserve "active" menus when
+				// moving mouse through them
+				//viewp->getEnabled() && 
 				viewp->pointInView(local_x, local_y) && 
 				viewp->handleHover(local_x, local_y, mask))
 			{
@@ -2891,6 +3031,7 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
 				if (mouse_delta_x != 0 || mouse_delta_y != 0)
 				{
 					((LLMenuItemGL*)viewp)->setHighlight(TRUE);
+					LLMenuGL::setKeyboardMode(FALSE);
 				}
 				mHasSelection = TRUE;
 			}
@@ -2900,19 +3041,6 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask )
 	return TRUE;
 }
 
-BOOL LLMenuGL::handleMouseUp( S32 x, S32 y, MASK mask )
-{
-	if( LLView::childrenHandleMouseUp( x, y, mask ) )
-	{
-		if (!getTornOff())
-		{
-			((LLMenuHolderGL*)getParent())->hideMenus();
-		}
-	}
-
-	return TRUE;
-}
-
 void LLMenuGL::draw( void )
 {
 	if (mDropShadowed && !mTornOff)
@@ -2946,6 +3074,10 @@ void LLMenuGL::setVisible(BOOL visible)
 		{
 			mFadeTimer.start();
 			clearHoverItem();
+			// reset last known mouse coordinates so
+			// we don't spoof a mouse move next time we're opened
+			mLastMouseX = 0;
+			mLastMouseY = 0;
 		}
 		else
 		{
@@ -2977,12 +3109,12 @@ LLMenuGL* LLMenuGL::getChildMenuByName(const LLString& name, BOOL recurse) const
 	return NULL;
 }
 
-BOOL LLMenuGL::clearHoverItem(BOOL include_active)
+BOOL LLMenuGL::clearHoverItem()
 {
 	for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 	{
 		LLMenuItemGL* itemp = (LLMenuItemGL*)*child_it;
-		if (itemp->getHighlight() && (include_active || !itemp->isActive()))
+		if (itemp->getHighlight())
 		{
 			itemp->setHighlight(FALSE);
 			return TRUE;
@@ -3243,10 +3375,8 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
 
 		if (item != mHoverItem)
 		{
-			BOOL active = FALSE;
 			if (mHoverItem)
 			{
-				active = mHoverItem->isActive();
 				mHoverItem->setHighlight( FALSE );
 			}
 			mHoverItem = item;
@@ -3824,6 +3954,7 @@ LLMenuBarGL::LLMenuBarGL( const LLString& name ) : LLMenuGL ( name, name )
 	mHorizontalLayout = TRUE;
 	setCanTearOff(FALSE);
 	mKeepFixedSize = TRUE;
+	mAltKeyTrigger = FALSE;
 }
 
 // Default destructor
@@ -3934,15 +4065,112 @@ LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
 	return menubar;
 }
 
-void LLMenuBarGL::handleJumpKey(KEY key)
+BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
 {
+	if (getHighlightedItem() && mask == MASK_NONE)
+	{
+		// unmodified key accelerators are ignored when navigating menu
+		// (but are used as jump keys so will still work when appropriate menu is up)
+		return FALSE;
+	}
+	BOOL result = LLMenuGL::handleAcceleratorKey(key, mask);
+	if (result && mask & MASK_ALT)
+	{
+		// ALT key used to trigger hotkey, don't use as shortcut to open menu
+		mAltKeyTrigger = FALSE;
+	}
+
+	if(!result && (key == KEY_F10 && mask == MASK_CONTROL) && !gKeyboard->getKeyRepeated(key))
+	{
+		if (getHighlightedItem())
+		{
+			clearHoverItem();
+		}
+		else
+		{
+			highlightNextItem(NULL);
+			LLMenuGL::setKeyboardMode(TRUE);
+		}
+		return TRUE;
+	}
+
+	return result;
+}
+
+BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
+{
+	if(key == KEY_ALT)
+	{
+		mAltKeyTrigger = TRUE;
+	}
+	// before processing any other key, check to see if ALT key has triggered menu access
+	checkMenuTrigger();
+
+	return LLMenuGL::handleKeyHere(key, mask, called_from_parent);
+}
+
+BOOL LLMenuBarGL::handleJumpKey(KEY key)
+{
+	// perform case-insensitive comparison
+	key = toupper(key);
 	navigation_key_map_t::iterator found_it = mJumpKeys.find(key);
 	if(found_it != mJumpKeys.end() && found_it->second->getEnabled())
 	{
-		clearHoverItem();
+		// switch to keyboard navigation mode
+		LLMenuGL::setKeyboardMode(TRUE);
+
 		found_it->second->setHighlight(TRUE);
 		found_it->second->doIt();
 	}
+	return TRUE;
+}
+
+void LLMenuBarGL::draw()
+{
+	LLMenuItemGL* itemp = getHighlightedItem();
+	// If we are in mouse-control mode and the mouse cursor is not hovering over
+	// the current highlighted menu item and it isn't open, then remove the highlight.
+	// This is done via a polling mechanism here, as we don't receive notifications when
+	// the mouse cursor moves off of us
+	if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode())
+	{
+		clearHoverItem();
+	}
+
+	checkMenuTrigger();
+
+	LLMenuGL::draw();
+}
+
+void LLMenuBarGL::checkMenuTrigger()
+{
+	// has the ALT key been pressed and subsequently released?
+	if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT))
+	{
+		// 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") ||
+			gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2)
+		{
+			if (getHighlightedItem())
+			{
+				clearHoverItem();
+			}
+			else
+			{
+				highlightNextItem(NULL);
+				LLMenuGL::setKeyboardMode(TRUE);
+			}
+		}
+		mAltKeyTrigger = FALSE;
+	}
+}
+
+BOOL LLMenuBarGL::jumpKeysActive()
+{
+	// require item to be highlighted to activate key triggers
+	// as menu bars are always visible
+	return getHighlightedItem() && LLMenuGL::jumpKeysActive();
 }
 
 // rearrange the child rects so they fit the shape of the menu bar.
@@ -4013,8 +4241,9 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
 	BOOL handled = FALSE;
 	LLView* active_menu = NULL;
 
-	S32 mouse_delta_x = x - mLastMouseX;
-	S32 mouse_delta_y = y - mLastMouseY;
+	BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0;
+	S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX;
+	S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY;
 	mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2);
 	mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2);
 	mLastMouseX = x;
@@ -4022,13 +4251,13 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
 
 	// if nothing currently selected or mouse has moved since last call, pick menu item via mouse
 	// otherwise let keyboard control it
-	if (!getHighlightedItem() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0)
+	if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0)
 	{
 		// find current active menu
 		for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
 		{
 			LLView* viewp = *child_it;
-			if (((LLMenuItemGL*)viewp)->isActive())
+			if (((LLMenuItemGL*)viewp)->isOpen())
 			{
 				active_menu = viewp;
 			}
@@ -4050,6 +4279,7 @@ BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask )
 				if (active_menu && active_menu != viewp)
 				{
 					((LLMenuItemGL*)viewp)->doIt();
+					LLMenuGL::setKeyboardMode(FALSE);
 				}
 			}
 		}
@@ -4249,23 +4479,6 @@ LLTearOffMenu::~LLTearOffMenu()
 
 void LLTearOffMenu::draw()
 {
-	if (hasFocus())
-	{
-		LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem();
-		while(parent_menu_item)
-		{
-			if (parent_menu_item->getMenu()->getVisible())
-			{
-				parent_menu_item->setHighlight(TRUE);
-				parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem();
-			}
-			else
-			{
-				break;
-			}
-		}
-	}
-
 	mMenu->setBackgroundVisible(mBgOpaque);
 	mMenu->arrange();
 
@@ -4290,6 +4503,21 @@ void LLTearOffMenu::onFocusReceived()
 	{
 		mMenu->highlightNextItem(NULL);
 	}
+
+	// parent menu items get highlights so navigation logic keeps working
+	LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem();
+	while(parent_menu_item)
+	{
+		if (parent_menu_item->getMenu()->getVisible())
+		{
+			parent_menu_item->setHighlight(TRUE);
+			parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem();
+		}
+		else
+		{
+			break;
+		}
+	}
 }
 
 void LLTearOffMenu::onFocusLost()
@@ -4298,6 +4526,41 @@ void LLTearOffMenu::onFocusLost()
 	mMenu->clearHoverItem();
 }
 
+BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
+{
+	// pass keystrokes down to menu
+	return mMenu->handleUnicodeChar(uni_char, TRUE);
+}
+
+BOOL LLTearOffMenu::handleKey(KEY key, MASK mask, BOOL called_from_parent)
+{
+	if (!mMenu->getHighlightedItem())
+	{
+		if (key == KEY_UP)
+		{
+			mMenu->highlightPrevItem(NULL);		
+			return TRUE;
+		}
+		else if (key == KEY_DOWN)
+		{
+			mMenu->highlightNextItem(NULL);
+			return TRUE;
+		}
+	}
+	// pass keystrokes down to menu
+	return mMenu->handleKey(key, mask, TRUE);
+}
+
+void LLTearOffMenu::translate(S32 x, S32 y)
+{
+	if (x != 0 && y != 0)
+	{
+		// hide open sub-menus by clearing current hover item
+		mMenu->clearHoverItem();
+	}
+	LLFloater::translate(x, y);
+}
+
 //static
 LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup)
 {
diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h
index 7dcd950996d00e0a72792ed7d17f1488fabdf3ec..0dca8f2550f65ad966877d4bef2f4f87b7b9dd6e 100644
--- a/indra/llui/llmenugl.h
+++ b/indra/llui/llmenugl.h
@@ -129,14 +129,17 @@ public:
 	virtual void updateBranchParent( LLView* parentp ){};
 	
 	// doIt() - do the primary funcationality of the menu item.
-	virtual void doIt( void ) = 0;
+	virtual void doIt( void );
 
 	// set the hover status (called by it's menu)
 	virtual void setHighlight( BOOL highlight );
 
-	// determine if this object is active
+	// determine if this represents an active sub-menu
 	virtual BOOL isActive( void ) const;
 
+	// determine if this represents an open sub-menu
+	virtual BOOL isOpen( void ) const;
+
 	virtual void setEnabledSubMenus(BOOL enable){};
 
 	// LLView Functionality
@@ -144,6 +147,8 @@ public:
 	virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
 	virtual void draw( void );
 
+	BOOL getHover() { return mGotHover; }
+
 	BOOL getDrawTextDisabled() const { return mDrawTextDisabled; }
 
 protected:
@@ -398,9 +403,9 @@ public:
 
 	// LLView Functionality
 	virtual BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent );
-	virtual BOOL handleKeyHere( KEY key, MASK mask, BOOL called_from_parent );
+	//virtual BOOL handleKeyHere( KEY key, MASK mask, BOOL called_from_parent );
+	virtual BOOL handleUnicodeCharHere( llwchar uni_char, BOOL called_from_parent );
 	virtual BOOL handleHover( S32 x, S32 y, MASK mask );
-	virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );
 	virtual void draw( void );
 	virtual void drawBackground(LLMenuItemGL* itemp, LLColor4& color);
 	virtual void setVisible(BOOL visible);
@@ -409,7 +414,7 @@ public:
 
 	LLMenuGL* getChildMenuByName(const LLString& name, BOOL recurse) const;
 	
-	BOOL clearHoverItem(BOOL include_active = TRUE);
+	BOOL clearHoverItem();
 
 	// return the name label
 	const LLString& getLabel( void ) const { return mLabel.getString(); }
@@ -445,7 +450,11 @@ public:
 	// sets the left,bottom corner of menu, useful for popups
 	void setLeftAndBottom(S32 left, S32 bottom);
 
-	virtual void handleJumpKey(KEY key);
+	virtual BOOL handleJumpKey(KEY key);
+
+	virtual BOOL jumpKeysActive();
+
+	virtual BOOL isOpen();
 
 	// Shape this menu to fit the current state of the children, and
 	// adjust the child rects to fit. This is called automatically
@@ -491,8 +500,10 @@ public:
 	KEY getJumpKey() { return mJumpKey; }
 	void setJumpKey(KEY key) { mJumpKey = key; }
 
-	static void onFocusLost(LLView* old_focus);
+	static void setKeyboardMode(BOOL mode) { sKeyboardMode = mode; }
+	static BOOL getKeyboardMode() { return sKeyboardMode; }
 
+	static void onFocusLost(LLView* old_focus);
 	static LLView *sDefaultMenuContainer;
 	
 protected:
@@ -501,6 +512,7 @@ protected:
 
 protected:
 	static LLColor4 sDefaultBackgroundColor;
+	static BOOL		sKeyboardMode;
 
 	LLColor4		mBackgroundColor;
 	BOOL			mBgVisible;
@@ -602,7 +614,8 @@ private:
 class LLMenuBarGL : public LLMenuGL
 {
 protected:
-	std::list <LLKeyBinding*> mAccelerators;
+	std::list <LLKeyBinding*>	mAccelerators;
+	BOOL						mAltKeyTrigger;
 
 public:
 	LLMenuBarGL( const LLString& name );
@@ -613,10 +626,15 @@ public:
 	virtual EWidgetType getWidgetType() const { return WIDGET_TYPE_MENU_BAR; }
 	virtual LLString getWidgetTag() const { return LL_MENU_BAR_GL_TAG; }
 
+	virtual BOOL handleAcceleratorKey(KEY key, MASK mask);
+	virtual BOOL handleKeyHere(KEY key, MASK mask, BOOL called_from_parent);
+	virtual BOOL handleJumpKey(KEY key);
+
 	// rearrange the child rects so they fit the shape of the menu
 	// bar.
-	virtual void handleJumpKey(KEY key);
 	virtual void arrange( void );
+	virtual void draw();
+	virtual BOOL jumpKeysActive();
 
 	// add a vertical separator to this menu
 	virtual BOOL appendSeparator( const LLString &separator_name = "separator" );
@@ -629,6 +647,12 @@ public:
 
 	// Returns x position of rightmost child, usually Help menu
 	S32 getRightmostMenuEdge();
+
+	void resetMenuTrigger() { mAltKeyTrigger = FALSE; }
+
+protected:
+	void checkMenuTrigger();
+
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -679,6 +703,9 @@ public:
 	virtual void draw(void);
 	virtual void onFocusReceived();
 	virtual void onFocusLost();
+	virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent);
+	virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
+	virtual void translate(S32 x, S32 y);
 
 protected:
 	LLTearOffMenu(LLMenuGL* menup);
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 64ba319151cd84ac129820fb27bbd94797d358c2..8c3d2362c5d8c73aa0ebb9b8776db7995ff4dc55 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -894,7 +894,6 @@ BOOL LLView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_scre
 	return handled;
 }
 
-
 BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
@@ -908,17 +907,14 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 		}
 	}
 
-	if( !handled )
+	// JC: Must pass to disabled views, since they could have
+	// keyboard focus, which requires the escape key to exit.
+	if (!handled && getVisible())
 	{
-		// JC: Must pass to disabled views, since they could have
-		// keyboard focus, which requires the escape key to exit.
-		if (getVisible())
+		handled = handleKeyHere( key, mask, called_from_parent );
+		if (handled && LLView::sDebugKeys)
 		{
-			handled = handleKeyHere( key, mask, called_from_parent );
-			if (handled && LLView::sDebugKeys)
-			{
-				llinfos << "Key handled by " << getName() << llendl;
-			}
+			llinfos << "Key handled by " << getName() << llendl;
 		}
 	}
 
@@ -945,25 +941,20 @@ BOOL LLView::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
 	return FALSE;
 }
 
-
 BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
 {
 	BOOL handled = FALSE;
 
-	/*
 	if( called_from_parent )
 	{
 		// Downward traversal
 		if (getVisible() && mEnabled)
 		{
-			handled = childrenHandleKey( key, mask ) != NULL;
+			handled = childrenHandleUnicodeChar( uni_char ) != NULL;
 		}
 	}
-	*/
 
-	// JC: Must pass to disabled views, since they could have
-	// keyboard focus, which requires the escape key to exit.
-	if (getVisible())
+	if (!handled && getVisible())
 	{
 		handled = handleUnicodeCharHere(uni_char, called_from_parent);
 		if (handled && LLView::sDebugKeys)
@@ -1215,6 +1206,30 @@ LLView* LLView::childrenHandleKey(KEY key, MASK mask)
 	return handled_view;
 }
 
+// Called during downward traversal
+LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
+{
+	LLView* handled_view = NULL;
+
+	if ( getVisible() && mEnabled )
+	{
+		for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
+		{
+			LLView* viewp = *child_it;
+			if (viewp->handleUnicodeChar(uni_char, TRUE))
+			{
+				if (LLView::sDebugKeys)
+				{
+					llinfos << "Unicode character handled by " << viewp->getName() << llendl;
+				}
+				handled_view = viewp;
+				break;
+			}
+		}
+	}
+
+	return handled_view;
+}
 
 LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
 {
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 9a36c56e3ec160a739b0a530117abb673d64c41e..839c300476917f16aaa0da9e7f26e8393001944b 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -448,6 +448,7 @@ protected:
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent);
 
 	LLView*	childrenHandleKey(KEY key, MASK mask);
+	LLView* childrenHandleUnicodeChar(llwchar uni_char);
 	LLView*	childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
 											  BOOL drop,
 											  EDragAndDropType type,
diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp
index ee42f53571d27cd8bf32e5f56f134f5117850d67..a0970f01402930be5b862b643554d029d111c9b6 100644
--- a/indra/llwindow/llkeyboard.cpp
+++ b/indra/llwindow/llkeyboard.cpp
@@ -205,6 +205,8 @@ BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask
 	{
 		mKeyLevel[translated_key] = TRUE;
 		mKeyLevelTimer[translated_key].reset();
+		mKeyLevelFrameCount[translated_key] = 0;
+		mKeyRepeated[translated_key] = FALSE;
 	}
 	else
 	{
@@ -226,7 +228,6 @@ BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask)
 	if( mKeyLevel[translated_key] )
 	{
 		mKeyLevel[translated_key] = FALSE;
-		mKeyLevelFrameCount[translated_key] = 0;
 		
 		// Only generate key up events if the key is thought to
 		// be down.  This allows you to call resetKeys() in the
@@ -234,7 +235,6 @@ BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask)
 		// messages in the same frame.  This was causing the
 		// sequence W<return> in chat to move agents forward. JC
 		mKeyUp[translated_key] = TRUE;
-		mKeyRepeated[translated_key] = FALSE;
 		handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask);
 	}
 	
@@ -260,27 +260,13 @@ void LLKeyboard::toggleInsertMode()
 // Returns time in seconds since key was pressed.
 F32 LLKeyboard::getKeyElapsedTime(KEY key)
 {
-	if( mKeyLevel[key] )
-	{
-		return mKeyLevelTimer[key].getElapsedTimeF32();
-	}
-	else
-	{
-		return 0.f;
-	}
+	return mKeyLevelTimer[key].getElapsedTimeF32();
 }
 
 // Returns time in frames since key was pressed.
 S32 LLKeyboard::getKeyElapsedFrameCount(KEY key)
 {
-	if( mKeyLevel[key] )
-	{
-		return mKeyLevelFrameCount[key];
-	}
-	else
-	{
-		return 0;
-	}
+	return mKeyLevelFrameCount[key];
 }
 
 // static
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index 0c47d117d096f8a509839e652c44c02ce62da216..1d7919f06b99076dc3922b9d9249736e05bb7c29 100644
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -58,8 +58,8 @@ public:
 	void			resetKeys();
 
 
-	F32				getCurKeyElapsedTime()	{ return getKeyElapsedTime( mCurScanKey ); }
-	F32				getCurKeyElapsedFrameCount()	{ return (F32)getKeyElapsedFrameCount( mCurScanKey ); }
+	F32				getCurKeyElapsedTime()	{ return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; }
+	F32				getCurKeyElapsedFrameCount()	{ return getKeyDown(mCurScanKey) ? (F32)getKeyElapsedFrameCount( mCurScanKey ) : 0.f; }
 	BOOL			getKeyDown(const KEY key) { return mKeyLevel[key]; }
 	BOOL			getKeyRepeated(const KEY key) { return mKeyRepeated[key]; }
 
@@ -92,9 +92,10 @@ public:
 	void setNumpadDistinct(e_numpad_distinct val) { mNumpadDistinct = val; }
 
 	void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; }
-protected:
 	F32				getKeyElapsedTime( KEY key );  // Returns time in seconds since key was pressed.
 	S32				getKeyElapsedFrameCount( KEY key );  // Returns time in frames since key was pressed.
+
+protected:
 	void 			addKeyName(KEY key, const LLString& name);
 
 protected:
diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp
index ddc099418c2e4c53712023b6e92887ef22c7bd46..fe553a8230e867d8c39d759ef0c4ca9b1ef1750b 100644
--- a/indra/llwindow/llkeyboardwin32.cpp
+++ b/indra/llwindow/llkeyboardwin32.cpp
@@ -146,29 +146,32 @@ void LLKeyboardWin32::resetMaskKeys()
 }
 
 
-void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state )
-{
-	if( mKeyLevel[key] != new_state )
-	{
-		mKeyLevelFrameCount[key] = 0;
-
-		if( new_state )
-		{
-			mKeyLevelTimer[key].reset();
-		}
-		mKeyLevel[key] = new_state;
-	}
-}
+//void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state )
+//{
+//	if( mKeyLevel[key] != new_state )
+//	{
+//		mKeyLevelFrameCount[key] = 0;
+//
+//		if( new_state )
+//		{
+//			mKeyLevelTimer[key].reset();
+//		}
+//		mKeyLevel[key] = new_state;
+//	}
+//}
 
 
 MASK LLKeyboardWin32::updateModifiers()
 {
+	//RN: this seems redundant, as we should have already received the appropriate
+	// messages for the modifier keys
+
 	// Scan the modifier keys as of the last Windows key message
 	// (keydown encoded in high order bit of short)
-	setModifierKeyLevel( KEY_SHIFT, GetKeyState(VK_SHIFT) & 0x8000 );
-	setModifierKeyLevel( KEY_CONTROL, GetKeyState(VK_CONTROL) & 0x8000 );
-	setModifierKeyLevel( KEY_ALT, GetKeyState(VK_MENU) & 0x8000 );
-	setModifierKeyLevel( KEY_CAPSLOCK, GetKeyState(VK_CAPITAL) & 0x0001); // Low order bit carries the toggle state.
+	//setModifierKeyLevel( KEY_SHIFT, GetKeyState(VK_SHIFT) & 0x8000 );
+	//setModifierKeyLevel( KEY_CONTROL, GetKeyState(VK_CONTROL) & 0x8000 );
+	//setModifierKeyLevel( KEY_ALT, GetKeyState(VK_MENU) & 0x8000 );
+	//setModifierKeyLevel( KEY_CAPSLOCK, GetKeyState(VK_CAPITAL) & 0x0001); // Low order bit carries the toggle state.
 	// Get mask for keyboard events
 	MASK mask = currentMask(FALSE);
 	return mask;
diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h
index e7eb4b9c1e066be98335a887f8666151a85549fb..c8355bb7a1072fdeb925603f1d01a8e39a77e91e 100644
--- a/indra/llwindow/llkeyboardwin32.h
+++ b/indra/llwindow/llkeyboardwin32.h
@@ -31,7 +31,7 @@ public:
 
 protected:
 	MASK	updateModifiers();
-	void	setModifierKeyLevel( KEY key, BOOL new_state );
+	//void	setModifierKeyLevel( KEY key, BOOL new_state );
 private:
 	std::map<U16, KEY> mTranslateNumpadMap;
 	std::map<KEY, U16> mInvTranslateNumpadMap;
diff --git a/indra/newview/app_settings/keys.ini b/indra/newview/app_settings/keys.ini
index f6232abb4709488f6d2caa965103c79532492bc0..b7fc6f9286a715efca6be3d06e1eb4cf99d56a67 100644
--- a/indra/newview/app_settings/keys.ini
+++ b/indra/newview/app_settings/keys.ini
@@ -129,6 +129,13 @@ THIRD_PERSON	DOWN	ALT			move_backward
 THIRD_PERSON	PGUP	ALT			spin_over
 THIRD_PERSON	PGDN	ALT			spin_under
 
+THIRD_PERSON	A		ALT			spin_around_cw
+THIRD_PERSON	D		ALT			spin_around_ccw
+THIRD_PERSON	W		ALT			move_forward
+THIRD_PERSON	S		ALT			move_backward
+THIRD_PERSON	E		ALT			spin_over
+THIRD_PERSON	C		ALT			spin_under
+
 THIRD_PERSON	PAD_LEFT	ALT			spin_around_cw
 THIRD_PERSON	PAD_RIGHT	ALT			spin_around_ccw
 THIRD_PERSON	PAD_UP		ALT			move_forward
diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp
index 208a14a6c66da81a38ea05dac42082b05c0f0725..e958bd215201abcca1dbd5f36655ada80f1a8feb 100644
--- a/indra/newview/llchatbar.cpp
+++ b/indra/newview/llchatbar.cpp
@@ -95,6 +95,7 @@ LLChatBar::LLChatBar(const std::string& name, const LLRect& rect)
 		mInputEditor->setFocusLostCallback(&onInputEditorFocusLost);
 		mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus );
 		mInputEditor->setCommitOnFocusLost( FALSE );
+		mInputEditor->setRevertOnEsc( FALSE );
 		mInputEditor->setIgnoreTab(TRUE);
 		mInputEditor->setPassDelete(TRUE);
 	}
diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp
index 181a66c2efd8d7d959b02b9a8e335f180dbaaeef..59147c54f8e83bd7be9e60c63f2c701212c020b5 100644
--- a/indra/newview/llfloatercolorpicker.cpp
+++ b/indra/newview/llfloatercolorpicker.cpp
@@ -42,7 +42,8 @@
 #include "lldraghandle.h"
 
 const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
-const F32 CONTEXT_CONE_OUT_ALPHA = 0.35f;
+const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
+const F32 CONTEXT_FADE_TIME = 0.08f;
 
 //////////////////////////////////////////////////////////////////////////////
 //
@@ -607,11 +608,11 @@ void LLFloaterColorPicker::draw()
 
 	if (gFocusMgr.childHasMouseCapture(mDragHandle))
 	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 1.f, LLCriticalDamp::getInterpolant(0.1f));
+		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 	}
 	else
 	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(0.2f));
+		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 	}
 
 	mPipetteBtn->setEnabled(gToolMgr != NULL);
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 718ea894aa4bc61df8690ee2beeeb35ddefd911d..865de53512e4fa3b8d63cf21feded2db58240c31 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -110,6 +110,7 @@ BOOL LLFloaterIMPanel::postBuild()
 		mInputEditor->setKeystrokeCallback( onInputEditorKeystroke );
 		mInputEditor->setCallbackUserData(this);
 		mInputEditor->setCommitOnFocusLost( FALSE );
+		mInputEditor->setRevertOnEsc( FALSE );
 
 		LLButton* profile_btn = LLUICtrlFactory::getButtonByName(this, "profile_btn");
 		profile_btn->setClickedCallback(&LLFloaterIMPanel::onClickProfile, this);
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 509f040c34ff6c3bcce27347fcbabda628799ac2..f1c4f0d918e7285bea35d0d93f54f07fb3df1c53 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -2340,19 +2340,25 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, boo
 				open_notecard(
 					lastitem->getUUID(),
 					LLString("Note: ") + lastitem->getName(),
-					show_keep_discard);
+					show_keep_discard,
+					LLUUID::null, 
+					FALSE);
 				break;
 			case LLAssetType::AT_LANDMARK:
 				open_landmark(
 					lastitem->getUUID(),
 					LLString("  ") + lastitem->getName(),
-					show_keep_discard);
+					show_keep_discard,
+					LLUUID::null,
+					FALSE);
 				break;
 			case LLAssetType::AT_TEXTURE:
 				open_texture(
 					lastitem->getUUID(),
 					LLString("Texture: ") + lastitem->getName(),
-					show_keep_discard);
+					show_keep_discard,
+					LLUUID::null, 
+					FALSE);
 				break;
 			default:
 				break;
diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp
index 74c7ae6c18beb24b2256f394feac0e1e3ddfc74b..57d34f672bf9cbe7b4250acc6a70c411430a720a 100644
--- a/indra/newview/llmanip.cpp
+++ b/indra/newview/llmanip.cpp
@@ -88,7 +88,9 @@ void LLManip::getManipNormal(LLViewerObject* object, EManipPart manip, LLVector3
 		LLVector3 arrow_axis;
 		getManipAxis(object, manip, arrow_axis);
 
-		LLVector3 cross = arrow_axis % gCamera->getAtAxis();
+		LLVector3 origin_dir = grid_origin - gCamera->getOrigin();
+		origin_dir.normVec();
+		LLVector3 cross = arrow_axis % origin_dir;
 		normal = cross % arrow_axis;
 		normal.normVec();
 	}
diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp
index 5cc2d2e39fc93d38a28274aec5ef9fa1fbfb9d1d..82974da634fadbcf8bbf5e59109ba1cb2101b96a 100644
--- a/indra/newview/llpreview.cpp
+++ b/indra/newview/llpreview.cpp
@@ -157,6 +157,16 @@ void LLPreview::onCommit()
 	LLViewerInventoryItem* item = getItem();
 	if(item)
 	{
+		if (!item->isComplete())
+		{
+			// We are attempting to save an item that was never loaded
+			llwarns << "LLPreview::onCommit() called with mIsComplete == FALSE"
+					<< " Type: " << item->getType()
+					<< " ID: " << item->getUUID()
+					<< llendl;
+			return;
+		}
+		
 		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
 		BOOL has_sale_info = FALSE;
 		LLSaleInfo sale_info;
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 106bfd00955a3717df12cc564820a77f00e1f049..cb7679557e4a360288b389bc0c7e27a2dca1d44a 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -67,8 +67,8 @@ static const S32 FOOTER_HEIGHT = 100;
 static const S32 BORDER_PAD = HPAD;
 static const S32 TEXTURE_INVENTORY_PADDING = 30;
 static const F32 CONTEXT_CONE_IN_ALPHA = 0.0f;
-static const F32 CONTEXT_CONE_OUT_ALPHA = 0.35f;
-
+static const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
+static const F32 CONTEXT_FADE_TIME = 0.08f;
 
 //static const char CURRENT_IMAGE_NAME[] = "Current Texture";
 //static const char WHITE_IMAGE_NAME[] = "Blank Texture";
@@ -437,11 +437,11 @@ void LLFloaterTexturePicker::draw()
 
 	if (gFocusMgr.childHasMouseCapture(mDragHandle))
 	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 1.f, LLCriticalDamp::getInterpolant(0.1f));
+		mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 	}
 	else
 	{
-		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(0.2f));
+		mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME));
 	}
 
 	updateImageStats();
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 689dcee663b4d903b22940a28aa1ae6a440af969..8ab2b52a50d2190cbfd51dcb98e976cc656caf53 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -8263,6 +8263,8 @@ BOOL LLViewerMenuHolderGL::hideMenus()
 			gParcelMgr->deselectLand();	
 		}
 	}
+	gMenuBarView->clearHoverItem();
+	gMenuBarView->resetMenuTrigger();
 	return handled;
 }
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 8920d09fa6af816881e03f004e245f5f21102a83..df396c93be3ed3fb99e686a76e4590bd97a1c518 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2137,7 +2137,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 	}
 
 	// don't pass keys on to world when something in ui has focus
-	return gFocusMgr.childHasKeyboardFocus(mRootView);
+	return gFocusMgr.childHasKeyboardFocus(mRootView) || (gMenuBarView && gMenuBarView->getHighlightedItem());
 }
 
 
@@ -2154,6 +2154,12 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
 		return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
 	}
 
+	// let menus handle navigation (jump) keys
+	if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
+	{
+		return TRUE;
+	}
+
 	// Traverses up the hierarchy
 	LLView* keyboard_focus = gFocusMgr.getKeyboardFocus();
 	if( keyboard_focus )
@@ -2665,7 +2671,8 @@ BOOL LLViewerWindow::handlePerFrameHover()
 	if (gParcelMgr
 		&& !LLFloaterLand::floaterVisible()
 		&& !LLFloaterBuyLand::isOpen()
-		&& (!gFloaterTools || !gFloaterTools->getVisible()))
+		&& (!gFloaterTools || !gFloaterTools->getVisible())
+		&& !gToolMgr)
 	{
 		gParcelMgr->deselectLand();
 	}
@@ -3499,8 +3506,21 @@ BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, con
 	mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
 	LLVector3d	plane_normal_global_d;
 	plane_normal_global_d.setVec(plane_normal_global);
-	F64	mouse_look_at_scale = (plane_normal_global_d * (plane_point_global - gAgent.getCameraPositionGlobal()))
-								/ (plane_normal_global_d * mouse_direction_global_d);
+	F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
+	LLVector3d plane_origin_camera_rel = plane_point_global - gAgent.getCameraPositionGlobal();
+	F64	mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
+								/ plane_mouse_dot;
+	if (llabs(plane_mouse_dot) < 0.00001)
+	{
+		// if mouse is parallel to plane, return closest point on line through plane origin
+		// that is parallel to camera plane by scaling mouse direction vector
+		// by distance to plane origin, modulated by deviation of mouse direction from plane origin
+		LLVector3d plane_origin_dir = plane_origin_camera_rel;
+		plane_origin_dir.normVec();
+		
+		mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
+	}
+
 	point = gAgent.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
 
 	return mouse_look_at_scale > 0.0;