diff options
Diffstat (limited to 'indra/llui')
26 files changed, 411 insertions, 135 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 2ed1082f56..136fd2a9ac 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -332,11 +332,31 @@ void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) == getChildList()->end()) addChild(accordion_tab); mAccordionTabs.push_back(accordion_tab); - + accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, mAccordionTabs.size() - 1) ); } +void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view) +{ + LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(view); + if(!accordion_tab) + return; + + if(std::find(getChildList()->begin(),getChildList()->end(),accordion_tab) != getChildList()->end()) + removeChild(accordion_tab); + + for (std::vector<LLAccordionCtrlTab*>::iterator iter = mAccordionTabs.begin(); + iter != mAccordionTabs.end(); ++iter) + { + if (accordion_tab == (*iter)) + { + mAccordionTabs.erase(iter); + break; + } + } +} + void LLAccordionCtrl::arrangeSinge() { S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter @@ -372,11 +392,33 @@ void LLAccordionCtrl::arrangeSinge() } else { - panel_height = expanded_height; + if(mFitParent) + { + panel_height = expanded_height; + } + else + { + if(accordion_tab->getAccordionView()) + { + panel_height = accordion_tab->getAccordionView()->getRect().getHeight() + + accordion_tab->getHeaderHeight() + 2*BORDER_MARGIN; + } + else + { + panel_height = accordion_tab->getRect().getHeight(); + } + } } + + // make sure at least header is shown + panel_height = llmax(panel_height, accordion_tab->getHeaderHeight()); + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); panel_top-=mAccordionTabs[i]->getRect().getHeight(); } + + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); + updateLayout(getRect().getWidth(), getRect().getHeight()); } void LLAccordionCtrl::arrangeMultiple() diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h index 7c29e545b7..ab7d6548ca 100644 --- a/indra/llui/llaccordionctrl.h +++ b/indra/llui/llaccordionctrl.h @@ -92,6 +92,7 @@ public: virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void addCollapsibleCtrl(LLView* view); + void removeCollapsibleCtrl(LLView* view); void arrange(); diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 0959722aa6..d389236642 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -425,6 +425,9 @@ bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) setDisplayChildren(getDisplayChildren()); } + if (!mContainerPanel) + mContainerPanel = findContainerView(); + return res; } @@ -860,5 +863,16 @@ void LLAccordionCtrlTab::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, panel->reshape( width, height, 1); panel->setRect(panel_rect); } +BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, MASK mask) +{ + //header may be not the first child but we need to process it first + if(y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT/2) ) + { + //inside tab header + //fix for EXT-6619 + return TRUE; + } + return LLUICtrl::handleToolTip(x, y, mask); +} diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h index 4b8b22405e..fb19d17e99 100644 --- a/indra/llui/llaccordionctrltab.h +++ b/indra/llui/llaccordionctrltab.h @@ -148,6 +148,8 @@ public: virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleToolTip(S32 x, S32 y, MASK mask); + virtual bool addChild(LLView* child, S32 tab_group); bool isExpanded() { return mDisplayChildren; } diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 33c6a8b6ac..0255061b12 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -1003,6 +1003,11 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image) mFadeWhenDisabled = TRUE; } +void LLButton::setImagePressed(LLPointer<LLUIImage> image) +{ + mImagePressed = image; +} + void LLButton::setImageHoverSelected(LLPointer<LLUIImage> image) { mImageHoverSelected = image; diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 6a1e3a9425..a4d81ed6c3 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -246,6 +246,7 @@ public: void setImageHoverUnselected(LLPointer<LLUIImage> image); void setImageDisabled(LLPointer<LLUIImage> image); void setImageDisabledSelected(LLPointer<LLUIImage> image); + void setImagePressed(LLPointer<LLUIImage> image); void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } BOOL getCommitOnReturn() const { return mCommitOnReturn; } diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 9d4e2fa495..9f83fcca35 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -249,7 +249,7 @@ void LLDragHandleTop::reshapeTitleBox() } const LLFontGL* font = LLFontGL::getFontSansSerif(); S32 title_width = getRect().getWidth(); - title_width -= 2 * LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth(); + title_width -= LEFT_PAD + 2 * BORDER_PAD + getButtonsRect().getWidth(); S32 title_height = llround(font->getLineHeight()); LLRect title_rect; title_rect.setLeftTopAndSize( diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 35f5a6bbb9..990bf5cd22 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1,10 +1,10 @@ /** * @file llflatlistview.cpp - * @brief LLFlatListView base class + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2009, Linden Research, Inc. + * Copyright (c) 2009-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -504,7 +504,68 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) //*TODO find a better place for that enforcing stuff if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; - + + if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) + && mMultipleSelection && !mSelectedItemPairs.empty() ) + { + item_pair_t* last_selected_pair = mSelectedItemPairs.back(); + + // If item_pair is already selected - do nothing + if (last_selected_pair == item_pair) + return; + + bool grab_items = false; + pairs_list_t pairs_to_select; + + // Pick out items from list between last selected and current clicked item_pair. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* cur = *iter; + if (cur == last_selected_pair || cur == item_pair) + { + grab_items = !grab_items; + // Skip last selected and current clicked item pairs. + continue; + } + if (!cur->first->getVisible()) + { + // Skip invisible item pairs. + continue; + } + if (grab_items) + { + pairs_to_select.push_back(cur); + } + } + + if (select_item) + { + pairs_to_select.push_back(item_pair); + } + + for (pairs_iterator_t + iter = pairs_to_select.begin(), + iter_end = pairs_to_select.end(); + iter != iter_end; ++iter) + { + item_pair_t* pair_to_select = *iter; + selectItemPair(pair_to_select, true); + } + + if (!select_item) + { + // Item was already selected but there is a need to update last selected item and its border. + // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). + mSelectedItemPairs.remove(item_pair); + mSelectedItemPairs.push_back(item_pair); + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + } + return; + } + if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(); selectItemPair(item_pair, select_item); } @@ -1061,4 +1122,38 @@ void LLFlatListView::detachItems(std::vector<LLPanel*>& detached_items) } } + +/************************************************************************/ +/* LLFlatListViewEx implementation */ +/************************************************************************/ +LLFlatListViewEx::Params::Params() +: no_items_msg("no_items_msg") +, no_filtered_items_msg("no_filtered_items_msg") +{ + +} + +LLFlatListViewEx::LLFlatListViewEx(const Params& p) +: LLFlatListView(p) +, mNoFilteredItemsMsg(p.no_filtered_items_msg) +, mNoItemsMsg(p.no_items_msg) +{ + +} + +void LLFlatListViewEx::updateNoItemsMessage(bool items_filtered) +{ + if (items_filtered) + { + // items were filtered + setNoItemsCommentText(mNoFilteredItemsMsg); + } + else + { + // list does not contain any items at all + setNoItemsCommentText(mNoItemsMsg); + } + +} + //EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index e3c07e811f..f7d094f7e7 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -1,10 +1,10 @@ /** * @file llflatlistview.h - * @brief LLFlatListView base class + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2009, Linden Research, Inc. + * Copyright (c) 2009-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -430,4 +430,54 @@ private: commit_signal_t mOnReturnSignal; }; +/** + * Extends LLFlatListView functionality to show different messages when there are no items in the + * list depend on whether they are filtered or not. + * + * Class provides one message per case of empty list. + * It also provides protected updateNoItemsMessage() method to be called each time when derived list + * is changed to update base mNoItemsCommentTextbox value. + * + * It is implemented to avoid duplication of this functionality in concrete implementations of the + * lists. It is intended to be used as a base class for lists which should support two different + * messages for empty state. Can be improved to support more than two messages via state-to-message map. + */ +class LLFlatListViewEx : public LLFlatListView +{ +public: + struct Params : public LLInitParam::Block<Params, LLFlatListView::Params> + { + /** + * Contains a message for empty list when it does not contain any items at all. + */ + Optional<std::string> no_items_msg; + + /** + * Contains a message for empty list when its items are removed by filtering. + */ + Optional<std::string> no_filtered_items_msg; + Params(); + }; + + // *WORKAROUND: two methods to overload appropriate Params due to localization issue: + // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 + void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } + void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + +protected: + LLFlatListViewEx(const Params& p); + + /** + * Applies a message for empty list depend on passed argument. + * + * @param items_filtered - if true message for filtered items will be set, otherwise for + * completely empty list. + */ + void updateNoItemsMessage(bool items_filtered); + +private: + std::string mNoFilteredItemsMsg; + std::string mNoItemsMsg; +}; + #endif diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index e672252a50..79c47a1136 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -563,6 +563,7 @@ void LLFloater::handleVisibilityChange ( BOOL new_visibility ) void LLFloater::openFloater(const LLSD& key) { + llinfos << "Opening floater " << getName() << llendl; mKey = key; // in case we need to open ourselves again if (getSoundFlags() != SILENT @@ -603,6 +604,7 @@ void LLFloater::openFloater(const LLSD& key) void LLFloater::closeFloater(bool app_quitting) { + llinfos << "Closing floater " << getName() << llendl; if (app_quitting) { LLFloater::sQuitting = true; @@ -1786,13 +1788,16 @@ void LLFloater::updateTitleButtons() llround((F32)floater_close_box_size * mButtonScale)); } - if(!buttons_rect.isValid()) + // first time here, init 'buttons_rect' + if(1 == button_count) { buttons_rect = btn_rect; } else { - mDragOnLeft ? buttons_rect.mRight + btn_rect.mRight : + // if mDragOnLeft=true then buttons are on top-left side vertically aligned + // title is not displayed in this case, calculating 'buttons_rect' for future use + mDragOnLeft ? buttons_rect.mBottom -= btn_rect.mBottom : buttons_rect.mLeft = btn_rect.mLeft; } mButtons[i]->setRect(btn_rect); diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 66368f979b..7e37600409 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -73,6 +73,7 @@ public: std::string getImageName() const; void setColor(const LLColor4& color) { mColor = color; } + void setImage(LLPointer<LLUIImage> image) { mImagep = image; } private: void setIconImageDrawSize() ; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 65ef53443b..7b8f51ae3c 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -48,122 +48,38 @@ const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; -// local channel for notification history -class LLNotificationHistoryChannel : public LLNotificationChannel +// Local channel for persistent notifications +// Stores only persistent notifications. +// Class users can use connectChanged() to process persistent notifications +// (see LLNotificationStorage for example). +class LLPersistentNotificationChannel : public LLNotificationChannel { - LOG_CLASS(LLNotificationHistoryChannel); + LOG_CLASS(LLPersistentNotificationChannel); public: - LLNotificationHistoryChannel(const std::string& filename) : - LLNotificationChannel("History", "Visible", &historyFilter, LLNotificationComparators::orderByUUID()), - mFileName(filename) + LLPersistentNotificationChannel() : + LLNotificationChannel("Persistent", "Visible", ¬ificationFilter, LLNotificationComparators::orderByUUID()) { - connectChanged(boost::bind(&LLNotificationHistoryChannel::historyHandler, this, _1)); - loadPersistentNotifications(); } private: - bool historyHandler(const LLSD& payload) - { - // we ignore "load" messages, but rewrite the persistence file on any other - std::string sigtype = payload["sigtype"]; - if (sigtype != "load") - { - savePersistentNotifications(); - } - return false; - } - - // The history channel gets all notifications except those that have been cancelled - static bool historyFilter(LLNotificationPtr pNotification) - { - return !pNotification->isCancelled(); - } - void savePersistentNotifications() + // The channel gets all persistent notifications except those that have been canceled + static bool notificationFilter(LLNotificationPtr pNotification) { - /* NOTE: As of 2009-11-09 the reload of notifications on startup does not - work, and has not worked for months. Skip saving notifications until the - read can be fixed, because this hits the disk once per notification and - causes log spam. James - - llinfos << "Saving open notifications to " << mFileName << llendl; + bool handle_notification = false; - llofstream notify_file(mFileName.c_str()); - if (!notify_file.is_open()) - { - llwarns << "Failed to open " << mFileName << llendl; - return; - } - - LLSD output; - output["version"] = NOTIFICATION_PERSIST_VERSION; - LLSD& data = output["data"]; - - for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) - { - if (!LLNotifications::instance().templateExists((*it)->getName())) continue; + handle_notification = pNotification->isPersistent() + && !pNotification->isCancelled(); - // only store notifications flagged as persisting - LLNotificationTemplatePtr templatep = LLNotifications::instance().getTemplate((*it)->getName()); - if (!templatep->mPersist) continue; - - data.append((*it)->asLLSD()); - } - - LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); - formatter->format(output, notify_file, LLSDFormatter::OPTIONS_PRETTY); - */ + return handle_notification; } - void loadPersistentNotifications() - { - llinfos << "Loading open notifications from " << mFileName << llendl; - - llifstream notify_file(mFileName.c_str()); - if (!notify_file.is_open()) - { - llwarns << "Failed to open " << mFileName << llendl; - return; - } - - LLSD input; - LLPointer<LLSDParser> parser = new LLSDXMLParser(); - if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0) - { - llwarns << "Failed to parse open notifications" << llendl; - return; - } - - if (input.isUndefined()) return; - std::string version = input["version"]; - if (version != NOTIFICATION_PERSIST_VERSION) - { - llwarns << "Bad open notifications version: " << version << llendl; - return; - } - LLSD& data = input["data"]; - if (data.isUndefined()) return; - - LLNotifications& instance = LLNotifications::instance(); - for (LLSD::array_const_iterator notification_it = data.beginArray(); - notification_it != data.endArray(); - ++notification_it) - { - instance.add(LLNotificationPtr(new LLNotification(*notification_it))); - } - } - - //virtual void onDelete(LLNotificationPtr pNotification) { - // we want to keep deleted notifications in our log + // we want to keep deleted notifications in our log, otherwise some + // notifications will be lost on exit. mItems.insert(pNotification); - - return; } - -private: - std::string mFileName; }; bool filterIgnoredNotifications(LLNotificationPtr notification) @@ -417,6 +333,10 @@ LLNotification::LLNotification(const LLNotification::Params& p) : mTemporaryResponder = true; } + else if(p.functor.responder.isChosen()) + { + mResponder = p.functor.responder; + } if(p.responder.isProvided()) { @@ -462,6 +382,12 @@ LLSD LLNotification::asLLSD() output["priority"] = (S32)mPriority; output["responseFunctor"] = mResponseFunctorName; output["reusable"] = mIsReusable; + + if(mResponder) + { + output["responder"] = mResponder->asLLSD(); + } + return output; } @@ -571,12 +497,20 @@ void LLNotification::respond(const LLSD& response) // *TODO may remove mRespondedTo and use mResponce.isDefined() in isRespondedTo() mRespondedTo = true; mResponse = response; - // look up the functor - LLNotificationFunctorRegistry::ResponseFunctor functor = - LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); - // and then call it - functor(asLLSD(), response); - + + if(mResponder) + { + mResponder->handleRespond(asLLSD(), response); + } + else + { + // look up the functor + LLNotificationFunctorRegistry::ResponseFunctor functor = + LLNotificationFunctorRegistry::instance().getFunctor(mResponseFunctorName); + // and then call it + functor(asLLSD(), response); + } + if (mTemporaryResponder && !isReusable()) { LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); @@ -621,6 +555,11 @@ void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::Res LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); } +void LLNotification::setResponseFunctor(const LLNotificationResponderPtr& responder) +{ + mResponder = responder; +} + bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const { for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); @@ -1116,12 +1055,9 @@ void LLNotifications::createDefaultChannels() LLNotificationChannel::buildChannel("Visible", "Ignore", &LLNotificationFilters::includeEverything); - // create special history channel - //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" ); - // use ^^^ when done debugging notifications serialization - std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" ); + // create special persistent notification channel // this isn't a leak, don't worry about the empty "new" - new LLNotificationHistoryChannel(notifications_log_file); + new LLPersistentNotificationChannel(); // connect action methods to these channels LLNotifications::instance().getChannel("Expiration")-> diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 1799ca65b7..c942a32512 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -116,8 +116,23 @@ typedef enum e_notification_priority NOTIFICATION_PRIORITY_CRITICAL } ENotificationPriority; +class LLNotificationResponderInterface +{ +public: + LLNotificationResponderInterface(){}; + virtual ~LLNotificationResponderInterface(){}; + + virtual void handleRespond(const LLSD& notification, const LLSD& response) = 0; + + virtual LLSD asLLSD() = 0; + + virtual void fromLLSD(const LLSD& params) = 0; +}; + typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder; +typedef boost::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr; + typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry; typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration; @@ -303,10 +318,12 @@ public: { Alternative<std::string> name; Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function; + Alternative<LLNotificationResponderPtr> responder; Functor() : name("functor_name"), - function("functor") + function("functor"), + responder("responder") {} }; Optional<Functor> functor; @@ -349,12 +366,13 @@ private: bool mIgnored; ENotificationPriority mPriority; LLNotificationFormPtr mForm; - void* mResponderObj; + void* mResponderObj; // TODO - refactor/remove this field bool mIsReusable; - + LLNotificationResponderPtr mResponder; + // a reference to the template LLNotificationTemplatePtr mTemplatep; - + /* We want to be able to store and reload notifications so that they can survive a shutdown/restart of the client. So we can't simply pass in callbacks; @@ -393,6 +411,8 @@ public: void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb); + void setResponseFunctor(const LLNotificationResponderPtr& responder); + typedef enum e_response_template_type { WITHOUT_DEFAULT_BUTTON, @@ -459,7 +479,12 @@ public: { return mTemplatep->mName; } - + + bool isPersistent() const + { + return mTemplatep->mPersist; + } + const LLUUID& id() const { return mId; diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp index 4f55c0507c..b7840d1b59 100644 --- a/indra/llui/llscrollingpanellist.cpp +++ b/indra/llui/llscrollingpanellist.cpp @@ -47,7 +47,12 @@ void LLScrollingPanelList::clearPanels() { deleteAllChildren(); mPanelList.clear(); - reshape( 1, 1, FALSE ); + + LLRect rc = getRect(); + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, 1, 1); + setRect(rc); + + notifySizeChanged(rc.getHeight()); } S32 LLScrollingPanelList::addPanel( LLScrollingPanel* panel ) @@ -67,7 +72,11 @@ S32 LLScrollingPanelList::addPanel( LLScrollingPanel* panel ) max_width = llmax( max_width, childp->getRect().getWidth() ); cur_gap = GAP_BETWEEN_PANELS; } - reshape( max_width, total_height, FALSE ); + LLRect rc = getRect(); + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height); + setRect(rc); + + notifySizeChanged(rc.getHeight()); // Reposition each of the child views S32 cur_y = total_height; @@ -131,7 +140,11 @@ void LLScrollingPanelList::removePanel( U32 panel_index ) max_width = llmax( max_width, childp->getRect().getWidth() ); cur_gap = GAP_BETWEEN_PANELS; } - reshape( max_width, total_height, FALSE ); + LLRect rc = getRect(); + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height); + setRect(rc); + + notifySizeChanged(rc.getHeight()); // Reposition each of the child views S32 cur_y = total_height; @@ -200,3 +213,12 @@ void LLScrollingPanelList::draw() LLUICtrl::draw(); } +void LLScrollingPanelList::notifySizeChanged(S32 height) +{ + LLSD info; + info["action"] = "size_changes"; + info["height"] = height; + notifyParent(info); +} + +// EOF diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index 3abfbcbbe7..5f1996159b 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -61,7 +61,6 @@ public: Params() { name = "scrolling_panel_list"; - follows.flags = FOLLOWS_LEFT | FOLLOWS_BOTTOM; } }; LLScrollingPanelList(const Params& p) @@ -86,6 +85,11 @@ public: private: void updatePanelVisiblilty(); + /** + * Notify parent about size change, makes sense when used inside accordion + */ + void notifySizeChanged(S32 height); + panel_list_t mPanelList; }; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index db0f2bd6e2..94eade06ad 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -282,6 +282,8 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) text_p.border_visible(false); text_p.rect(mItemListRect); text_p.follows.flags(FOLLOWS_ALL); + // word wrap was added accroding to the EXT-6841 + text_p.wrap(true); addChild(LLUICtrlFactory::create<LLTextBox>(text_p)); } diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 80ee5d0984..04958075db 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -63,7 +63,8 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) mCanEditText(p.can_edit_text), mPrecision(p.decimal_digits), mTextEnabledColor(p.text_color()), - mTextDisabledColor(p.text_disabled_color()) + mTextDisabledColor(p.text_disabled_color()), + mLabelWidth(p.label_width) { S32 top = getRect().getHeight(); S32 bottom = 0; @@ -86,6 +87,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p) params.initial_value(p.label()); mLabelBox = LLUICtrlFactory::create<LLTextBox> (params); addChild(mLabelBox); + mLabelFont = params.font(); } if (p.show_text && !p.text_width.isProvided()) @@ -186,9 +188,9 @@ BOOL LLSliderCtrl::setLabelArg( const std::string& key, const LLStringExplicit& if (mLabelBox) { res = mLabelBox->setTextArg(key, text); - if (res && mLabelWidth == 0) + if (res && mLabelFont && mLabelWidth == 0) { - S32 label_width = mFont->getWidth(mLabelBox->getText()); + S32 label_width = mLabelFont->getWidth(mLabelBox->getText()); LLRect rect = mLabelBox->getRect(); S32 prev_right = rect.mRight; rect.mRight = rect.mLeft + label_width; diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index c425849782..482c81a0f4 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -141,6 +141,7 @@ private: void reportInvalidData(); const LLFontGL* mFont; + const LLFontGL* mLabelFont; BOOL mShowText; BOOL mCanEditText; @@ -158,3 +159,4 @@ private: }; #endif // LL_LLSLIDERCTRL_H + diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index e08026eaf4..390ec234d3 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1507,6 +1507,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url)); registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url)); registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url)); + registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url)); registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url)); registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url)); registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url)); diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index a1cae4bb98..4fd62045e8 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -713,7 +713,8 @@ BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { setFocus(TRUE); } - if (!LLTextBase::handleRightMouseDown(x, y, mask)) + // Prefer editor menu if it has selection. See EXT-6806. + if (hasSelection() || !LLTextBase::handleRightMouseDown(x, y, mask)) { if(getShowContextMenu()) { diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index 679db5e39b..2f13a56b42 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -146,3 +146,20 @@ void LLUrlAction::copyLabelToClipboard(std::string url) LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(match.getLabel())); } } + +void LLUrlAction::showProfile(std::string url) +{ + // Get id from 'secondlife:///app/{cmd}/{id}/{action}' + // and show its profile + LLURI uri(url); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + std::string id_str = path_array.get(2).asString(); + if (LLUUID::validate(id_str)) + { + std::string cmd_str = path_array.get(1).asString(); + executeSLURL("secondlife:///app/" + cmd_str + "/" + id_str + "/about"); + } + } +} diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index 4830cf27ef..b96faf1b3f 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -79,6 +79,9 @@ public: /// copy a Url to the clipboard static void copyURLToClipboard(std::string url); + /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile + static void showProfile(std::string url); + /// specify the callbacks to enable this class's functionality static void setOpenURLCallback(void (*cb) (const std::string& url)); static void setOpenURLInternalCallback(void (*cb) (const std::string& url)); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index c38e38c900..20d3e679e6 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -499,6 +499,35 @@ std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLab return LLURI::unescape(label.empty() ? url : label); } +// +// LLUrlEntryObjectIM Describes a Second Life inspector for the object Url, e.g., +// secondlife:///app/objectim/7bcd7864-da6b-e43f-4486-91d28a28d95b?name=Object&owner=3de548e1-57be-cfea-2b78-83ae3ad95998&slurl=Danger!%20Danger!/200/200/30/&groupowned=1 +// +LLUrlEntryObjectIM::LLUrlEntryObjectIM() +{ + mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\?.*", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_objectim.xml"; +} + +std::string LLUrlEntryObjectIM::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + LLURI uri(url); + LLSD query_map = uri.queryMap(); + if (query_map.has("name")) + return query_map["name"]; + return unescapeUrl(url); +} + +std::string LLUrlEntryObjectIM::getLocation(const std::string &url) const +{ + LLURI uri(url); + LLSD query_map = uri.queryMap(); + if (query_map.has("slurl")) + return query_map["slurl"]; + return LLUrlEntryBase::getLocation(url); +} + /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about @@ -716,7 +745,7 @@ std::string LLUrlEntryWorldMap::getLabel(const std::string &url, const LLUrlLabe } const std::string label = LLTrans::getString("SLurlLabelShowOnMap"); - std::string location = path_array[2]; + std::string location = unescapeUrl(path_array[2]); std::string x = (path_parts > 3) ? path_array[3] : "128"; std::string y = (path_parts > 4) ? path_array[4] : "128"; std::string z = (path_parts > 5) ? path_array[5] : "0"; diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 84d0968779..29575d752c 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -201,6 +201,18 @@ public: private: }; +/// +/// LLUrlEntryObjectIM Describes a Second Life inspector for the object Url, e.g., +/// secondlife:///app/objectim/7bcd7864-da6b-e43f-4486-91d28a28d95b?name=Object&owner=3de548e1-57be-cfea-2b78-83ae3ad95998&slurl=Danger!%20Danger!/200/200/30/&groupowned=1 +/// +class LLUrlEntryObjectIM : public LLUrlEntryBase +{ +public: + LLUrlEntryObjectIM(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLocation(const std::string &url) const; +private: +}; /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index faa02e1904..0a70aa586a 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -53,8 +53,10 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryParcel()); registerUrl(new LLUrlEntryTeleport()); registerUrl(new LLUrlEntryWorldMap()); + registerUrl(new LLUrlEntryObjectIM()); registerUrl(new LLUrlEntryPlace()); registerUrl(new LLUrlEntryInventory()); + registerUrl(new LLUrlEntryObjectIM()); //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, //so it should be registered in the end of list registerUrl(new LLUrlEntrySL()); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 781c111474..e67f0ec3fc 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1321,6 +1321,8 @@ void LLView::drawChildren() if (viewp->getVisible() && viewp->getRect().isValid()) { + // check for bad data + llassert_always(viewp->getVisible() == TRUE); // Only draw views that are within the root view localRectToScreen(viewp->getRect(),&screenRect); if ( rootRect.overlaps(screenRect) && LLUI::sDirtyRect.overlaps(screenRect)) |