diff options
author | Josh Bell <josh@lindenlab.com> | 2007-01-09 20:19:31 +0000 |
---|---|---|
committer | Josh Bell <josh@lindenlab.com> | 2007-01-09 20:19:31 +0000 |
commit | 8c344f4da02105428c5933501d028a4a8908a657 (patch) | |
tree | 1463f67247c48a7420620917aa7fde5d6a810820 | |
parent | 8534623734e64387736ddb76683939104d796ade (diff) |
svn merge -r 56560:56599 svn+ssh://svn.lindenlab.com/svn/linden/branches/maintenance
-rw-r--r-- | indra/llmath/v3dmath.h | 9 | ||||
-rw-r--r-- | indra/llui/llcheckboxctrl.cpp | 9 | ||||
-rw-r--r-- | indra/llui/lllineeditor.cpp | 15 | ||||
-rw-r--r-- | indra/llui/lllineeditor.h | 5 | ||||
-rw-r--r-- | indra/llui/llmenugl.cpp | 627 | ||||
-rw-r--r-- | indra/llui/llmenugl.h | 45 | ||||
-rw-r--r-- | indra/llui/llview.cpp | 49 | ||||
-rw-r--r-- | indra/llui/llview.h | 1 | ||||
-rw-r--r-- | indra/llwindow/llkeyboard.cpp | 22 | ||||
-rw-r--r-- | indra/llwindow/llkeyboard.h | 7 | ||||
-rw-r--r-- | indra/llwindow/llkeyboardwin32.cpp | 37 | ||||
-rw-r--r-- | indra/llwindow/llkeyboardwin32.h | 2 | ||||
-rw-r--r-- | indra/newview/app_settings/keys.ini | 7 | ||||
-rw-r--r-- | indra/newview/llchatbar.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llfloatercolorpicker.cpp | 7 | ||||
-rw-r--r-- | indra/newview/llimpanel.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 12 | ||||
-rw-r--r-- | indra/newview/llmanip.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llpreview.cpp | 10 | ||||
-rw-r--r-- | indra/newview/lltexturectrl.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llviewermenu.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llviewerwindow.cpp | 28 |
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; |