summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llmath/v3dmath.h9
-rw-r--r--indra/llui/llcheckboxctrl.cpp9
-rw-r--r--indra/llui/lllineeditor.cpp15
-rw-r--r--indra/llui/lllineeditor.h5
-rw-r--r--indra/llui/llmenugl.cpp627
-rw-r--r--indra/llui/llmenugl.h45
-rw-r--r--indra/llui/llview.cpp49
-rw-r--r--indra/llui/llview.h1
-rw-r--r--indra/llwindow/llkeyboard.cpp22
-rw-r--r--indra/llwindow/llkeyboard.h7
-rw-r--r--indra/llwindow/llkeyboardwin32.cpp37
-rw-r--r--indra/llwindow/llkeyboardwin32.h2
-rw-r--r--indra/newview/app_settings/keys.ini7
-rw-r--r--indra/newview/llchatbar.cpp1
-rw-r--r--indra/newview/llfloatercolorpicker.cpp7
-rw-r--r--indra/newview/llimpanel.cpp1
-rw-r--r--indra/newview/llinventorymodel.cpp12
-rw-r--r--indra/newview/llmanip.cpp4
-rw-r--r--indra/newview/llpreview.cpp10
-rw-r--r--indra/newview/lltexturectrl.cpp8
-rw-r--r--indra/newview/llviewermenu.cpp2
-rw-r--r--indra/newview/llviewerwindow.cpp28
22 files changed, 640 insertions, 268 deletions
diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h
index d8feb10757..5d414df5d6 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 3b054d2fec..fde27132e6 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 41049fdf1f..46d66b3cd4 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 1df5dd88f7..ef2f43a1d3 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 f8fcefd11d..650596c7f7 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 7dcd950996..0dca8f2550 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 64ba319151..8c3d2362c5 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 9a36c56e3e..839c300476 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 ee42f53571..a0970f0140 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 0c47d117d0..1d7919f06b 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 ddc099418c..fe553a8230 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 e7eb4b9c1e..c8355bb7a1 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 f6232abb47..b7fc6f9286 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 208a14a6c6..e958bd2152 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 181a66c2ef..59147c54f8 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 718ea894aa..865de53512 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 509f040c34..f1c4f0d918 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 74c7ae6c18..57d34f672b 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 5cc2d2e39f..82974da634 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 106bfd0095..cb7679557e 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 689dcee663..8ab2b52a50 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 8920d09fa6..df396c93be 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;