diff options
Diffstat (limited to 'indra/newview/llchiclet.cpp')
-rw-r--r-- | indra/newview/llchiclet.cpp | 941 |
1 files changed, 645 insertions, 296 deletions
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index d8e844d291..f71ea9f8ad 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -32,72 +32,60 @@ #include "llviewerprecompiledheaders.h" // must be first include #include "llchiclet.h" -#include "llfloaterreg.h" -#include "llvoiceclient.h" #include "llagent.h" -#include "lltextbox.h" +#include "llavataractions.h" +#include "llbottomtray.h" +#include "llgroupactions.h" #include "lliconctrl.h" -#include "llvoicecontrolpanel.h" -#include "lloutputmonitorctrl.h" +#include "llimpanel.h" // LLFloaterIMPanel #include "llimview.h" -#include "llbottomtray.h" +#include "llfloatergroupinfo.h" +#include "llmenugl.h" +#include "lloutputmonitorctrl.h" +#include "lltextbox.h" +#include "llvoiceclient.h" +#include "llvoicecontrolpanel.h" + +static const std::string P2P_MENU_NAME = "IMChiclet P2P Menu"; +static const std::string GROUP_MENU_NAME = "IMChiclet Group Menu"; -static const S32 CHICLET_HEIGHT = 25; -static const S32 CHICLET_SPACING = 0; -static const S32 CHICLET_PADDING = 3; -static const S32 AVATAR_WIDTH = 25; -static const S32 SPEAKER_WIDTH = 20; -static const S32 COUNTER_WIDTH = 20; -static const S32 SCROLL_BUTTON_WIDTH = 19; -static const S32 SCROLL_BUTTON_HEIGHT = 20; -static const S32 NOTIFICATION_TEXT_TOP_PAD = 5; - -static LLDefaultWidgetRegistry::Register<LLChicletPanel> t1("chiclet_panel"); -static LLDefaultWidgetRegistry::Register<LLTalkButton> t2("chiclet_talk"); -static LLDefaultWidgetRegistry::Register<LLNotificationChiclet> t3("chiclet_notification"); -static LLDefaultWidgetRegistry::Register<LLChicletPanel> t4("chiclet_panel"); +static LLDefaultChildRegistry::Register<LLChicletPanel> t1("chiclet_panel"); +static LLDefaultChildRegistry::Register<LLTalkButton> t2("chiclet_talk"); +static LLDefaultChildRegistry::Register<LLNotificationChiclet> t3("chiclet_notification"); +static LLDefaultChildRegistry::Register<LLIMChiclet> t4("chiclet_im"); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// LLNotificationChiclet::Params::Params() -: image_unselected("image_unselected") -, image_selected("image_selected") -, image_overlay("image_overlay") +: button("button") +, unread_notifications("unread_notifications") { + button.name("button"); + button.tab_stop(FALSE); + button.label(LLStringUtil::null); + + unread_notifications.name("unread"); + unread_notifications.font(LLFontGL::getFontSansSerif()); + unread_notifications.text_color=(LLColor4::white); + unread_notifications.font_halign(LLFontGL::HCENTER); + unread_notifications.mouse_opaque(FALSE); } LLNotificationChiclet::LLNotificationChiclet(const Params& p) : LLChiclet(p) , mButton(NULL) -, mCounterText(NULL) -{ - LLRect rc(p.rect); - - LLButton::Params button_params; - button_params.name("btn"); - button_params.label(LLStringUtil::null); - button_params.rect(LLRect(0,rc.getHeight(),rc.getWidth(),0)); - button_params.image_overlay(p.image_overlay); - button_params.image_unselected(p.image_unselected); - button_params.image_selected(p.image_selected); - button_params.tab_stop(false); +, mCounterCtrl(NULL) +{ + LLButton::Params button_params = p.button; + button_params.rect(p.rect()); mButton = LLUICtrlFactory::create<LLButton>(button_params); addChild(mButton); - LLTextBox::Params textbox_params; - textbox_params.name("txt"); - textbox_params.rect(LLRect(p.label_left,rc.getHeight(), - rc.getWidth()-p.label_left,0)); - textbox_params.mouse_opaque(false); - textbox_params.v_pad(NOTIFICATION_TEXT_TOP_PAD); - textbox_params.font.style("SansSerif"); - textbox_params.font_halign(LLFontGL::HCENTER); - mCounterText = LLUICtrlFactory::create<LLTextBox>(textbox_params); - addChild(mCounterText); - mCounterText->setColor(LLColor4::white); - mCounterText->setText(LLStringUtil::null); + LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications; + mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params); + addChild(mCounterCtrl); } LLNotificationChiclet::~LLNotificationChiclet() @@ -105,18 +93,15 @@ LLNotificationChiclet::~LLNotificationChiclet() } -LLChiclet* LLNotificationChiclet::create(const Params& p) +void LLNotificationChiclet::setCounter(S32 counter) { - LLChiclet* chiclet = new LLNotificationChiclet(p); - return chiclet; + mCounterCtrl->setCounter(counter); } -void LLNotificationChiclet::setCounter(S32 counter) +void LLNotificationChiclet::setShowCounter(bool show) { - std::stringstream stream; - mCounter = counter; - stream << mCounter; - mCounterText->setText(stream.str()); + LLChiclet::setShowCounter(show); + mCounterCtrl->setVisible(getShowCounter()); } boost::signals2::connection LLNotificationChiclet::setClickCallback( @@ -129,10 +114,16 @@ boost::signals2::connection LLNotificationChiclet::setClickCallback( ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +LLChiclet::Params::Params() + : show_counter("show_counter") +{ + show_counter = true; +} + LLChiclet::LLChiclet(const Params& p) : LLUICtrl(p) -, mCounter(0) -, mShowCounter(true) +, mSessionId(LLUUID::null) +, mShowCounter(p.show_counter) { } @@ -155,47 +146,81 @@ BOOL LLChiclet::handleMouseDown(S32 x, S32 y, MASK mask) return TRUE; } +boost::signals2::connection LLChiclet::setChicletSizeChangedCallback( + const chiclet_size_changed_callback_t& cb) +{ + return mChicletSizeChangedSignal.connect(cb); +} + +void LLChiclet::onChicletSizeChanged() +{ + mChicletSizeChangedSignal(this, getValue()); +} + +LLSD LLChiclet::getValue() const +{ + return LLSD(getSessionId()); +} + +void LLChiclet::setValue(const LLSD& value) +{ + if(value.isUUID()) + setSessionId(value.asUUID()); +} + ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -LLIMChiclet::LLIMChiclet(const LLChiclet::Params& p) +LLIMChiclet::Params::Params() +: avatar_icon("avatar_icon") +, unread_notifications("unread_notifications") +, speaker("speaker") +, show_speaker("show_speaker") +{ + rect(LLRect(0, 25, 45, 0)); + + avatar_icon.name("avatar_icon"); + avatar_icon.rect(LLRect(0, 25, 25, 0)); + + unread_notifications.name("unread"); + unread_notifications.rect(LLRect(25, 25, 45, 0)); + unread_notifications.font(LLFontGL::getFontSansSerif()); + unread_notifications.font_halign(LLFontGL::HCENTER); + unread_notifications.v_pad(5); + unread_notifications.text_color(LLColor4::white); + + speaker.name("speaker"); + speaker.rect(LLRect(45, 25, 65, 0)); + + show_speaker = false; +} + +LLIMChiclet::LLIMChiclet(const Params& p) : LLChiclet(p) -, mAvatar(NULL) -, mCounterText(NULL) -, mSpeaker(NULL) -, mIMSessionId() -, mShowSpeaker(false) -, mSpeakerStatus(SPEAKER_IDLE) -{ - LLAvatarIconCtrl::Params avatar_params; - avatar_params.control_name("avatar"); - avatar_params.draw_tooltip = FALSE; - mAvatar = LLUICtrlFactory::create<LLAvatarIconCtrl>(avatar_params); - - addChild(mAvatar); - - LLTextBox::Params unread_params; - unread_params.font.style("SansSerif"); - unread_params.font_halign(LLFontGL::HCENTER); - unread_params.v_pad(5); - mCounterText = LLUICtrlFactory::create<LLTextBox>(unread_params); - addChild(mCounterText); - mCounterText->setColor(LLColor4::white); +, mAvatarCtrl(NULL) +, mCounterCtrl(NULL) +, mSpeakerCtrl(NULL) +, mShowSpeaker(p.show_speaker) +, mPopupMenu(NULL) +, mDockTongueVisible(false) +{ + LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon; + mAvatarCtrl = LLUICtrlFactory::create<LLChicletAvatarIconCtrl>(avatar_params); + addChild(mAvatarCtrl); + + LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications; + mCounterCtrl = LLUICtrlFactory::create<LLChicletNotificationCounterCtrl>(unread_params); + addChild(mCounterCtrl); + setCounter(getCounter()); + setShowCounter(getShowCounter()); - LLIconCtrl::Params speaker_params; - speaker_params.image( LLUI::getUIImage("icn_voice_ptt-on-lvl2.tga") ); - mSpeaker = LLUICtrlFactory::create<LLIconCtrl>(speaker_params); - addChild(mSpeaker); - mSpeaker->setVisible(getShowSpeaker()); + LLChicletSpeakerCtrl::Params speaker_params = p.speaker; + mSpeakerCtrl = LLUICtrlFactory::create<LLChicletSpeakerCtrl>(speaker_params); + addChild(mSpeakerCtrl); - S32 left = 0; - mAvatar->setRect(LLRect(left,CHICLET_HEIGHT,AVATAR_WIDTH,0)); - left += AVATAR_WIDTH + CHICLET_SPACING; - mCounterText->setRect(LLRect(left,CHICLET_HEIGHT,left + COUNTER_WIDTH,0)); - left += COUNTER_WIDTH + CHICLET_SPACING; - mSpeaker->setRect(LLRect(left,CHICLET_HEIGHT,left + SPEAKER_WIDTH,0)); + setShowSpeaker(getShowSpeaker()); } LLIMChiclet::~LLIMChiclet() @@ -203,43 +228,57 @@ LLIMChiclet::~LLIMChiclet() } -LLChiclet* LLIMChiclet::create(LLSD* imSessionId /* = NULL */) +void LLIMChiclet::setDockTongueVisible(bool visible) { - LLIMChiclet* chiclet = new LLIMChiclet(LLChiclet::Params()); - chiclet->setIMSessionId(imSessionId); - return chiclet; + mDockTongueVisible = visible; } void LLIMChiclet::setCounter(S32 counter) { - mCounter = counter; - std::stringstream stream; - stream << mCounter; - mCounterText->setText(stream.str()); + mCounterCtrl->setCounter(counter); + + if(getShowCounter()) + { + LLRect counter_rect = mCounterCtrl->getRect(); + LLRect required_rect = mCounterCtrl->getRequiredRect(); + bool needs_resize = required_rect.getWidth() != counter_rect.getWidth(); - LLRect rc = mCounterText->getRect(); - rc.mRight = rc.mLeft + calcCounterWidth(); - mCounterText->setRect(rc); + if(needs_resize) + { + counter_rect.mRight = counter_rect.mLeft + required_rect.getWidth(); + mCounterCtrl->reshape(counter_rect.getWidth(), counter_rect.getHeight()); + mCounterCtrl->setRect(counter_rect); + + onChicletSizeChanged(); + } + } } LLRect LLIMChiclet::getRequiredRect() { - LLRect rect(0,CHICLET_HEIGHT,AVATAR_WIDTH,0); + LLRect rect(0, 0, mAvatarCtrl->getRect().getWidth(), 0); if(getShowCounter()) { - rect.mRight += CHICLET_SPACING + calcCounterWidth(); + rect.mRight += mCounterCtrl->getRequiredRect().getWidth(); } if(getShowSpeaker()) { - rect.mRight += CHICLET_SPACING + SPEAKER_WIDTH; + rect.mRight += mSpeakerCtrl->getRect().getWidth(); } return rect; } void LLIMChiclet::setShowCounter(bool show) { + bool needs_resize = getShowCounter() != show; + LLChiclet::setShowCounter(show); - mCounterText->setVisible(getShowCounter()); + mCounterCtrl->setVisible(getShowCounter()); + + if(needs_resize) + { + onChicletSizeChanged(); + } } void LLIMChiclet::setIMSessionName(const std::string& name) @@ -249,63 +288,195 @@ void LLIMChiclet::setIMSessionName(const std::string& name) void LLIMChiclet::setOtherParticipantId(const LLUUID& other_participant_id) { - if (mAvatar) + if (mAvatarCtrl) { - mAvatar->setValue(other_participant_id); + mAvatarCtrl->setValue(other_participant_id); + } +} + +void LLIMChiclet::updateMenuItems() +{ + if(!mPopupMenu) + return; + if(getSessionId().isNull()) + return; + + if(P2P_MENU_NAME == mPopupMenu->getName()) + { + bool is_friend = LLAvatarActions::isFriend(mAvatarCtrl->getAvatarId()); + + mPopupMenu->getChild<LLUICtrl>("Add Friend")->setEnabled(!is_friend); + mPopupMenu->getChild<LLUICtrl>("Remove Friend")->setEnabled(is_friend); } } void LLIMChiclet::setShowSpeaker(bool show) { + bool needs_resize = getShowSpeaker() != show; + mShowSpeaker = show; - mSpeaker->setVisible(getShowSpeaker()); + mSpeakerCtrl->setVisible(getShowSpeaker()); + + if(needs_resize) + { + onChicletSizeChanged(); + } } void LLIMChiclet::draw() { LLUICtrl::draw(); - gl_rect_2d(1, getRect().getHeight(), getRect().getWidth(), 1, LLColor4(0.0f,0.0f,0.0f,1.f), FALSE); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.0f,0.0f,0.0f,1.f), FALSE); + + if (mDockTongueVisible) + { + LLUIImagePtr flyout_tongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); + // was previously AVATAR_WIDTH-16 and CHICLET_HEIGHT-6 + flyout_tongue->draw( getRect().getWidth()-31, getRect().getHeight()-5); + } +} + +BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if(!mPopupMenu) + createPopupMenu(); + + updateMenuItems(); + + if (mPopupMenu) + { + mPopupMenu->arrangeAndClear(); + } + + LLMenuGL::showPopup(this, mPopupMenu, x, y); + + return TRUE; +} + +void LLIMChiclet::createPopupMenu() +{ + if(mPopupMenu) + { + llwarns << "Menu already exists" << llendl; + return; + } + if(getSessionId().isNull()) + return; + + LLFloaterIMPanel*floater = gIMMgr->findFloaterBySession(getSessionId()); + if(!floater) + return; + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("IMChicletMenu.Action", boost::bind(&LLIMChiclet::onMenuItemClicked, this, _2)); + + switch(floater->getDialogType()) + { + case IM_SESSION_GROUP_START: + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> + ("menu_imchiclet_group.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + break; + case IM_NOTHING_SPECIAL: + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> + ("menu_imchiclet_p2p.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + break; + default: + llwarns << "Unexpected dialog type" << llendl; + break; + } } -S32 LLIMChiclet::calcCounterWidth() +void LLIMChiclet::onMenuItemClicked(const LLSD& user_data) { - S32 font_width = mCounterText->getFont()->getWidth("0"); - S32 text_size = mCounterText->getText().size(); + std::string level = user_data.asString(); + LLUUID other_participant_id = mAvatarCtrl->getAvatarId(); - return llmax(font_width * text_size, COUNTER_WIDTH); + if("profile" == level) + { + LLAvatarActions::showProfile(other_participant_id); + } + else if("im" == level) + { + LLAvatarActions::startIM(other_participant_id); + } + else if("add" == level) + { + std::string name; + gCacheName->getFullName(other_participant_id,name); + LLAvatarActions::requestFriendshipDialog(other_participant_id,name); + } + else if("remove" == level) + { + LLAvatarActions::removeFriendDialog(other_participant_id); + } + else if("group chat" == level) + { + LLGroupActions::startChat(other_participant_id); + } + else if("info" == level) + { + LLFloaterGroupInfo::showFromUUID(other_participant_id); + } } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +LLChicletPanel::Params::Params() +: chiclet_padding("chiclet_padding") +, scrolling_offset("scrolling_offset") +, left_scroll_button("left_scroll_button") +, right_scroll_button("right_scroll_button") +, min_width("min_width") +{ + chiclet_padding = 3; + scrolling_offset = 40; + min_width = 70; + + LLRect scroll_button_rect(0, 25, 19, 5); + + left_scroll_button.name("left_scroll"); + left_scroll_button.label(LLStringUtil::null); + left_scroll_button.rect(scroll_button_rect); + left_scroll_button.tab_stop(false); + left_scroll_button.image_selected(LLUI::getUIImage("bottom_tray_scroll_left.tga")); + left_scroll_button.image_unselected(LLUI::getUIImage("bottom_tray_scroll_left.tga")); + left_scroll_button.image_hover_selected(LLUI::getUIImage("bottom_tray_scroll_left.tga")); + + right_scroll_button.name("right_scroll"); + right_scroll_button.label(LLStringUtil::null); + right_scroll_button.rect(scroll_button_rect); + right_scroll_button.tab_stop(false); + right_scroll_button.image_selected(LLUI::getUIImage("bottom_tray_scroll_right.tga")); + right_scroll_button.image_unselected(LLUI::getUIImage("bottom_tray_scroll_right.tga")); + right_scroll_button.image_hover_selected(LLUI::getUIImage("bottom_tray_scroll_right.tga")); +}; + LLChicletPanel::LLChicletPanel(const Params&p) : LLPanel(p) -, mLeftScroll(NULL) -, mRightScroll(NULL) -, mFirstToShow(0) -{ - LLButton::Params params; - - params.name("scroll_left"); - params.label(LLStringUtil::null); - params.tab_stop(false); - params.image_selected(LLUI::getUIImage("scroll_left.tga")); - params.image_unselected(LLUI::getUIImage("scroll_left.tga")); - params.image_hover_selected(LLUI::getUIImage("scroll_left.tga")); - mLeftScroll = LLUICtrlFactory::create<LLButton>(params); - addChild(mLeftScroll); - mLeftScroll->setClickedCallback(boost::bind(&LLChicletPanel::onLeftScrollClick,this)); - mLeftScroll->setEnabled(false); - - params.name("scroll_right"); - params.image_selected(LLUI::getUIImage("scroll_right.tga")); - params.image_unselected(LLUI::getUIImage("scroll_right.tga")); - params.image_hover_selected(LLUI::getUIImage("scroll_right.tga")); - mRightScroll = LLUICtrlFactory::create<LLButton>(params); - addChild(mRightScroll); - mRightScroll->setClickedCallback(boost::bind(&LLChicletPanel::onRightScrollClick,this)); - mRightScroll->setEnabled(false); +, mScrollArea(NULL) +, mLeftScrollButton(NULL) +, mRightScrollButton(NULL) +, mChicletPadding(p.chiclet_padding) +, mScrollingOffset(p.scrolling_offset) +, mMinWidth(p.min_width) +, mShowControls(true) +{ + LLButton::Params scroll_button_params = p.left_scroll_button; + + mLeftScrollButton = LLUICtrlFactory::create<LLButton>(scroll_button_params); + addChild(mLeftScrollButton); + + mLeftScrollButton->setClickedCallback(boost::bind(&LLChicletPanel::onLeftScrollClick,this)); + mLeftScrollButton->setEnabled(false); + + scroll_button_params = p.right_scroll_button; + mRightScrollButton = LLUICtrlFactory::create<LLButton>(scroll_button_params); + addChild(mRightScrollButton); + + mRightScrollButton->setClickedCallback(boost::bind(&LLChicletPanel::onRightScrollClick,this)); + mRightScrollButton->setEnabled(false); LLPanel::Params panel_params; mScrollArea = LLUICtrlFactory::create<LLPanel>(panel_params,this); @@ -317,44 +488,55 @@ LLChicletPanel::~LLChicletPanel() } -LLChicletPanel* LLChicletPanel::create() -{ - LLChicletPanel* panel = new LLChicletPanel(LLChicletPanel::Params()); - return panel; +void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){ + + LLUUID session_id = data["session_id"].asUUID(); + LLChiclet* chiclet = panel->findChiclet<LLChiclet>(session_id); + + if (chiclet) + { + chiclet->setCounter(data["num_unread"].asInteger()); + } + else + { + llwarns << "Unable to set counter for chiclet " << session_id << llendl; + } } + BOOL LLChicletPanel::postBuild() { LLPanel::postBuild(); + LLIMModel::instance().addChangedCallback(boost::bind(im_chiclet_callback, this, _1)); return TRUE; } -LLChiclet* LLChicletPanel::createChiclet(LLSD* imSessionId, S32 pos) +bool LLChicletPanel::addChiclet(LLChiclet* chiclet, S32 index) { - LLChiclet* chiclet = LLIMChiclet::create(imSessionId); - if(!chiclet) - { - assert(false); - return NULL; - } - - if(!addChiclet(chiclet, pos)) + if(mScrollArea->addChild(chiclet)) { - assert(false); - return NULL; - } + S32 offset = 0; + // Do not scroll chiclets if chiclets are scrolled right and new + // chiclet is added to the beginning of the list + if(canScrollLeft()) + { + offset = - (chiclet->getRequiredRect().getWidth() + getChicletPadding()); + if(0 == index) + { + offset += getChiclet(0)->getRect().mLeft; + } + } - return chiclet; -} + mChicletList.insert(mChicletList.begin() + index, chiclet); -bool LLChicletPanel::addChiclet(LLChiclet* chiclet, S32 pos) -{ - if(mScrollArea->addChild(chiclet)) - { - mChicletList.insert(mChicletList.begin() + pos, chiclet); + getChiclet(0)->translate(offset, 0); chiclet->setLeftButtonClickCallback(boost::bind(&LLChicletPanel::onChicletClick, this, _1, _2)); + chiclet->setChicletSizeChangedCallback(boost::bind(&LLChicletPanel::onChicletSizeChanged, this, _1, index)); + + arrange(); + showScrollButtonsIfNeeded(); return true; } @@ -362,57 +544,65 @@ bool LLChicletPanel::addChiclet(LLChiclet* chiclet, S32 pos) return false; } -void LLChicletPanel::onChicletClick(LLUICtrl*ctrl,const LLSD¶m) +void LLChicletPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param) { - LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(ctrl); - if (chiclet) + S32 chiclet_width = ctrl->getRect().getWidth(); + S32 chiclet_new_width = ctrl->getRequiredRect().getWidth(); + + if(chiclet_new_width == chiclet_width) { - LLFloaterReg::showInstance("communicate", chiclet->getIMSessionId().asUUID()); + return; } - mCommitSignal(ctrl,param); -} + LLRect chiclet_rect = ctrl->getRect(); + chiclet_rect.mRight = chiclet_rect.mLeft + chiclet_new_width; -LLChiclet* LLChicletPanel::findIMChiclet(LLSD* imSessionId) -{ - chiclet_list_t::const_iterator it = mChicletList.begin(); - for( ; mChicletList.end() != it; ++it) - { - LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it); - if(!chiclet) - { - continue; - } + ctrl->setRect(chiclet_rect); - if(chiclet->getIMSessionId().asUUID() == imSessionId->asUUID()) - { - return chiclet; - } - } - return NULL; + S32 offset = chiclet_new_width - chiclet_width; + S32 index = getChicletIndex(ctrl); + + shiftChiclets(offset, index + 1); + trimChiclets(); + showScrollButtonsIfNeeded(); } -LLChiclet* LLChicletPanel::getChiclet(S32 pos) +void LLChicletPanel::onChicletClick(LLUICtrl*ctrl,const LLSD¶m) { - return mChicletList.at(pos); + mCommitSignal(ctrl,param); } void LLChicletPanel::removeChiclet(chiclet_list_t::iterator it) { mScrollArea->removeChild(*it); - delete *it; mChicletList.erase(it); - mLeftScroll->setEnabled(canScrollLeft()); - mRightScroll->setEnabled(canScrollRight()); + + arrange(); + trimChiclets(); + showScrollButtonsIfNeeded(); } -void LLChicletPanel::removeChiclet(S32 pos) +void LLChicletPanel::removeChiclet(S32 index) { - if(0 > pos || getChicletCount() >= pos) + if(index >= 0 && index < getChicletCount()) { - return; + removeChiclet(mChicletList.begin() + index); + } +} + +S32 LLChicletPanel::getChicletIndex(const LLChiclet* chiclet) +{ + if(mChicletList.empty()) + return -1; + + S32 size = getChicletCount(); + for(int n = 0; n < size; ++n) + { + if(chiclet == mChicletList[n]) + return n; } - removeChiclet(mChicletList.begin() + pos); + + return -1; } void LLChicletPanel::removeChiclet(LLChiclet*chiclet) @@ -429,18 +619,14 @@ void LLChicletPanel::removeChiclet(LLChiclet*chiclet) } } -void LLChicletPanel::removeIMChiclet(LLSD* imSessionId) +void LLChicletPanel::removeChiclet(const LLUUID& im_session_id) { chiclet_list_t::iterator it = mChicletList.begin(); for( ; mChicletList.end() != it; ++it) { LLIMChiclet* chiclet = dynamic_cast<LLIMChiclet*>(*it); - if(!chiclet) - { - continue; - } - if(chiclet->getIMSessionId().asUUID() == imSessionId->asUUID()) + if(chiclet->getSessionId() == im_session_id) { removeChiclet(it); return; @@ -450,54 +636,104 @@ void LLChicletPanel::removeIMChiclet(LLSD* imSessionId) void LLChicletPanel::removeAll() { - mScrollArea->deleteAllChildren(); + S32 size = getChicletCount(); + for(S32 n = 0; n < size; ++n) + { + mScrollArea->removeChild(mChicletList[n]); + } mChicletList.erase(mChicletList.begin(), mChicletList.end()); - mLeftScroll->setEnabled(false); - mRightScroll->setEnabled(false); + + showScrollButtonsIfNeeded(); } void LLChicletPanel::reshape(S32 width, S32 height, BOOL called_from_parent ) { LLPanel::reshape(width,height,called_from_parent); - mLeftScroll->setRect(LLRect(0,CHICLET_HEIGHT,SCROLL_BUTTON_WIDTH, - CHICLET_HEIGHT - SCROLL_BUTTON_HEIGHT)); - mRightScroll->setRect(LLRect(getRect().getWidth()-SCROLL_BUTTON_WIDTH,CHICLET_HEIGHT, - getRect().getWidth(),CHICLET_HEIGHT - SCROLL_BUTTON_HEIGHT)); + static const S32 SCROLL_BUTTON_PAD = 5; - mScrollArea->setRect(LLRect(SCROLL_BUTTON_WIDTH + 5,CHICLET_HEIGHT + 1, - getRect().getWidth() - SCROLL_BUTTON_WIDTH - 5, 0)); + LLRect scroll_button_rect = mLeftScrollButton->getRect(); + mLeftScrollButton->setRect(LLRect(0,height,scroll_button_rect.getWidth(), + height - scroll_button_rect.getHeight())); + scroll_button_rect = mRightScrollButton->getRect(); + mRightScrollButton->setRect(LLRect(width - scroll_button_rect.getWidth(),height, + width, height - scroll_button_rect.getHeight())); - arrange(); + mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + SCROLL_BUTTON_PAD, + height + 7, width - scroll_button_rect.getWidth() - SCROLL_BUTTON_PAD, 0)); + + mShowControls = width > mMinWidth; + mScrollArea->setVisible(mShowControls); + + trimChiclets(); + + showScrollButtonsIfNeeded(); } void LLChicletPanel::arrange() { - S32 left = 0; - S32 size = getChicletCount(); + if(mChicletList.empty()) + return; - for( int n = mFirstToShow; n < size; ++n) + S32 chiclet_left = getChiclet(0)->getRect().mLeft; + + S32 size = getChicletCount(); + for( int n = 0; n < size; ++n) { LLChiclet* chiclet = getChiclet(n); + S32 chiclet_width = chiclet->getRequiredRect().getWidth(); - LLRect rc(left, CHICLET_HEIGHT, left + chiclet_width, 0); + LLRect rect = chiclet->getRect(); + rect.set(chiclet_left, rect.mTop, chiclet_left + chiclet_width, rect.mBottom); - chiclet->setRect(rc); - chiclet->reshape(rc.getWidth(),rc.getHeight()); + chiclet->setRect(rect); - left += chiclet_width + CHICLET_PADDING; + chiclet_left += chiclet_width + getChicletPadding(); } +} - mLeftScroll->setEnabled(canScrollLeft()); - mRightScroll->setEnabled(canScrollRight()); +void LLChicletPanel::trimChiclets() +{ + // trim right + if(canScrollLeft() && !canScrollRight()) + { + S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight; + S32 scroll_width = mScrollArea->getRect().getWidth(); + if(last_chiclet_right < scroll_width) + { + shiftChiclets(scroll_width - last_chiclet_right); + } + } + + // trim left + if(!mChicletList.empty()) + { + LLRect first_chiclet_rect = getChiclet(0)->getRect(); + if(first_chiclet_rect.mLeft > 0) + { + shiftChiclets( - first_chiclet_rect.mLeft); + } + } } -void LLChicletPanel::draw() +void LLChicletPanel::showScrollButtonsIfNeeded() { - //gl_rect_2d(0,getRect().getHeight(),getRect().getWidth(),0,LLColor4(0.f,1.f,1.f,1.f),TRUE); + bool can_scroll_left = canScrollLeft(); + bool can_scroll_right = canScrollRight(); + + mLeftScrollButton->setEnabled(can_scroll_left); + mRightScrollButton->setEnabled(can_scroll_right); + + bool show_scroll_buttons = (can_scroll_left || can_scroll_right) && mShowControls; + mLeftScrollButton->setVisible(show_scroll_buttons); + mRightScrollButton->setVisible(show_scroll_buttons); +} + +void LLChicletPanel::draw() +{ child_list_const_iter_t it = getChildList()->begin(); for( ; getChildList()->end() != it; ++it) { @@ -516,38 +752,39 @@ void LLChicletPanel::draw() bool LLChicletPanel::canScrollRight() { - S32 width = 0; - LLRect visible_rect = mScrollArea->getRect(); + if(mChicletList.empty()) + return false; + + S32 scroll_width = mScrollArea->getRect().getWidth(); + S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight; + + if(last_chiclet_right > scroll_width) + return true; - chiclet_list_t::const_iterator it = mChicletList.begin() + mFirstToShow; - for(;mChicletList.end() != it; ++it) - { - LLChiclet* chiclet = *it; - width += chiclet->getRect().getWidth() + CHICLET_PADDING; - if(width > visible_rect.getWidth()) - return true; - } return false; } bool LLChicletPanel::canScrollLeft() { - return mFirstToShow > 0; + if(mChicletList.empty()) + return false; + + return getChiclet(0)->getRect().mLeft < 0; } -void LLChicletPanel::scroll(ScrollDirection direction) +void LLChicletPanel::scroll(S32 offset) { - S32 elem = 0; - if(SCROLL_LEFT == direction) - elem = mFirstToShow; - else if(SCROLL_RIGHT) - elem = mFirstToShow - 1; + shiftChiclets(offset); +} - S32 offset = mChicletList[elem]->getRect().getWidth() + - CHICLET_PADDING; - offset *= direction; +void LLChicletPanel::shiftChiclets(S32 offset, S32 start_index /* = 0 */) +{ + if(start_index < 0 || start_index >= getChicletCount()) + { + return; + } - chiclet_list_t::const_iterator it = mChicletList.begin(); + chiclet_list_t::const_iterator it = mChicletList.begin() + start_index; for(;mChicletList.end() != it; ++it) { LLChiclet* chiclet = *it; @@ -559,10 +796,18 @@ void LLChicletPanel::scrollLeft() { if(canScrollLeft()) { - --mFirstToShow; - scroll(SCROLL_LEFT); - mLeftScroll->setEnabled(canScrollLeft()); - mRightScroll->setEnabled(canScrollRight()); + S32 offset = getScrollingOffset(); + LLRect first_chiclet_rect = getChiclet(0)->getRect(); + + // shift chiclets in case first chiclet is partially visible + if(first_chiclet_rect.mLeft < 0 && first_chiclet_rect.mRight > 0) + { + offset = llabs(first_chiclet_rect.mLeft); + } + + scroll(offset); + + showScrollButtonsIfNeeded(); } } @@ -570,10 +815,20 @@ void LLChicletPanel::scrollRight() { if(canScrollRight()) { - ++mFirstToShow; - scroll(SCROLL_RIGHT); - mLeftScroll->setEnabled(canScrollLeft()); - mRightScroll->setEnabled(canScrollRight()); + S32 offset = - getScrollingOffset(); + + S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight; + S32 scroll_rect_width = mScrollArea->getRect().getWidth(); + // if after scrolling, the last chiclet will not be aligned to + // scroll area right side - align it. + if( last_chiclet_right + offset < scroll_rect_width ) + { + offset = scroll_rect_width - last_chiclet_right; + } + + scroll(offset); + + showScrollButtonsIfNeeded(); } } @@ -587,7 +842,7 @@ void LLChicletPanel::onRightScrollClick() scrollRight(); } -boost::signals2::connection LLChicletPanel::setChicletClickCallback( +boost::signals2::connection LLChicletPanel::setChicletClickedCallback( const commit_callback_t& cb) { return mCommitSignal.connect(cb); @@ -606,62 +861,87 @@ BOOL LLChicletPanel::handleScrollWheel(S32 x, S32 y, S32 clicks) return TRUE; } -LLTalkButton::LLTalkButton(const LLUICtrl::Params& p) +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLTalkButton::Params::Params() + : speak_button("speak_button") + , show_button("show_button") + , monitor("monitor") +{ + speak_button.name("left"); + speak_button.label("Speak"); + speak_button.label_selected("Speak"); + speak_button.font(LLFontGL::getFontSansSerifSmall()); + speak_button.tab_stop(false); + speak_button.is_toggle(true); + speak_button.picture_style(true); + speak_button.image_selected(LLUI::getUIImage("SegmentedBtn_Left_Selected")); + speak_button.image_unselected(LLUI::getUIImage("SegmentedBtn_Left_Off")); + + show_button.name("right"); + show_button.label(LLStringUtil::null); + show_button.rect(LLRect(0, 0, 20, 0)); + show_button.tab_stop(false); + show_button.is_toggle(true); + show_button.picture_style(true); + show_button.image_selected(LLUI::getUIImage("ComboButton_Selected")); + show_button.image_unselected(LLUI::getUIImage("ComboButton_Off")); + + monitor.name("monitor"); + monitor.rect(LLRect(0, 10, 16, 0)); +} + +LLTalkButton::LLTalkButton(const Params& p) : LLUICtrl(p) +, mPrivateCallPanel(NULL) +, mOutputMonitor(NULL) +, mSpeakBtn(NULL) +, mShowBtn(NULL) { - static S32 DROPDOWN_BTN_WIDTH = 20; - - LLRect rc(p.rect); - - LLButton::Params speak_params; - speak_params.name("left"); - speak_params.rect(LLRect(0,rc.getHeight(),rc.getWidth()-DROPDOWN_BTN_WIDTH,0)); - speak_params.label("Speak"); - speak_params.label_selected("Speak"); - speak_params.font(LLFontGL::getFontSansSerifSmall()); - speak_params.label_color(LLColor4::black); - speak_params.label_color_selected(LLColor4::black); - speak_params.tab_stop(false); - speak_params.is_toggle(true); - speak_params.picture_style(true); - speak_params.image_selected(LLUI::getUIImage("flyout_btn_left_selected.tga")); - speak_params.image_unselected(LLUI::getUIImage("flyout_btn_left.tga")); + LLRect rect = p.rect(); + LLRect speak_rect(0, rect.getHeight(), rect.getWidth(), 0); + LLRect show_rect = p.show_button.rect(); + show_rect.set(0, rect.getHeight(), show_rect.getWidth(), 0); + + speak_rect.mRight -= show_rect.getWidth(); + show_rect.mLeft = speak_rect.getWidth(); + show_rect.mRight = rect.getWidth(); + + LLButton::Params speak_params = p.speak_button; + speak_params.rect(speak_rect); mSpeakBtn = LLUICtrlFactory::create<LLButton>(speak_params); addChild(mSpeakBtn); mSpeakBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_SpeakBtn, this)); - mSpeakBtn->setToggleState(false); - - LLButton::Params show_params; - show_params.name("right"); - show_params.rect(LLRect(rc.getWidth()-DROPDOWN_BTN_WIDTH,rc.getHeight(),rc.getWidth(),0)); - show_params.label(""); - show_params.tab_stop(false); - show_params.is_toggle(true); - show_params.picture_style(true); - show_params.image_selected(LLUI::getUIImage("show_btn_selected.tga")); - show_params.image_unselected(LLUI::getUIImage("show_btn.tga")); + mSpeakBtn->setToggleState(FALSE); + + LLButton::Params show_params = p.show_button; + show_params.rect(show_rect); mShowBtn = LLUICtrlFactory::create<LLButton>(show_params); addChild(mShowBtn); mShowBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_ShowBtn, this)); - mShowBtn->setToggleState(false); - - mSpeakBtn->setToggleState(FALSE); mShowBtn->setToggleState(FALSE); - rc = mSpeakBtn->getRect(); + static const S32 MONITOR_RIGHT_PAD = 2; - LLOutputMonitorCtrl::Params monitor_param; - monitor_param.name("monitor"); - monitor_param.draw_border(false); - monitor_param.rect(LLRect(rc.getWidth()-20,18,rc.getWidth()-3,2)); - monitor_param.visible(true); - mOutputMonitor = LLUICtrlFactory::create<LLOutputMonitorCtrl>(monitor_param); + LLRect monitor_rect = p.monitor.rect(); + S32 monitor_height = monitor_rect.getHeight(); + monitor_rect.mLeft = speak_rect.getWidth() - monitor_rect.getWidth() - MONITOR_RIGHT_PAD; + monitor_rect.mRight = speak_rect.getWidth() - MONITOR_RIGHT_PAD; + monitor_rect.mBottom = (rect.getHeight() / 2) - (monitor_height / 2); + monitor_rect.mTop = monitor_rect.mBottom + monitor_height; + LLOutputMonitorCtrl::Params monitor_params = p.monitor; + monitor_params.draw_border(false); + monitor_params.rect(monitor_rect); + mOutputMonitor = LLUICtrlFactory::create<LLOutputMonitorCtrl>(monitor_params); mSpeakBtn->addChild(mOutputMonitor); - mPrivateCallPanel = NULL; + // never show "muted" because you can't mute yourself + mOutputMonitor->setIsMuted(false); } LLTalkButton::~LLTalkButton() @@ -670,19 +950,22 @@ LLTalkButton::~LLTalkButton() void LLTalkButton::draw() { - if(mSpeakBtn->getToggleState()) - { - mOutputMonitor->setPower(gVoiceClient->getCurrentPower(gAgent.getID())); - } + // Always provide speaking feedback. User can trigger speaking + // with keyboard or middle-mouse shortcut. + mOutputMonitor->setPower(gVoiceClient->getCurrentPower(gAgent.getID())); LLUICtrl::draw(); } +void LLTalkButton::setSpeakBtnToggleState(bool state) +{ + mSpeakBtn->setToggleState(state); +} + void LLTalkButton::onClick_SpeakBtn() { bool speaking = mSpeakBtn->getToggleState(); gVoiceClient->setUserPTTState(speaking); - mOutputMonitor->setIsMuted(!speaking); } void LLTalkButton::onClick_ShowBtn() @@ -704,8 +987,7 @@ void LLTalkButton::onClick_ShowBtn() mPrivateCallPanel = new LLVoiceControlPanel; getRootView()->addChild(mPrivateCallPanel); - y = LLBottomTray::getInstance()->getRect().getHeight() - + mPrivateCallPanel->getRect().getHeight(); + y = LLBottomTray::getInstance()->getRect().getHeight() + mPrivateCallPanel->getRect().getHeight(); LLRect rect; rect.setLeftTopAndSize(x, y, mPrivateCallPanel->getRect().getWidth(), mPrivateCallPanel->getRect().getHeight()); @@ -723,3 +1005,70 @@ void LLTalkButton::onClick_ShowBtn() mShowBtn->setToggleState(TRUE); } + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletNotificationCounterCtrl::LLChicletNotificationCounterCtrl(const Params& p) + : LLTextBox(p) + , mCounter(0) + , mInitialWidth(0) +{ + mInitialWidth = getRect().getWidth(); +} + +void LLChicletNotificationCounterCtrl::setCounter(S32 counter) +{ + mCounter = counter; + + std::stringstream stream; + stream << getCounter(); + if(mCounter != 0) + { + setText(stream.str()); + } + else + { + setText(std::string("")); + } +} + +LLRect LLChicletNotificationCounterCtrl::getRequiredRect() +{ + LLRect rc; + S32 text_width = getFont()->getWidth(getText()); + + rc.mRight = rc.mLeft + llmax(text_width, mInitialWidth); + + return rc; +} + +void LLChicletNotificationCounterCtrl::setValue(const LLSD& value) +{ + if(value.isInteger()) + setCounter(value.asInteger()); +} + +LLSD LLChicletNotificationCounterCtrl::getValue() const +{ + return LLSD(getCounter()); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletAvatarIconCtrl::LLChicletAvatarIconCtrl(const Params& p) + : LLAvatarIconCtrl(p) +{ +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p) + : LLIconCtrl(p) +{ +} |