diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f1994c6a0..46b54481b 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6307,6 +6307,149 @@ This should be as low as possible, but too low may break functionality 0 + RadarColumnMarkWidth + + Comment + Width for radar's mark column + Persist + 1 + Type + S32 + Value + 12 + + RadarColumnPositionWidth + + Comment + Width for radar's position column + Persist + 1 + Type + S32 + Value + 60 + + RadarColumnAltitudeWidth + + Comment + Width for radar's altitude column + Persist + 1 + Type + S32 + Value + 48 + + RadarColumnActivityWidth + + Comment + Width for radar's activity column + Persist + 1 + Type + S32 + Value + 24 + + RadarColumnAgeWidth + + Comment + Width for radar's age column + Persist + 1 + Type + S32 + Value + 45 + + RadarColumnTimeWidth + + Comment + Width for radar's time column + Persist + 1 + Type + S32 + Value + 52 + + RadarColumnMarkHidden + + Comment + Hide radar's mark column + Persist + 1 + Type + Boolean + Value + 0 + + RadarColumnPositionHidden + + Comment + Hide radar's position column + Persist + 1 + Type + Boolean + Value + 0 + + RadarColumnAltitudeHidden + + Comment + Hide radar's altitude column + Persist + 1 + Type + Boolean + Value + 0 + + RadarColumnActivityHidden + + Comment + Hide radar's activity column + Persist + 1 + Type + Boolean + Value + 0 + + RadarColumnAgeHidden + + Comment + Hide radar's age column + Persist + 1 + Type + Boolean + Value + 0 + + RadarColumnTimeHidden + + Comment + Hide radar's time column + Persist + 1 + Type + Boolean + Value + 1 + + RadarColumnClientHidden + + Comment + Hide radar's client column + Persist + 1 + Type + Boolean + Value + 0 + RadarKeepOpen Comment @@ -6373,6 +6516,28 @@ This should be as low as possible, but too low may break functionality Value 1 + RadarAlertAge + + Comment + Whether the radar emits chat alerts for avatars younger than AvatarAgeAlertDays appearing. + Persist + 1 + Type + Boolean + Value + 0 + + AvatarAgeAlertDays + + Comment + Age below which avatars will be made known to you + Persist + 1 + Type + U32 + Value + 3 + RadarChatAlerts Comment diff --git a/indra/newview/llfloateravatarlist.cpp b/indra/newview/llfloateravatarlist.cpp index 887afe476..339b90f3c 100644 --- a/indra/newview/llfloateravatarlist.cpp +++ b/indra/newview/llfloateravatarlist.cpp @@ -53,6 +53,7 @@ #include #include +#include #include "llworld.h" #include "llsdutil.h" @@ -79,6 +80,7 @@ typedef enum e_radar_alert_type ALERT_TYPE_DRAW = 2, ALERT_TYPE_SHOUTRANGE = 4, ALERT_TYPE_CHATRANGE = 8, + ALERT_TYPE_AGE = 16, } ERadarAlertType; void chat_avatar_status(std::string name, LLUUID key, ERadarAlertType type, bool entering) @@ -90,10 +92,12 @@ void chat_avatar_status(std::string name, LLUUID key, ERadarAlertType type, bool static LLCachedControl radar_alert_draw(gSavedSettings, "RadarAlertDraw"); static LLCachedControl radar_alert_shout_range(gSavedSettings, "RadarAlertShoutRange"); static LLCachedControl radar_alert_chat_range(gSavedSettings, "RadarAlertChatRange"); + static LLCachedControl radar_alert_age(gSavedSettings, "RadarAlertAge"); static LLCachedControl radar_chat_keys(gSavedSettings, "RadarChatKeys"); LLFloaterAvatarList* self = LLFloaterAvatarList::getInstance(); LLStringUtil::format_map_t args; + args["[NAME]"] = name; switch(type) { case ALERT_TYPE_SIM: @@ -123,10 +127,21 @@ void chat_avatar_status(std::string name, LLUUID key, ERadarAlertType type, bool args["[RANGE]"] = self->getString("chat_range"); } break; + + case ALERT_TYPE_AGE: + if (radar_alert_age) + { + LLChat chat; + chat.mFromName = name; + chat.mText = name + " " + self->getString("has_triggered_your_avatar_age_alert") + "."; + chat.mURL = llformat("secondlife:///app/agent/%s/about",key.asString().c_str()); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChat(chat); + } + break; } if (args.find("[RANGE]") != args.end()) { - args["[NAME]"] = name; args["[ACTION]"] = self->getString(entering ? "has_entered" : "has_left"); LLChat chat; chat.mText = self->getString("template", args); @@ -142,8 +157,40 @@ LLAvatarListEntry::LLAvatarListEntry(const LLUUID& id, const std::string &name, mUpdateTimer(), mFrame(gFrameCount), mInSimFrame(U32_MAX), mInDrawFrame(U32_MAX), mInChatFrame(U32_MAX), mInShoutFrame(U32_MAX), mActivityType(ACTIVITY_NEW), mActivityTimer(), - mIsInList(false) + mIsInList(false), mAge(-1), mAgeAlert(false), mTime(time(NULL)) { + if (mID.notNull()) + LLAvatarPropertiesProcessor::getInstance()->addObserver(mID, this); +} + +LLAvatarListEntry::~LLAvatarListEntry() +{ + if (mID.notNull()) + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mID, this); +} + +// virtual +void LLAvatarListEntry::processProperties(void* data, EAvatarProcessorType type) +{ + if(type == APT_PROPERTIES) + { + const LLAvatarData* pAvatarData = static_cast(data); + if (pAvatarData && (pAvatarData->avatar_id != LLUUID::null)) + { + //Chalice - Show avatar age in days. + int year, month, day; + sscanf(pAvatarData->born_on.c_str(),"%d/%d/%d",&month,&day,&year); + time_t now = time(NULL); + struct tm * timeinfo; + timeinfo=localtime(&now); + timeinfo->tm_mon = --month; + timeinfo->tm_year = year - 1900; + timeinfo->tm_mday = day; + time_t birth = mktime(timeinfo); + mAge = difftime(now,birth) / (60*60*24); + // If one wanted more information that gets displayed on profiles to be displayed, here would be the place to do it. + } + } } void LLAvatarListEntry::setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange) @@ -354,6 +401,13 @@ BOOL LLFloaterAvatarList::postBuild() getChild("update_rate")->setSelectedIndex(gSavedSettings.getU32("RadarUpdateRate")); getChild("update_rate")->setCommitCallback(boost::bind(&LLFloaterAvatarList::onCommitUpdateRate, this)); + getChild("hide_mark")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + getChild("hide_pos")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + getChild("hide_alt")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + getChild("hide_act")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + getChild("hide_age")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + getChild("hide_time")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + // Get a pointer to the scroll list from the interface mAvatarList = getChild("avatar_list"); mAvatarList->sortByColumn("distance", TRUE); @@ -365,20 +419,69 @@ BOOL LLFloaterAvatarList::postBuild() gIdleCallbacks.addFunction(LLFloaterAvatarList::callbackIdle); - if(gHippoGridManager->getConnectedGrid()->isSecondLife()){ - LLScrollListCtrl* list = getChild("avatar_list"); - list->getColumn(LIST_AVATAR_NAME)->setWidth(0); - list->getColumn(LIST_CLIENT)->setWidth(0); - list->getColumn(LIST_CLIENT)->mDynamicWidth = FALSE; - list->getColumn(LIST_CLIENT)->mRelWidth = 0; - list->getColumn(LIST_AVATAR_NAME)->mDynamicWidth = TRUE; - list->getColumn(LIST_AVATAR_NAME)->mRelWidth = -1; - list->updateLayout(); - } + assessColumns(); + + if(gHippoGridManager->getConnectedGrid()->isSecondLife()) + childSetVisible("hide_client", false); + else + getChild("hide_client")->setCommitCallback(boost::bind(&LLFloaterAvatarList::assessColumns, this)); return TRUE; } +void col_helper(const bool hide, const std::string width_ctrl_name, LLScrollListColumn* col) +{ + // Brief Explanation: + // Check if we want the column hidden, and if it's still showing. If so, hide it, but save its width. + // Otherwise, if we don't want it hidden, but it is, unhide it to the saved width. + // We only store width of columns when hiding here for the purpose of hiding and unhiding. + const int width = col->getWidth(); + + if (hide && width) + { + gSavedSettings.setS32(width_ctrl_name, width); + col->setWidth(0); + } + else if(!hide && !width) + { + llinfos << "We got into the setter!!" << llendl; + col->setWidth(gSavedSettings.getS32(width_ctrl_name)); + } +} + +void LLFloaterAvatarList::assessColumns() +{ + static LLCachedControl hide_mark(gSavedSettings, "RadarColumnMarkHidden"); + col_helper(hide_mark, "RadarColumnMarkWidth", mAvatarList->getColumn(LIST_MARK)); + + static LLCachedControl hide_pos(gSavedSettings, "RadarColumnPositionHidden"); + col_helper(hide_pos, "RadarColumnPositionWidth", mAvatarList->getColumn(LIST_POSITION)); + + static LLCachedControl hide_alt(gSavedSettings, "RadarColumnAltitudeHidden"); + col_helper(hide_alt, "RadarColumnAltitudeWidth", mAvatarList->getColumn(LIST_ALTITUDE)); + + static LLCachedControl hide_act(gSavedSettings, "RadarColumnActivityHidden"); + col_helper(hide_act, "RadarColumnActivityWidth", mAvatarList->getColumn(LIST_ACTIVITY)); + + static LLCachedControl hide_age(gSavedSettings, "RadarColumnAgeHidden"); + col_helper(hide_age, "RadarColumnAgeWidth", mAvatarList->getColumn(LIST_AGE)); + + static LLCachedControl hide_time(gSavedSettings, "RadarColumnTimeHidden"); + col_helper(hide_time, "RadarColumnTimeWidth", mAvatarList->getColumn(LIST_TIME)); + + static LLCachedControl hide_client(gSavedSettings, "RadarColumnClientHidden"); + if (gHippoGridManager->getConnectedGrid()->isSecondLife() || hide_client){ + mAvatarList->getColumn(LIST_AVATAR_NAME)->setWidth(0); + mAvatarList->getColumn(LIST_CLIENT)->setWidth(0); + mAvatarList->getColumn(LIST_CLIENT)->mDynamicWidth = FALSE; + mAvatarList->getColumn(LIST_CLIENT)->mRelWidth = 0; + mAvatarList->getColumn(LIST_AVATAR_NAME)->mDynamicWidth = TRUE; + mAvatarList->getColumn(LIST_AVATAR_NAME)->mRelWidth = -1; + } + + mAvatarList->updateLayout(); +} + void updateParticleActivity(LLDrawable *drawablep) { if (LLFloaterAvatarList::instanceExists()) @@ -716,6 +819,10 @@ void LLFloaterAvatarList::refreshAvatarList() continue; } + //Request properties here, so we'll have them later on when we need them + LLAvatarPropertiesProcessor::getInstance()->addObserver(entry.mID, &entry); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(entry.mID); + element["id"] = av_id; element["columns"][LIST_MARK]["column"] = "marked"; @@ -755,6 +862,7 @@ void LLFloaterAvatarList::refreshAvatarList() static LLCachedControl sRadarTextChatRange(gColors, "RadarTextChatRange"); static LLCachedControl sRadarTextShoutRange(gColors, "RadarTextShoutRange"); static LLCachedControl sRadarTextDrawDist(gColors, "RadarTextDrawDist"); + static LLCachedControl sRadarTextYoung(gColors, "RadarTextYoung"); LLColor4 name_color = sDefaultListText; //Lindens are always more Linden than your friend, make that take precedence @@ -872,28 +980,50 @@ void LLFloaterAvatarList::refreshAvatarList() element["columns"][LIST_ACTIVITY]["type"] = "icon"; std::string activity_icon = ""; + std::string activity_tip = ""; switch(entry.getActivity()) { case LLAvatarListEntry::ACTIVITY_MOVING: - activity_icon = "inv_item_animation.tga"; + { + activity_icon = "inv_item_animation.tga"; + activity_tip = getString("Moving"); + } break; case LLAvatarListEntry::ACTIVITY_GESTURING: - activity_icon = "inv_item_gesture.tga"; + { + activity_icon = "inv_item_gesture.tga"; + activity_tip = getString("Playing a gesture"); + } break; case LLAvatarListEntry::ACTIVITY_SOUND: - activity_icon = "inv_item_sound.tga"; + { + activity_icon = "inv_item_sound.tga"; + activity_tip = getString("Playing a sound"); + } break; case LLAvatarListEntry::ACTIVITY_REZZING: - activity_icon = "ff_edit_theirs.tga"; + { + activity_icon = "ff_edit_theirs.tga"; + activity_tip = getString("Rezzing objects"); + } break; case LLAvatarListEntry::ACTIVITY_PARTICLES: - activity_icon = "particles_scan.tga"; + { + activity_icon = "particles_scan.tga"; + activity_tip = getString("Creating particles"); + } break; case LLAvatarListEntry::ACTIVITY_NEW: - activity_icon = "avatar_new.tga"; + { + activity_icon = "avatar_new.tga"; + activity_tip = getString("Just arrived"); + } break; case LLAvatarListEntry::ACTIVITY_TYPING: - activity_icon = "avatar_typing.tga"; + { + activity_icon = "avatar_typing.tga"; + activity_tip = getString("Typing"); + } break; default: break; @@ -901,6 +1031,40 @@ void LLFloaterAvatarList::refreshAvatarList() element["columns"][LIST_ACTIVITY]["value"] = activity_icon;//icon_image_id; //"icn_active-speakers-dot-lvl0.tga"; //element["columns"][LIST_AVATAR_ACTIVITY]["color"] = icon_color.getValue(); + element["columns"][LIST_ACTIVITY]["tool_tip"] = activity_tip; + + element["columns"][LIST_AGE]["column"] = "age"; + element["columns"][LIST_AGE]["type"] = "text"; + color = sDefaultListText; + std::string age = boost::lexical_cast(entry.mAge); + if (entry.mAge > -1) + { + static LLCachedControl sAvatarAgeAlertDays(gSavedSettings, "AvatarAgeAlertDays"); + if (entry.mAge < sAvatarAgeAlertDays) + { + color = sRadarTextYoung; + if (!entry.mAgeAlert) //Only announce age once per entry. + { + entry.mAgeAlert = true; + chat_avatar_status(entry.getName().c_str(), av_id, ALERT_TYPE_AGE, true); + } + } + } + else + { + age = "?"; + } + element["columns"][LIST_AGE]["value"] = age; + element["columns"][LIST_AGE]["color"] = color.getValue(); + + int dur = difftime(time(NULL), entry.getTime()); + int hours = dur / 360; + int mins = (dur % 360) / 60; + int secs = (dur % 360) % 60; + + element["columns"][LIST_TIME]["column"] = "time"; + element["columns"][LIST_TIME]["type"] = "text"; + element["columns"][LIST_TIME]["value"] = llformat("%d:%02d:%02d", hours, mins, secs); element["columns"][LIST_CLIENT]["column"] = "client"; element["columns"][LIST_CLIENT]["type"] = "text"; diff --git a/indra/newview/llfloateravatarlist.h b/indra/newview/llfloateravatarlist.h index d9fe93581..8aa3d3665 100644 --- a/indra/newview/llfloateravatarlist.h +++ b/indra/newview/llfloateravatarlist.h @@ -11,6 +11,7 @@ // // #include "llavatarname.h" +#include "llavatarpropertiesprocessor.h" #include "llfloater.h" #include "llfloaterreporter.h" #include "lluuid.h" @@ -29,7 +30,8 @@ class LLFloaterAvatarList; * Instances are kept in a map. We keep track of the * frame where the avatar was last seen. */ -class LLAvatarListEntry { +class LLAvatarListEntry : public LLAvatarPropertiesObserver +{ public: @@ -52,6 +54,10 @@ enum ACTIVITY_TYPE * @param position Avatar's current position */ LLAvatarListEntry(const LLUUID& id = LLUUID::null, const std::string &name = "", const LLVector3d &position = LLVector3d::zero); + ~LLAvatarListEntry(); + + // Get properties, such as age and other niceties displayed on profiles. + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); /** * Update world position. @@ -78,6 +84,7 @@ enum ACTIVITY_TYPE * @brief Returns the name of the avatar */ const std::string& getName() const { return mName; } + const time_t& getTime() const { return mTime; } /** * @brief Returns the ID of the avatar @@ -132,11 +139,14 @@ private: LLUUID mID; std::string mName; + time_t mTime; LLVector3d mPosition; LLVector3d mDrawPosition; bool mMarked; bool mFocused; bool mIsInList; + bool mAgeAlert; + int mAge; /** * @brief Timer to keep track of whether avatars are still there @@ -202,6 +212,9 @@ public: static void showInstance(); + // Decides which user-chosen columns to show and hide. + void assessColumns(); + /** * @brief Updates the internal avatar list with the currently present avatars. */ @@ -245,6 +258,8 @@ private: LIST_POSITION, LIST_ALTITUDE, LIST_ACTIVITY, + LIST_AGE, + LIST_TIME, LIST_CLIENT, }; diff --git a/indra/newview/skins/default/colors_base.xml b/indra/newview/skins/default/colors_base.xml index eaed66c4d..651f4c232 100644 --- a/indra/newview/skins/default/colors_base.xml +++ b/indra/newview/skins/default/colors_base.xml @@ -153,6 +153,7 @@ + diff --git a/indra/newview/skins/default/xui/en-us/floater_radar.xml b/indra/newview/skins/default/xui/en-us/floater_radar.xml index 5a2c78cea..8b5117601 100644 --- a/indra/newview/skins/default/xui/en-us/floater_radar.xml +++ b/indra/newview/skins/default/xui/en-us/floater_radar.xml @@ -14,11 +14,13 @@ + + + name="actions_tab_container" tab_position="top" tab_min_width="0" follows="left|right|bottom"> @@ -337,7 +339,33 @@ follows="bottom|left" /> + + + + + Hide columns: + + + + + + + + + Moving + Playing a gesture + Playing a sound + Rezzing objects + Creating particles + Just arrived + Typing + has triggered your avatar age alert [NAME] [ACTION] [RANGE]. has entered diff --git a/indra/newview/skins/gemini/colors.xml b/indra/newview/skins/gemini/colors.xml index 7e5870fc8..331979419 100644 --- a/indra/newview/skins/gemini/colors.xml +++ b/indra/newview/skins/gemini/colors.xml @@ -151,6 +151,7 @@ +