Implemented low task EXT-1153(FlatListView should support keyboard)
--HG-- branch : product-enginemeow-7.2.2
parent
0c468557b9
commit
c9101f603a
|
|
@ -94,6 +94,9 @@ bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*
|
|||
item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4));
|
||||
item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4));
|
||||
|
||||
// Children don't accept the focus
|
||||
item->setTabStop(false);
|
||||
|
||||
rearrangeItems();
|
||||
notifyParentItemsRectChanged();
|
||||
return true;
|
||||
|
|
@ -282,6 +285,9 @@ void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/)
|
|||
{
|
||||
onCommit();
|
||||
}
|
||||
|
||||
// Stretch selected items rect to ensure it won't be clipped
|
||||
mSelectedItemsBorder->setRect(getSelectedItemsRect().stretch(-1));
|
||||
}
|
||||
|
||||
void LLFlatListView::setNoItemsCommentText(const std::string& comment_text)
|
||||
|
|
@ -381,8 +387,34 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p)
|
|||
//we don't need to stretch in vertical direction on reshaping by a parent
|
||||
//no bottom following!
|
||||
mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP);
|
||||
|
||||
LLViewBorder::Params params;
|
||||
params.name("scroll border");
|
||||
params.rect(getSelectedItemsRect());
|
||||
params.visible(false);
|
||||
params.bevel_style(LLViewBorder::BEVEL_IN);
|
||||
mSelectedItemsBorder = LLUICtrlFactory::create<LLViewBorder> (params);
|
||||
mItemsPanel->addChild( mSelectedItemsBorder );
|
||||
};
|
||||
|
||||
// virtual
|
||||
void LLFlatListView::draw()
|
||||
{
|
||||
// Highlight border if a child of this container has keyboard focus
|
||||
if( mSelectedItemsBorder->getVisible() )
|
||||
{
|
||||
mSelectedItemsBorder->setKeyboardFocusHighlight( hasFocus() );
|
||||
}
|
||||
LLScrollContainer::draw();
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLFlatListView::postBuild()
|
||||
{
|
||||
setTabStop(true);
|
||||
return LLScrollContainer::postBuild();
|
||||
}
|
||||
|
||||
void LLFlatListView::rearrangeItems()
|
||||
{
|
||||
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
|
||||
|
|
@ -444,6 +476,9 @@ void LLFlatListView::rearrangeItems()
|
|||
// move top for next item in list
|
||||
item_new_top -= (rc.getHeight() + mItemPad);
|
||||
}
|
||||
|
||||
// Stretch selected items rect to ensure it won't be clipped
|
||||
mSelectedItemsBorder->setRect(getSelectedItemsRect().stretch(-1));
|
||||
}
|
||||
|
||||
void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask)
|
||||
|
|
@ -473,6 +508,64 @@ void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask)
|
|||
onItemMouseClick(item_pair, mask);
|
||||
}
|
||||
|
||||
BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
BOOL reset_selection = (mask != MASK_SHIFT);
|
||||
BOOL handled = FALSE;
|
||||
switch (key)
|
||||
{
|
||||
case KEY_RETURN:
|
||||
{
|
||||
if (mSelectedItemPairs.size() && mask == MASK_NONE)
|
||||
{
|
||||
mOnReturnSignal(this, getValue());
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_UP:
|
||||
{
|
||||
if ( !selectNextItemPair(true, reset_selection) && reset_selection)
|
||||
{
|
||||
// If case we are in accordion tab notify parent to go to the previous accordion
|
||||
notifyParent(LLSD().insert("action","select_prev"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_DOWN:
|
||||
{
|
||||
if ( !selectNextItemPair(false, reset_selection) && reset_selection)
|
||||
{
|
||||
// If case we are in accordion tab notify parent to go to the next accordion
|
||||
notifyParent(LLSD().insert("action","select_next"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'A':
|
||||
{
|
||||
if(MASK_CONTROL & mask)
|
||||
{
|
||||
selectAll();
|
||||
handled = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( key == KEY_UP || key == KEY_DOWN )
|
||||
{
|
||||
LLRect selcted_rect = getLastSelectedItemRect().stretch(1);
|
||||
LLRect visible_rect = getVisibleContentRect();
|
||||
if ( !visible_rect.contains (selcted_rect) )
|
||||
scrollToShowRect(selcted_rect);
|
||||
handled = TRUE;
|
||||
}
|
||||
|
||||
return handled ? handled : LLScrollContainer::handleKeyHere(key, mask);
|
||||
}
|
||||
|
||||
LLFlatListView::item_pair_t* LLFlatListView::getItemPair(LLPanel* item) const
|
||||
{
|
||||
llassert(item);
|
||||
|
|
@ -552,6 +645,143 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select)
|
|||
onCommit();
|
||||
}
|
||||
|
||||
setFocus(TRUE);
|
||||
|
||||
// Stretch selected items rect to ensure it won't be clipped
|
||||
mSelectedItemsBorder->setRect(getSelectedItemsRect().stretch(-1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LLRect LLFlatListView::getLastSelectedItemRect()
|
||||
{
|
||||
if (!mSelectedItemPairs.size())
|
||||
{
|
||||
return LLRect::null;
|
||||
}
|
||||
|
||||
return mSelectedItemPairs.back()->first->getRect();
|
||||
}
|
||||
|
||||
LLRect LLFlatListView::getSelectedItemsRect()
|
||||
{
|
||||
if (!mSelectedItemPairs.size())
|
||||
{
|
||||
return LLRect::null;
|
||||
}
|
||||
LLRect rc = getLastSelectedItemRect();
|
||||
for ( pairs_const_iterator_t
|
||||
it = mSelectedItemPairs.begin(),
|
||||
it_end = mSelectedItemPairs.end();
|
||||
it != it_end; ++it )
|
||||
{
|
||||
rc.unionWith((*it)->first->getRect());
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// virtual
|
||||
bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection)
|
||||
{
|
||||
// No items - no actions!
|
||||
if ( !mItemPairs.size() )
|
||||
return false;
|
||||
|
||||
item_pair_t* cur_sel_pair = NULL;
|
||||
item_pair_t* to_sel_pair = NULL;
|
||||
|
||||
if ( mSelectedItemPairs.size() )
|
||||
{
|
||||
// Take the last selected pair
|
||||
cur_sel_pair = mSelectedItemPairs.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there weren't selected items then choose the first one bases on given direction
|
||||
cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front();
|
||||
// Force selection to first item
|
||||
to_sel_pair = cur_sel_pair;
|
||||
}
|
||||
|
||||
// Bases on given direction choose next item to select
|
||||
if ( is_up_direction )
|
||||
{
|
||||
// Find current selected item position in mItemPairs list
|
||||
pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair);
|
||||
|
||||
for (;++sel_it != mItemPairs.rend();)
|
||||
{
|
||||
// skip invisible items
|
||||
if ( (*sel_it)->first->getVisible() )
|
||||
{
|
||||
to_sel_pair = *sel_it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find current selected item position in mItemPairs list
|
||||
pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair);
|
||||
|
||||
for (;++sel_it != mItemPairs.end();)
|
||||
{
|
||||
// skip invisible items
|
||||
if ( (*sel_it)->first->getVisible() )
|
||||
{
|
||||
to_sel_pair = *sel_it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( to_sel_pair )
|
||||
{
|
||||
bool select = true;
|
||||
|
||||
if ( reset_selection )
|
||||
{
|
||||
// Reset current selection if we were asked about it
|
||||
resetSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If item already selected and no reset request than we should deselect last selected item.
|
||||
select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair));
|
||||
}
|
||||
|
||||
// Select/Deselect next item
|
||||
selectItemPair(select ? to_sel_pair : cur_sel_pair, select);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLFlatListView::selectAll()
|
||||
{
|
||||
if (!mAllowSelection)
|
||||
return false;
|
||||
|
||||
mSelectedItemPairs.clear();
|
||||
|
||||
for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it)
|
||||
{
|
||||
item_pair_t* item_pair = *it;
|
||||
mSelectedItemPairs.push_back(item_pair);
|
||||
//a way of notifying panel of selection state changes
|
||||
LLPanel* item = item_pair->first;
|
||||
item->setValue(SELECTED_EVENT);
|
||||
}
|
||||
|
||||
if (mCommitOnSelectionChange)
|
||||
{
|
||||
onCommit();
|
||||
}
|
||||
|
||||
// Stretch selected items rect to ensure it won't be clipped
|
||||
mSelectedItemsBorder->setRect(getSelectedItemsRect().stretch(-1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -670,4 +900,15 @@ void LLFlatListView::getValues(std::vector<LLSD>& values) const
|
|||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFlatListView::onFocusReceived()
|
||||
{
|
||||
mSelectedItemsBorder->setVisible(TRUE);
|
||||
}
|
||||
// virtual
|
||||
void LLFlatListView::onFocusLost()
|
||||
{
|
||||
mSelectedItemsBorder->setVisible(FALSE);
|
||||
}
|
||||
|
||||
//EOF
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ public:
|
|||
|
||||
virtual ~LLFlatListView() { clear(); };
|
||||
|
||||
/**
|
||||
* Connects callback to signal called when Return key is pressed.
|
||||
*/
|
||||
boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); }
|
||||
|
||||
/** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */
|
||||
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
|
|
@ -318,6 +322,10 @@ protected:
|
|||
|
||||
virtual bool selectItemPair(item_pair_t* item_pair, bool select);
|
||||
|
||||
virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection);
|
||||
|
||||
virtual bool selectAll();
|
||||
|
||||
virtual bool isSelected(item_pair_t* item_pair) const;
|
||||
|
||||
virtual bool removeItemPair(item_pair_t* item_pair);
|
||||
|
|
@ -331,6 +339,19 @@ protected:
|
|||
*/
|
||||
void notifyParentItemsRectChanged();
|
||||
|
||||
virtual BOOL handleKeyHere(KEY key, MASK mask);
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
virtual void onFocusReceived();
|
||||
|
||||
virtual void onFocusLost();
|
||||
|
||||
virtual void draw();
|
||||
|
||||
LLRect getLastSelectedItemRect();
|
||||
|
||||
LLRect getSelectedItemsRect();
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -381,6 +402,10 @@ private:
|
|||
LLRect mPrevNotifyParentRect;
|
||||
|
||||
LLTextBox* mNoItemsCommentTextbox;
|
||||
|
||||
LLViewBorder* mSelectedItemsBorder;
|
||||
|
||||
commit_signal_t mOnReturnSignal;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -536,8 +536,15 @@ BOOL LLPanelPeople::postBuild()
|
|||
mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList));
|
||||
mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList));
|
||||
|
||||
// Set openning IM as default on return action for avatar lists
|
||||
mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
|
||||
mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
|
||||
mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
|
||||
mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
|
||||
|
||||
mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
|
||||
mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this));
|
||||
mGroupList->setReturnCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
|
||||
|
||||
LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>("tab_all");
|
||||
accordion_tab->setDropDownStateChangedCallback(
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av
|
|||
mAvatarList->setNoItemsCommentText(LLTrans::getString("LoadingData"));
|
||||
mAvatarList->setDoubleClickCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList));
|
||||
mAvatarList->setRefreshCompleteCallback(boost::bind(&LLParticipantList::onAvatarListRefreshed, this, _1, _2));
|
||||
// Set onAvatarListDoubleClicked as default on_return action.
|
||||
mAvatarList->setReturnCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this, mAvatarList));
|
||||
|
||||
mParticipantListMenu = new LLParticipantListMenu(*this);
|
||||
mAvatarList->setContextMenu(mParticipantListMenu);
|
||||
|
|
@ -99,6 +101,7 @@ void LLParticipantList::setSpeakingIndicatorsVisible(BOOL visible)
|
|||
|
||||
void LLParticipantList::onAvatarListDoubleClicked(LLAvatarList* list)
|
||||
{
|
||||
// NOTE(EM): Should we check if there is multiple selection and start conference if it is so?
|
||||
LLUUID clicked_id = list->getSelectedUUID();
|
||||
|
||||
if (clicked_id.isNull() || clicked_id == gAgent.getID())
|
||||
|
|
|
|||
Loading…
Reference in New Issue