summaryrefslogtreecommitdiff
path: root/indra/newview/llfavoritesbar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfavoritesbar.cpp')
-rw-r--r--indra/newview/llfavoritesbar.cpp481
1 files changed, 366 insertions, 115 deletions
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 45bbea7e2a..0e5b943dd3 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -33,16 +33,21 @@
#include "llviewerprecompiledheaders.h"
#include "llfavoritesbar.h"
+
+#include "llbutton.h"
+#include "llfloaterreg.h"
+#include "llinventory.h"
#include "lluictrlfactory.h"
+#include "llmenugl.h"
#include "llagent.h"
-#include "llviewerinventory.h"
-#include "llinventory.h"
-#include "llinventorymodel.h"
-#include "llbutton.h"
#include "llinventorybridge.h"
+#include "llinventorymodel.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h"
+#include "llviewermenu.h"
-static LLRegisterWidget<LLFavoritesBarCtrl> r("favorites_bar");
+static LLDefaultWidgetRegistry::Register<LLFavoritesBarCtrl> r("favorites_bar");
// updateButtons's helper
struct LLFavoritesSort
@@ -64,16 +69,64 @@ struct LLFavoritesSort
}
};
+class LLVisibilityTrackingMenuGL : public LLMenuGL
+{
+protected:
+ LLVisibilityTrackingMenuGL(const LLMenuGL::Params&);
+ friend class LLUICtrlFactory;
+public:
+ virtual void onVisibilityChange (BOOL curVisibilityIn);
+ void setChevronRect(const LLRect& rect) { mChevronRect = rect; }
+
+ bool getClosedByChevronClick() { return mClosedByChevronClick; }
+ void resetClosedByChevronClick() { mClosedByChevronClick = false; }
+
+protected:
+ bool mClosedByChevronClick;
+ LLRect mChevronRect;
+};
+
+LLVisibilityTrackingMenuGL::LLVisibilityTrackingMenuGL(const LLMenuGL::Params& p)
+: LLMenuGL(p),
+ mClosedByChevronClick(false)
+{
+}
+
+//virtual
+void LLVisibilityTrackingMenuGL::onVisibilityChange (BOOL curVisibilityIn)
+{
+ S32 x,y;
+ LLUI::getCursorPositionLocal(LLUI::getRootView(), &x, &y);
+
+ if (!curVisibilityIn && mChevronRect.pointInRect(x, y))
+ {
+ mClosedByChevronClick = true;
+ }
+}
+
LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
: LLUICtrl(p),
- mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall())
+ mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()),
+ mPopupMenuHandle(),
+ mInventoryItemsPopupMenuHandle()
{
+ // Register callback for menus with current registrar (will be parent panel's registrar)
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected",
+ boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2));
+
+ // Add this if we need to selectively enable items
+ //LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected",
+ // boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2));
+
gInventory.addObserver(this);
}
LLFavoritesBarCtrl::~LLFavoritesBarCtrl()
{
gInventory.removeObserver(this);
+
+ LLView::deleteViewByHandle(mPopupMenuHandle);
+ LLView::deleteViewByHandle(mInventoryItemsPopupMenuHandle);
}
BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -87,9 +140,7 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
switch (cargo_type)
{
- // IAN BUG: did the spec ask for calling cards here?
case DAD_LANDMARK:
- case DAD_CALLINGCARD:
{
// Copy the item into the favorites folder (if it's not already there).
LLInventoryItem *item = (LLInventoryItem *)cargo_data;
@@ -127,6 +178,31 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
//virtual
void LLFavoritesBarCtrl::changed(U32 mask)
{
+ if (mFavoriteFolderId.isNull())
+ {
+ mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
+
+ if (mFavoriteFolderId.notNull())
+ {
+ gInventory.fetchDescendentsOf(mFavoriteFolderId);
+ }
+ }
+ else
+ {
+ updateButtons(getRect().getWidth());
+ }
+}
+
+//virtual
+void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ updateButtons(width);
+
+ LLUICtrl::reshape(width, height, called_from_parent);
+}
+
+void LLFavoritesBarCtrl::updateButtons(U32 bar_width)
+{
LLInventoryModel::item_array_t items;
if (!collectFavoriteItems(items))
@@ -134,170 +210,317 @@ void LLFavoritesBarCtrl::changed(U32 mask)
return;
}
+ const S32 buttonHPad = LLUI::sSettingGroups["config"]->getS32("ButtonHPad");
+ const S32 buttonHGap = 2;
+ const S32 buttonVGap = 2;
+ static LLButton::Params default_button_params(LLUICtrlFactory::getDefaultParams<LLButton::Params>());
+ std::string flat_icon = "transparent.j2c";
+ std::string hover_icon = default_button_params.image_unselected.name;
+ std::string hover_icon_selected = default_button_params.image_selected.name;
+
+ S32 curr_x = buttonHGap;
+
S32 count = items.count();
- if (getChildCount() == count)
+
+ const S32 chevron_button_width = mFont->getWidth(">>") + buttonHPad * 2;
+
+ S32 buttons_space = bar_width - curr_x;
+
+ S32 first_drop_down_item = count;
+
+ // Calculating, how much buttons can fit in the bar
+ S32 buttons_width = 0;
+ for (S32 i = 0; i < count; ++i)
{
- // Check whether buttons are reflecting state of favorite inventory folder
- const LLView::child_list_t *buttons_list = getChildList();
- S32 i = 0;
- for(LLView::child_list_const_iter_t iter = buttons_list->begin(); iter != buttons_list->end(); iter++)
+ buttons_width += mFont->getWidth(items.get(i)->getName()) + buttonHPad * 2 + buttonHGap;
+ if (buttons_width > buttons_space)
{
- LLButton *button = (LLButton *)*iter;
- LLInventoryItem* item = items.get(i);
- // tooltip contains full name of item, label can be cutted
- if (button->getToolTip() != item->getName())
+ // There is no space for all buttons.
+ // Calculating the number of buttons, that are fit with chevron button
+ buttons_space -= chevron_button_width + buttonHGap;
+ while (i >= 0 && buttons_width > buttons_space)
{
- break;
+ buttons_width -= mFont->getWidth(items.get(i)->getName()) + buttonHPad * 2 + buttonHGap;
+ i--;
}
-
-
- i++;
+ first_drop_down_item = i + 1; // First item behind visible items
+
+ break;
}
+ }
- // Check passed, nothing is changed
- if (i < items.count())
+ // If inventory items are not changed up to mFirstDropDownItem, no need to recreate them
+ if (mFirstDropDownItem == first_drop_down_item && (mItemNamesCache.size() == count || mItemNamesCache.size() == mFirstDropDownItem))
+ {
+ S32 i;
+ for (i = 0; i < mFirstDropDownItem; ++i)
{
+ if (mItemNamesCache.get(i) != items.get(i)->getName())
+ {
+ break;
+ }
+ }
+ if (i == mFirstDropDownItem)
+ {
+ // Chevron button should stay right aligned
+ LLView *chevron_button = getChildView(std::string(">>"), FALSE, FALSE);
+ if (chevron_button)
+ {
+ LLRect rect;
+ rect.setOriginAndSize(bar_width - chevron_button_width - buttonHGap, buttonVGap, chevron_button_width, getRect().getHeight()-buttonVGap);
+ chevron_button->setRect(rect);
+
+ S32 chevron_root_x, chevron_root_y;
+ localPointToOtherView(rect.mLeft, rect.mBottom, &chevron_root_x, &chevron_root_y, LLUI::getRootView());
+ mChevronRect.setOriginAndSize(chevron_root_x, chevron_root_y, rect.getWidth(), rect.getHeight());
+ }
return;
}
}
- //FIXME: optimize this
- deleteAllChildren();
-
- LLButton::Params bparams;
+ mFirstDropDownItem = first_drop_down_item;
- const S32 buttonWidth = LLUI::sSettingGroups["config"]->getS32("ButtonHPad") * 2;
- LLRect rect;
+ mItemNamesCache.clear();
+ for (S32 i = 0; i < mFirstDropDownItem; i++)
+ {
+ mItemNamesCache.put(items.get(i)->getName());
+ }
- for(S32 i = 0; i < count; ++i)
+ // Rebuild the buttons only
+ // child_list_t is a linked list, so safe to erase from the middle if we pre-incrament the iterator
+ for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); )
+ {
+ child_list_const_iter_t cur_it = child_it++;
+ LLView* viewp = *cur_it;
+ LLButton* button = dynamic_cast<LLButton*>(viewp);
+ if (button)
+ {
+ removeChild(button);
+ delete button;
+ }
+ }
+
+ // Adding buttons
+ for(S32 i = 0; i < mFirstDropDownItem; i++)
{
- rect.setOriginAndSize(0, 0, buttonWidth, llround(mFont->getLineHeight()));
+
+ LLInventoryItem* item = items.get(i);
+ S32 buttonWidth = mFont->getWidth(item->getName()) + buttonHPad * 2;
+
+ LLRect rect;
+ rect.setOriginAndSize(curr_x, buttonVGap, buttonWidth, getRect().getHeight()-buttonVGap);
+
+ LLButton::Params bparams;
+ bparams.image_unselected.name(flat_icon);
+ bparams.image_disabled.name(flat_icon);
+ bparams.image_selected.name(hover_icon_selected);
+ bparams.image_hover_selected.name(hover_icon_selected);
+ bparams.image_disabled_selected.name(hover_icon_selected);
+ bparams.image_hover_unselected.name(hover_icon);
bparams.follows.flags (FOLLOWS_LEFT | FOLLOWS_BOTTOM);
bparams.rect (rect);
bparams.tab_stop(false);
bparams.font(mFont);
- bparams.click_callback.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, 0));
+ bparams.name(item->getName());
+ bparams.tool_tip(item->getName());
+ bparams.click_callback.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
+ bparams.rightclick_callback.function(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID()));
- LLButton *button = LLUICtrlFactory::create<LLButton> (bparams);
+ addChildInBack(LLUICtrlFactory::create<LLButton> (bparams));
- addChildInBack(button);
+ curr_x += buttonWidth + buttonHGap;
}
- updateButtons(getRect().getWidth(), items);
+ // Chevron button
+ if (mFirstDropDownItem != count)
+ {
+ LLButton::Params bparams;
+
+ LLRect rect;
+ rect.setOriginAndSize(bar_width - chevron_button_width - buttonHGap, buttonVGap, chevron_button_width, getRect().getHeight()-buttonVGap);
+
+ bparams.follows.flags (FOLLOWS_LEFT | FOLLOWS_BOTTOM);
+ bparams.image_unselected.name(flat_icon);
+ bparams.image_disabled.name(flat_icon);
+ bparams.image_selected.name(hover_icon_selected);
+ bparams.image_hover_selected.name(hover_icon_selected);
+ bparams.image_disabled_selected.name(hover_icon_selected);
+ bparams.image_hover_unselected.name(hover_icon);
+ bparams.rect (rect);
+ bparams.tab_stop(false);
+ bparams.font(mFont);
+ bparams.name(">>");
+ bparams.click_callback.function(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this));
+
+ addChildInBack(LLUICtrlFactory::create<LLButton> (bparams));
+
+ S32 chevron_root_x, chevron_root_y;
+ localPointToOtherView(rect.mLeft, rect.mBottom, &chevron_root_x, &chevron_root_y, LLUI::getRootView());
+ mChevronRect.setOriginAndSize(chevron_root_x, chevron_root_y, rect.getWidth(), rect.getHeight());
+ }
}
-//virtual
-void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent)
+BOOL LLFavoritesBarCtrl::postBuild()
{
- LLInventoryModel::item_array_t items;
- if (collectFavoriteItems(items))
+ // make the popup menu available
+ LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_favorites.xml", gMenuHolder);
+ if (!menu)
{
- updateButtons(width, items);
+ menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu");
}
+ menu->setBackgroundColor(gSavedSkinSettings.getColor("MenuPopupBgColor"));
+ mInventoryItemsPopupMenuHandle = menu->getHandle();
- LLUICtrl::reshape(width, height, called_from_parent);
+ return TRUE;
}
-void LLFavoritesBarCtrl::updateButtons(U32 barWidth, LLInventoryModel::item_array_t items)
+BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
{
- std::sort(items.begin(), items.end(), LLFavoritesSort());
+ if (mFavoriteFolderId.isNull())
+ return FALSE;
+
+ LLInventoryModel::cat_array_t cats;
- const S32 buttonHPad = LLUI::sSettingGroups["config"]->getS32("ButtonHPad");
- const S32 buttonHGap = 2;
+ LLIsType is_type(LLAssetType::AT_LANDMARK);
+ gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
- S32 curr_x = buttonHGap;
+ std::sort(items.begin(), items.end(), LLFavoritesSort());
- S32 count = items.count();
- S32 labelsWidth = 0;
+ return TRUE;
+}
- for (S32 i = 0; i < count; ++i)
+void LLFavoritesBarCtrl::showDropDownMenu()
+{
+ if (mPopupMenuHandle.isDead())
{
- labelsWidth += mFont->getWidth(items.get(i)->getName());
- }
-
- const S32 ellipsisWIdth = mFont->getWidth("...");
+ LLMenuGL::Params menu_p;
+ menu_p.name("favorites menu");
+ menu_p.can_tear_off(false);
+ menu_p.visible(false);
+ menu_p.scrollable(true);
- F32 shrinkFactor = 1.0f;
+ LLVisibilityTrackingMenuGL* menu = LLUICtrlFactory::create<LLVisibilityTrackingMenuGL>(menu_p);
- S32 labelsSpace = barWidth - buttonHGap * (count + 1) - buttonHPad * 2 * count; // There is leading buttonHGap in front of first button,
- // one buttonHGap at the end of each button and 2 buttonHPad's
- if (labelsWidth >= labelsSpace)
- {
- shrinkFactor = (float)labelsSpace / labelsWidth;
+ mPopupMenuHandle = menu->getHandle();
}
- const LLView::child_list_t *buttons_list = getChildList();
+ LLVisibilityTrackingMenuGL* menu = (LLVisibilityTrackingMenuGL*)mPopupMenuHandle.get();
- S32 i = 0;
- for(LLView::child_list_const_iter_t iter = buttons_list->begin(); iter != buttons_list->end(); iter++)
+ if(menu)
{
- LLButton *button = (LLButton *)*iter;
-
- LLInventoryItem* item = items.get(i);
+ if (menu->getClosedByChevronClick())
+ {
+ menu->resetClosedByChevronClick();
+ return;
+ }
- LLRect rect;
+ if (menu->getVisible())
+ {
+ menu->setVisible(FALSE);
+ menu->resetClosedByChevronClick();
+ return;
+ }
- S32 labelWidth = mFont->getWidth(item->getName());
+ LLInventoryModel::item_array_t items;
- if (shrinkFactor < 1.0f)
+ if (!collectFavoriteItems(items))
{
- labelWidth = (S32) ((float)labelWidth * shrinkFactor);
+ return;
+ }
- if (labelWidth > ellipsisWIdth)
- {
- labelWidth -= ellipsisWIdth;
+ S32 count = items.count();
- S32 charsTotal = item->getName().length();
- S32 charsFitted = 1;
- while (charsFitted < charsTotal && mFont->getWidth(item->getName(), 0, charsFitted) < labelWidth)
+ // Check it there are changed items, since last call
+ if (mItemNamesCache.size() == count)
+ {
+ S32 i;
+ for (i = mFirstDropDownItem; i < count; i++)
+ {
+ if (mItemNamesCache.get(i) != items.get(i)->getName())
{
- charsFitted++;
+ break;
}
+ }
+
+ // Check passed, just show the menu
+ if (i == count)
+ {
+ menu->buildDrawLabels();
+ menu->updateParent(LLMenuGL::sMenuContainer);
- charsFitted--;
- labelWidth += ellipsisWIdth;
+ menu->setChevronRect(mChevronRect);
- button->setLabel(item->getName().substr(0, charsFitted) + "...");
+ LLMenuGL::showPopup(this, menu, getRect().getWidth() - menu->getRect().getWidth(), 0);
+ return;
}
- else
+ }
+
+ // Add menu items to cache, if there is only names of buttons
+ if (mItemNamesCache.size() == mFirstDropDownItem)
+ {
+ for (S32 i = mFirstDropDownItem; i < count; i++)
{
- button->setLabel((LLStringExplicit)"");
- labelWidth = 0;
+ mItemNamesCache.put(items.get(i)->getName());
}
}
- else
+
+ menu->empty();
+
+ U32 max_width = 0;
+
+ // Menu will not be wider, than bar
+ S32 bar_width = getRect().getWidth();
+
+ for(S32 i = mFirstDropDownItem; i < count; i++)
{
- button->setLabel(item->getName());
- }
+ LLInventoryItem* item = items.get(i);
+ const std::string& item_name = item->getName();
- S32 buttonWidth = labelWidth + buttonHPad * 2;
- rect.setOriginAndSize(curr_x, 2, buttonWidth, llround(mFont->getLineHeight()));
- button->setRect(rect);
+ LLMenuItemCallGL::Params item_params;
+ item_params.name(item_name);
+ item_params.label(item_name);
+
+ item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID()));
- button->setToolTip(item->getName());
+ LLMenuItemCallGL *menu_item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- curr_x += buttonWidth + buttonHGap;
+ // Check whether item name wider than menu
+ if ((S32) menu_item->getNominalWidth() > bar_width)
+ {
+ S32 chars_total = item_name.length();
+ S32 chars_fitted = 1;
+ menu_item->setLabel(LLStringExplicit(""));
+ S32 label_space = bar_width - menu_item->getFont()->getWidth("...") -
+ menu_item->getNominalWidth(); // This returns width of menu item with empty label (pad pixels)
- i++;
- }
-}
+ while (chars_fitted < chars_total && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space)
+ {
+ chars_fitted++;
+ }
+ chars_fitted--; // Rolling back one char, that doesn't fit
-BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items)
-{
- LLUUID favorite_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE);
+ menu_item->setLabel(item_name.substr(0, chars_fitted) + "...");
+ }
- if (!favorite_folder_id.notNull())
- return FALSE;
-
- LLInventoryModel::cat_array_t cats;
+ max_width = llmax(max_width, menu_item->getNominalWidth());
- gInventory.collectDescendents(favorite_folder_id, cats, items, LLInventoryModel::EXCLUDE_TRASH);
+ menu->addChild(menu_item);
+ }
- return TRUE;
+ // Menu will not be wider, than bar
+ max_width = llmin((S32)max_width, bar_width);
+
+ menu->buildDrawLabels();
+ menu->updateParent(LLMenuGL::sMenuContainer);
+
+ menu->setChevronRect(mChevronRect);
+
+ LLMenuGL::showPopup(this, menu, getRect().getWidth() - max_width, 0);
+ }
}
-void LLFavoritesBarCtrl::onButtonClick(int idx)
+void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id)
{
LLInventoryModel::item_array_t items;
@@ -306,23 +529,51 @@ void LLFavoritesBarCtrl::onButtonClick(int idx)
return;
}
- S32 count = items.count();
+ // We only have one Inventory, gInventory. Some day this should be better abstracted.
+ LLInvFVBridgeAction::doAction(item_id,&gInventory);
+}
- if (idx < 0 || idx >= count)
+void LLFavoritesBarCtrl::onButtonRightClick(LLUUID item_id)
+{
+ mSelectedItemID = item_id;
+
+ LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get();
+ if (!menu)
{
- llwarns << "Invalid favorites bar index" << llendl;
return;
}
+
+ menu->updateParent(LLMenuGL::sMenuContainer);
- LLInventoryItem* item = items.get(idx);
- if(item)
- {
- LLUUID item_id = item->getUUID();
- LLAssetType::EType item_type = item->getType();
+ S32 x,y;
+ LLUI::getCursorPositionLocal(this, &x, &y);
+ LLMenuGL::showPopup(this, menu, x, y);
+}
- //TODO - donno but may be we must use InventoryModel from InventoryView
- //think for now there is only one model...but still
- LLInvFVBridgeAction::doAction(item_type,item_id,&gInventory);
+void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
+{
+ std::string action = userdata.asString();
+ llinfos << "Action = " << action << " Item = " << mSelectedItemID.asString() << llendl;
+
+ LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID);
+ if (!item)
+ return;
+
+ if (action == "open")
+ {
+ teleport_via_landmark(item->getAssetUUID());
+ }
+ else if (action == "about")
+ {
+ LLFloaterReg::showInstance("preview_landmark", LLSD(mSelectedItemID), TAKE_FOCUS_YES);
+ }
+ else if (action == "rename")
+ {
+ // Would need to re-implement this:
+ // folder->startRenamingSelectedItem();
+ }
+ else if (action == "delete")
+ {
+ gInventory.removeItem(mSelectedItemID);
}
}
-