From fda3891887c55a3ebc76184f076babefbc5e38c6 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 16 Apr 2013 12:08:35 +0200 Subject: [PATCH] FIRE-596: Make the radar a standalone floater --- indra/newview/CMakeLists.txt | 6 + indra/newview/app_settings/commands.xml | 10 + indra/newview/chatbar_as_cmdline.cpp | 14 +- indra/newview/fsfloaterradar.cpp | 473 ++++++ indra/newview/fsfloaterradar.h | 98 ++ indra/newview/fslslbridgerequest.cpp | 8 +- indra/newview/fsradar.cpp | 1053 ++++++++++++ indra/newview/fsradar.h | 143 ++ indra/newview/fsradarmenu.cpp | 250 +++ indra/newview/fsradarmenu.h | 55 + indra/newview/fsslurlcommand.cpp | 15 +- indra/newview/llnetmap.cpp | 18 +- indra/newview/llpanelpeople.cpp | 1437 ++++------------- indra/newview/llpanelpeople.h | 90 +- indra/newview/llpanelpeoplemenus.cpp | 66 +- indra/newview/llpanelpeoplemenus.h | 2 - indra/newview/llstartup.cpp | 8 +- indra/newview/llviewerfloaterreg.cpp | 2 + indra/newview/llviewermessage.cpp | 7 +- indra/newview/rlvui.cpp | 16 +- .../ansastorm/xui/en/floater_fs_radar.xml | 342 ++++ .../skins/ansastorm/xui/en/panel_people.xml | 27 +- .../skins/default/textures/textures.xml | 1 + .../skins/default/xui/de/floater_fs_radar.xml | 52 + .../skins/default/xui/de/menu_fs_radar.xml | 26 + .../default/xui/de/menu_fs_radar_gear.xml | 25 + .../xui/de/menu_fs_radar_multiselect.xml | 17 + .../default/xui/de/menu_people_nearby.xml | 16 +- .../xui/de/menu_people_nearby_multiselect.xml | 7 - .../skins/default/xui/de/menu_viewer.xml | 1 + .../newview/skins/default/xui/de/strings.xml | 33 + .../skins/default/xui/en/floater_fs_radar.xml | 341 ++++ .../skins/default/xui/en/menu_fs_radar.xml | 187 +++ .../default/xui/en/menu_fs_radar_gear.xml | 202 +++ .../xui/en/menu_fs_radar_multiselect.xml | 121 ++ .../default/xui/en/menu_people_nearby.xml | 113 +- .../xui/en/menu_people_nearby_multiselect.xml | 55 - .../skins/default/xui/en/menu_viewer.xml | 11 + .../skins/default/xui/en/panel_people.xml | 27 +- .../newview/skins/default/xui/en/strings.xml | 12 + .../skins/metaharper/xui/en/panel_people.xml | 27 +- .../skins/vintage/xui/en/panel_people.xml | 26 +- 42 files changed, 3851 insertions(+), 1589 deletions(-) create mode 100644 indra/newview/fsfloaterradar.cpp create mode 100644 indra/newview/fsfloaterradar.h create mode 100644 indra/newview/fsradar.cpp create mode 100644 indra/newview/fsradar.h create mode 100644 indra/newview/fsradarmenu.cpp create mode 100644 indra/newview/fsradarmenu.h create mode 100644 indra/newview/skins/ansastorm/xui/en/floater_fs_radar.xml create mode 100644 indra/newview/skins/default/xui/de/floater_fs_radar.xml create mode 100644 indra/newview/skins/default/xui/de/menu_fs_radar.xml create mode 100644 indra/newview/skins/default/xui/de/menu_fs_radar_gear.xml create mode 100644 indra/newview/skins/default/xui/de/menu_fs_radar_multiselect.xml create mode 100644 indra/newview/skins/default/xui/en/floater_fs_radar.xml create mode 100644 indra/newview/skins/default/xui/en/menu_fs_radar.xml create mode 100644 indra/newview/skins/default/xui/en/menu_fs_radar_gear.xml create mode 100644 indra/newview/skins/default/xui/en/menu_fs_radar_multiselect.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7577ff8d24..6cbe3646ba 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -135,6 +135,7 @@ set(viewer_SOURCE_FILES fsfloaterplacedetails.cpp fsfloaterposestand.cpp fsfloaterprofile.cpp + fsfloaterradar.cpp fsfloatersearch.cpp fsfloaterteleporthistory.cpp fsfloatervoicecontrols.cpp @@ -157,7 +158,9 @@ set(viewer_SOURCE_FILES fspanelprofile.cpp fspanelprofileclassifieds.cpp fspose.cpp + fsradar.cpp fsradarlistctrl.cpp + fsradarmenu.cpp fsslurlcommand.cpp fswsassetblacklist.cpp groupchatlistener.cpp @@ -796,6 +799,7 @@ set(viewer_HEADER_FILES fsfloaterplacedetails.h fsfloaterposestand.h fsfloaterprofile.h + fsfloaterradar.h fsfloatersearch.h fsfloaterteleporthistory.h fsfloatervoicecontrols.h @@ -819,7 +823,9 @@ set(viewer_HEADER_FILES fspanelprofile.h fspanelprofileclassifieds.h fspose.h + fsradar.h fsradarlistctrl.h + fsradarmenu.h fsslurl.h fsslurlcommand.h fswsassetblacklist.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 2cd58de7bb..ffb2fb4d19 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -465,4 +465,14 @@ tooltip_ref="Command_Snapshot_To_Disk_Tooltip" execute_function="File.TakeSnapshotToDisk" /> + diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index 1ac5d8c914..4b67d96b28 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -35,6 +35,7 @@ #include "aoengine.h" #include "fscommon.h" +#include "fsradar.h" #include "llagent.h" #include "llagentcamera.h" #include "llavatarlist.h" @@ -47,7 +48,6 @@ #include "llfloatersidepanelcontainer.h" #include "llinventorymodel.h" #include "llnotificationmanager.h" -#include "llpanelpeople.h" #include "llparcel.h" #include "lltooldraganddrop.h" #include "lltrans.h" @@ -1169,11 +1169,11 @@ LLUUID cmdline_partial_name2key(std::string partial_name) std::string av_name; LLStringUtil::toLower(partial_name); - LLPanelPeople* panel_people = getPeoplePanel(); - if (panel_people) + FSRadar* radar = FSRadar::getInstance(); + if (radar) { std::vector items; - LLAvatarList* nearbyList = panel_people->getNearbyList(); + LLAvatarList* nearbyList = radar->getNearbyList(); nearbyList->getItems(items); for (std::vector::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) @@ -1195,10 +1195,10 @@ LLUUID cmdline_partial_name2key(std::string partial_name) void cmdline_tp2name(std::string target) { LLUUID avkey = cmdline_partial_name2key(target); - LLPanelPeople* panel_people = getPeoplePanel(); - if (avkey.notNull() && panel_people) + FSRadar* radar = FSRadar::getInstance(); + if (avkey.notNull() && radar) { - LLAvatarListItem* avatar_list_item = panel_people->getNearbyList()->getAvatarListItem(avkey); + LLAvatarListItem* avatar_list_item = radar->getNearbyList()->getAvatarListItem(avkey); if (avatar_list_item) { LLVector3d pos = avatar_list_item->getPosition(); diff --git a/indra/newview/fsfloaterradar.cpp b/indra/newview/fsfloaterradar.cpp new file mode 100644 index 0000000000..c5d2138afd --- /dev/null +++ b/indra/newview/fsfloaterradar.cpp @@ -0,0 +1,473 @@ +/** + * @file fsfloaterradar.cpp + * @brief Firestorm radar floater implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Copyright (c) 2013 Ansariel Hiller @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "fsfloaterradar.h" + +// libs +#include "llfloaterreg.h" +#include "lllayoutstack.h" +#include "llmenugl.h" +#include "llnotificationsutil.h" +#include "lleventtimer.h" +#include "llfiltereditor.h" +#include "lluictrlfactory.h" +#include "llmenubutton.h" +#include "lltoggleablemenu.h" + +// newview +#include "fsradarmenu.h" +#include "llavataractions.h" +#include "llfloatersidepanelcontainer.h" +#include "llnetmap.h" +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewermenu.h" // for gMenuHolder +#include "llvoiceclient.h" +#include "rlvhandler.h" + + +/** + * Update buttons on changes in our friend relations (STORM-557). + */ +class FSButtonsUpdater : public FSRadar::Updater, public LLFriendObserver +{ +public: + FSButtonsUpdater(callback_t cb) + : FSRadar::Updater(cb) + { + LLAvatarTracker::instance().addObserver(this); + } + + ~FSButtonsUpdater() + { + LLAvatarTracker::instance().removeObserver(this); + } + + /*virtual*/ void changed(U32 mask) + { + (void) mask; + update(); + } +}; + + +//============================================================================= + +FSFloaterRadar::FSFloaterRadar(const LLSD& key) + : LLFloater(key), + mFilterSubString(LLStringUtil::null), + mFilterSubStringOrig(LLStringUtil::null), + mFilterEditor(NULL), + mRadarGearButton(NULL), + mMiniMap(NULL), + mRadarList(NULL) +{ + mButtonsUpdater = new FSButtonsUpdater(boost::bind(&FSFloaterRadar::updateButtons, this)); + mCommitCallbackRegistrar.add("People.addFriend", boost::bind(&FSFloaterRadar::onAddFriendButtonClicked, this)); +} + +FSFloaterRadar::~FSFloaterRadar() +{ + mUpdateSignalConnection.disconnect(); + delete mButtonsUpdater; + + if(LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->removeObserver(this); + } + + if (mRadarGearMenuHandle.get()) mRadarGearMenuHandle.get()->die(); +} + +BOOL FSFloaterRadar::postBuild() +{ + mFilterEditor = getChild("filter_input"); + mFilterEditor->setCommitCallback(boost::bind(&FSFloaterRadar::onFilterEdit, this, _2)); + + // AO: radarlist takes over for nearbylist for presentation. + mRadarList = getChild("radar_list"); + mRadarList->sortByColumn("range", TRUE); // sort by range + mRadarList->setFilterColumn(0); + mRadarList->setContextMenu(&FSFloaterRadarMenu::gFSRadarMenu); + mRadarList->setDoubleClickCallback(boost::bind(&FSFloaterRadar::onRadarListDoubleClicked, this)); + mRadarList->setCommitCallback(boost::bind(&FSFloaterRadar::onRadarListCommitted, this)); + + mMiniMap = getChild("Net Map"); + + buttonSetAction("view_profile_btn", boost::bind(&FSFloaterRadar::onViewProfileButtonClicked, this)); + buttonSetAction("im_btn", boost::bind(&FSFloaterRadar::onImButtonClicked, this)); + buttonSetAction("call_btn", boost::bind(&FSFloaterRadar::onCallButtonClicked, this)); + buttonSetAction("teleport_btn", boost::bind(&FSFloaterRadar::onTeleportButtonClicked, this)); + buttonSetAction("share_btn", boost::bind(&FSFloaterRadar::onShareButtonClicked, this)); + + // Create menus. + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + + registrar.add("Radar.Gear.Action", boost::bind(&FSFloaterRadar::onGearMenuItemClicked, this, _2)); + registrar.add("Radar.NameFmt", boost::bind(&FSRadar::onRadarNameFmtClicked, _2)); + registrar.add("Radar.ReportTo", boost::bind(&FSRadar::onRadarReportToClicked, _2)); + + enable_registrar.add("Radar.NameFmtCheck", boost::bind(&FSRadar::radarNameFmtCheck, _2)); + enable_registrar.add("Radar.ReportToCheck", boost::bind(&FSRadar::radarReportToCheck, _2)); + + mRadarGearButton = getChild("nearby_view_sort_btn"); + + LLToggleableMenu* radar_gear = LLUICtrlFactory::getInstance()->createFromFile("menu_fs_radar_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (radar_gear) + { + mRadarGearMenuHandle = radar_gear->getHandle(); + mRadarGearButton->setMenu(radar_gear); + } + + LLVoiceClient::getInstance()->addObserver(this); + + // Register for radar updates + mUpdateSignalConnection = FSRadar::getInstance()->setUpdateCallback(boost::bind(&FSFloaterRadar::updateNearby, this, _1, _2)); + + // call this method in case some list is empty and buttons can be in inconsistent state + updateButtons(); + + return TRUE; +} + +// virtual +void FSFloaterRadar::onOpen(const LLSD& key) +{ + // Fill radar with most recent data so we don't have a blank window until next radar update + FSRadar* radar = FSRadar::getInstance(); + if (radar) + { + std::vector entries; + LLSD stats; + radar->getCurrentData(entries, stats); + updateNearby(entries, stats); + } + LLFloater::onOpen(key); +} + +// virtual +void FSFloaterRadar::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if (status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + updateButtons(); +} + +void FSFloaterRadar::buttonSetEnabled(const std::string& btn_name, bool enabled) +{ + // To make sure we're referencing the right widget (a child of the button bar). + LLButton* button = getChild("button_bar")->getChild(btn_name); + button->setEnabled(enabled); +} + +void FSFloaterRadar::buttonSetAction(const std::string& btn_name, const commit_signal_t::slot_type& cb) +{ + // To make sure we're referencing the right widget (a child of the button bar). + LLButton* button = getChild("button_bar")->getChild(btn_name); + button->setClickedCallback(cb); +} + +void FSFloaterRadar::updateButtons() +{ + LLUUID selected_id; + + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + + bool item_selected = (selected_uuids.size() == 1); + bool multiple_selected = (selected_uuids.size() >= 1); + + // Check whether selected avatar is our friend. + bool is_friend = true; + if (item_selected) + { + selected_id = selected_uuids.front(); + is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; + } + getChildView("add_friend_btn_nearby")->setEnabled(!is_friend && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + + + bool enable_calls = LLVoiceClient::getInstance()->isVoiceWorking() && LLVoiceClient::getInstance()->voiceEnabled(); + +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.2a) | Modified: RLVa-1.2.0d + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + item_selected = multiple_selected = false; + } +// [/RLBa:KB] + + buttonSetEnabled("view_profile_btn",item_selected); + buttonSetEnabled("share_btn", item_selected); + buttonSetEnabled("im_btn", multiple_selected); // allow starting the friends conference for multiple selection + buttonSetEnabled("call_btn", multiple_selected && enable_calls); + buttonSetEnabled("teleport_btn", multiple_selected /* && LLAvatarActions::canOfferTeleport(selected_uuids) */ ); // LO - Dont block the TP button at all. +} + +LLUUID FSFloaterRadar::getCurrentItemID() const +{ + LLScrollListItem* item = mRadarList->getFirstSelected(); + if (item) + { + return item->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID(); + } + + return LLUUID::null; +} + +void FSFloaterRadar::getCurrentItemIDs(uuid_vec_t& selected_uuids) const +{ + for (size_t i = 0; i < mRadarList->getAllSelected().size(); ++i) + { + selected_uuids.push_back(mRadarList->getAllSelected().at(i)->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID()); + } +} + +void FSFloaterRadar::onFilterEdit(const std::string& search_string) +{ + mFilterSubStringOrig = search_string; + LLStringUtil::trimHead(mFilterSubStringOrig); + // Searches are case-insensitive + std::string search_upper = mFilterSubStringOrig; + LLStringUtil::toUpper(search_upper); + + if (mFilterSubString == search_upper) + { + return; + } + + mFilterSubString = search_upper; + + // Apply new filter. + mRadarList->setFilterString(mFilterSubStringOrig); +} + +void FSFloaterRadar::onRadarListDoubleClicked() +{ + LLScrollListItem* item = mRadarList->getFirstSelected(); + if (!item) + { + return; + } + + LLUUID clicked_id = item->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID(); + std::string name = item->getColumn(mRadarList->getColumn("name")->mIndex)->getValue().asString(); + + FSRadar* radar = FSRadar::getInstance(); + if (radar) + { + radar->zoomAvatar(clicked_id, name); + } +} + +void FSFloaterRadar::onRadarListCommitted() +{ + uuid_vec_t selected_uuids; + LLUUID sVal = mRadarList->getSelectedValue().asUUID(); + if (sVal.notNull()) + { + selected_uuids.push_back(sVal); + mMiniMap->setSelected(selected_uuids); + } + + updateButtons(); +} + +void FSFloaterRadar::onViewProfileButtonClicked() +{ + LLUUID id = getCurrentItemID(); + LLAvatarActions::showProfile(id); +} + +void FSFloaterRadar::onAddFriendButtonClicked() +{ + LLUUID id = getCurrentItemID(); + if (id.notNull()) + { + LLAvatarActions::requestFriendshipDialog(id); + } +} + +void FSFloaterRadar::onImButtonClicked() +{ + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + if ( selected_uuids.size() == 1 ) + { + // if selected only one person then start up IM + LLAvatarActions::startIM(selected_uuids.at(0)); + } + else if ( selected_uuids.size() > 1 ) + { + // for multiple selection start up friends conference + LLAvatarActions::startConference(selected_uuids); + } +} + +void FSFloaterRadar::onCallButtonClicked() +{ + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + + if (selected_uuids.size() == 1) + { + // initiate a P2P voice chat with the selected user + LLAvatarActions::startCall(getCurrentItemID()); + } + else if (selected_uuids.size() > 1) + { + // initiate an ad-hoc voice chat with multiple users + LLAvatarActions::startAdhocCall(selected_uuids); + } +} + +void FSFloaterRadar::onTeleportButtonClicked() +{ + uuid_vec_t selected_uuids; + getCurrentItemIDs(selected_uuids); + LLAvatarActions::offerTeleport(LLAvatarActions::canOfferTeleport(selected_uuids)); +} + +void FSFloaterRadar::onShareButtonClicked() +{ + LLAvatarActions::share(getCurrentItemID()); +} + +void FSFloaterRadar::onGearMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if (chosen_item == "panel_block_list_sidetray") + { + if (gSavedSettings.getBOOL("FSUseStandaloneBlocklistFloater")) + { + LLFloaterReg::showInstance("fs_blocklist", LLSD()); + } + else + { + LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD()); + } + } +} + +void FSFloaterRadar::updateNearby(const std::vector& entries, const LLSD& stats) +{ + if (!getVisible()) + { + return; + } + + if (!mRadarList) + { + return; + } + + // Store current selection and scroll position + static S32 uuidColumnIndex = mRadarList->getColumn("uuid")->mIndex; + std::vector selected_items = mRadarList->getAllSelected(); + uuid_vec_t selected_ids; + for (size_t i = 0; i < selected_items.size(); i++) + { + selected_ids.push_back(selected_items.at(i)->getColumn(uuidColumnIndex)->getValue().asUUID()); + } + S32 lastScroll = mRadarList->getScrollPos(); + + // Update list + mRadarList->clearRows(); + const std::vector::const_iterator it_end = entries.end(); + for (std::vector::const_iterator it = entries.begin(); it != it_end; ++it) + { + LLSD entry = (*it)["entry"]; + LLSD options = (*it)["options"]; + + LLSD row_data; + row_data["value"] = entry["id"]; + row_data["columns"][0]["column"] = "name"; + row_data["columns"][0]["value"] = entry["name"]; + row_data["columns"][1]["column"] = "voice_level"; + row_data["columns"][1]["type"] = "icon"; + row_data["columns"][1]["value"] = ""; // Need to set it after the row has been created because it's to big for the row + row_data["columns"][2]["column"] = "in_region"; + row_data["columns"][2]["type"] = "icon"; + row_data["columns"][2]["value"] = (entry["in_region"].asBoolean() ? "avatar_in_region" : ""); + row_data["columns"][3]["column"] = "flags"; + row_data["columns"][3]["value"] = entry["flags"]; + row_data["columns"][4]["column"] = "age"; + row_data["columns"][4]["value"] = entry["age"]; + row_data["columns"][5]["column"] = "seen"; + row_data["columns"][5]["value"] = entry["seen"]; + row_data["columns"][6]["column"] = "range"; + row_data["columns"][6]["value"] = entry["range"]; + row_data["columns"][7]["column"] = "uuid"; // invisible column for referencing av-key the row belongs to + row_data["columns"][7]["value"] = entry["id"]; + + LLScrollListItem* row = mRadarList->addElement(row_data); + + static S32 rangeColumnIndex = mRadarList->getColumn("range")->mIndex; + static S32 nameColumnIndex = mRadarList->getColumn("name")->mIndex; + static S32 voiceLevelColumnIndex = mRadarList->getColumn("voice_level")->mIndex; + + LLScrollListText* radarRangeCell = (LLScrollListText*)row->getColumn(rangeColumnIndex); + radarRangeCell->setColor(LLColor4(options["range_color"])); + radarRangeCell->setFontStyle(options["range_style"].asInteger()); + + LLScrollListText* radarNameCell = (LLScrollListText*)row->getColumn(nameColumnIndex); + radarNameCell->setFontStyle(options["name_style"].asInteger()); + if (options.has("name_color")) + { + radarNameCell->setColor(LLColor4(options["name_color"])); + } + + LLScrollListText* voiceLevelCell = (LLScrollListText*)row->getColumn(voiceLevelColumnIndex); + if (entry.has("voice_level_icon")) + { + voiceLevelCell->setValue(entry["voice_level_icon"].asString()); + } + } + + LLStringUtil::format_map_t name_count_args; + name_count_args["[TOTAL]"] = stats["total"].asString(); + name_count_args["[IN_REGION]"] = stats["region"].asString(); + name_count_args["[IN_CHAT_RANGE]"] = stats["chatrange"].asString(); + LLScrollListColumn* column = mRadarList->getColumn("name"); + column->mHeader->setLabel(getString("avatar_name_count", name_count_args)); + column->mHeader->setToolTipArgs(name_count_args); + + // Restore scroll position + mRadarList->setScrollPos(lastScroll); + + // Restore selection list + if (!selected_ids.empty()) + { + mRadarList->selectMultiple(selected_ids); + } + + updateButtons(); +} diff --git a/indra/newview/fsfloaterradar.h b/indra/newview/fsfloaterradar.h new file mode 100644 index 0000000000..0dfed91d26 --- /dev/null +++ b/indra/newview/fsfloaterradar.h @@ -0,0 +1,98 @@ +/** + * @file fsfloaterradar.h + * @brief Firestorm radar floater implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Copyright (c) 2013 Ansariel Hiller @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#ifndef FS_FLOATERRADAR_H +#define FS_FLOATERRADAR_H + +#include "llfloater.h" + +#include "fsradar.h" +#include "fsradarlistctrl.h" +#include "llcallingcard.h" // for avatar tracker +#include "llvoiceclient.h" + +class LLFilterEditor; +class LLMenuButton; + +class FSFloaterRadar + : public LLFloater + , public LLVoiceClientStatusObserver +{ + LOG_CLASS(FSFloaterRadar); +public: + FSFloaterRadar(const LLSD &); + virtual ~FSFloaterRadar(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + + // Implements LLVoiceClientStatusObserver::onChange() to enable call buttons + // when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + + static void onRadarNameFmtClicked(const LLSD& userdata); + static bool radarNameFmtCheck(const LLSD& userdata); + static void onRadarReportToClicked(const LLSD& userdata); + static bool radarReportToCheck(const LLSD& userdata); + + void updateNearby(const std::vector& entries, const LLSD& stats); + +private: + void updateButtons(); + LLUUID getCurrentItemID() const; + void getCurrentItemIDs(uuid_vec_t& selected_uuids) const; + void buttonSetEnabled(const std::string& btn_name, bool enabled); + void buttonSetAction(const std::string& btn_name, const commit_signal_t::slot_type& cb); + + // UI callbacks + void onFilterEdit(const std::string& search_string); + void onViewProfileButtonClicked(); + void onAddFriendButtonClicked(); + void onImButtonClicked(); + void onCallButtonClicked(); + void onTeleportButtonClicked(); + void onShareButtonClicked(); + void onRadarListCommitted(); + void onRadarListDoubleClicked(); + void onGearMenuItemClicked(const LLSD& userdata); + + LLFilterEditor* mFilterEditor; + FSRadarListCtrl* mRadarList; + LLNetMap* mMiniMap; + + LLHandle mRadarGearMenuHandle; + + FSRadar::Updater* mButtonsUpdater; + + LLMenuButton* mRadarGearButton; + + std::string mFilterSubString; + std::string mFilterSubStringOrig; + + boost::signals2::connection mUpdateSignalConnection; +}; + +#endif // FS_FLOATERRADAR_H diff --git a/indra/newview/fslslbridgerequest.cpp b/indra/newview/fslslbridgerequest.cpp index a4dd322593..5fbd6d5d28 100644 --- a/indra/newview/fslslbridgerequest.cpp +++ b/indra/newview/fslslbridgerequest.cpp @@ -33,7 +33,7 @@ #include "fslslbridge.h" #include #include // for radar -#include "llpanelpeople.h" +#include "fsradar.h" #include "llavatarlist.h" #include "llavatarlistitem.h" @@ -93,10 +93,10 @@ FSLSLBridgeRequestRadarPosResponder::FSLSLBridgeRequestRadarPosResponder() } void FSLSLBridgeRequestRadarPosResponder::result(const LLSD& content) { - LLPanelPeople* panel_people = getPeoplePanel(); - if (panel_people) + FSRadar* radar = FSRadar::getInstance(); + if (radar) { - LLAvatarList* nearbyList = panel_people->getNearbyList(); + LLAvatarList* nearbyList = radar->getNearbyList(); std::string strContent = content.asString(); //llinfos << "Got info: " << strContent << llendl; diff --git a/indra/newview/fsradar.cpp b/indra/newview/fsradar.cpp new file mode 100644 index 0000000000..da1ee067ac --- /dev/null +++ b/indra/newview/fsradar.cpp @@ -0,0 +1,1053 @@ +/** + * @file fsradar.cpp + * @brief Firestorm radar implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Copyright (c) 2013 Ansariel Hiller @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "fsradar.h" + +// libs +#include +#include "llavatarnamecache.h" +#include "llnotificationsutil.h" +#include "lleventtimer.h" + +// newview +#include "fscommon.h" +#include "fslslbridge.h" +#include "lggcontactsets.h" +#include "llagent.h" +#include "llavataractions.h" +#include "llavatarconstants.h" // for range constants +#include "llavatarlist.h" +#include "llgroupactions.h" +#include "llnotificationmanager.h" +#include "lltracker.h" +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewermenu.h" // for gMenuHolder +#include "llvoavatar.h" +#include "llvoiceclient.h" +#include "llworld.h" +#include "llspeakers.h" +#include "rlvhandler.h" + +using namespace boost; + +#define FS_RADAR_LIST_UPDATE_INTERVAL 1 + +std::string formatString(std::string text, const LLStringUtil::format_map_t& args) +{ + LLStringUtil::format(text, args); + return text; +} + +/** + * Periodically updates the nearby people list while the Nearby tab is active. + * + * The period is defined by FS_NEARBY_LIST_UPDATE_INTERVAL constant. + */ +class FSRadarListUpdater : public FSRadar::Updater, public LLEventTimer +{ + LOG_CLASS(FSRadarListUpdater); + +public: + FSRadarListUpdater(callback_t cb) + : LLEventTimer(FS_RADAR_LIST_UPDATE_INTERVAL), + FSRadar::Updater(cb) + { + update(); + mEventTimer.start(); + } + + /*virtual*/ BOOL tick() + { + update(); + return FALSE; + } +}; + +//============================================================================= + +FSRadar::FSRadar() : + mNearbyList(NULL), + mRadarAlertRequest(false), + mRadarFrameCount(0), + mRadarLastBulkOffsetRequestTime(0), + mRadarLastRequestTime(0.f) +{ + // TODO: Ewwww ugly! Need to get rid of LLAvatarList -Ansariel + mNearbyList = new LLAvatarList(LLAvatarList::Params::Params()); +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.2a) | Added: RLVa-1.2.0d + mNearbyList->setRlvCheckShowNames(true); +// [/RLVa:KB] + + mRadarListUpdater = new FSRadarListUpdater(boost::bind(&FSRadar::updateRadarList, this)); +} + +FSRadar::~FSRadar() +{ + delete mRadarListUpdater; + delete mNearbyList; +} + +void FSRadar::radarAlertMsg(const LLUUID& agent_id, const LLAvatarName& av_name, const std::string& postMsg) +{ +// Milkshake-style radar alerts + LLCachedControl milkshake_radar(gSavedSettings, "FSMilkshakeRadarToasts", false); + + if (milkshake_radar) + { + LLSD payload = agent_id; + LLSD args; + args["NAME"] = getRadarName(av_name); + args["MESSAGE"] = postMsg; + LLNotificationPtr notification; + notification = LLNotificationsUtil::add("RadarAlert", + args, + payload.with("respond_on_mousedown", TRUE), + boost::bind(&LLAvatarActions::zoomIn, agent_id)); + } + else + { +// + LLChat chat; + chat.mText = postMsg; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + chat.mFromName = getRadarName(av_name); + chat.mFromID = agent_id; + chat.mChatType = CHAT_TYPE_RADAR; + // FS:LO FIRE-1439 - Clickable avatar names on local chat radar crossing reports + LLSD args; + args["type"] = LLNotificationsUI::NT_NEARBYCHAT; + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); + } // +} + +void FSRadar::updateRadarList() +{ + //AO : Warning, reworked heavily for Firestorm. + if (!mNearbyList) + { + return; + } + + //Configuration + LLWorld* world = LLWorld::getInstance(); + LLMuteList* mutelist = LLMuteList::getInstance(); + + static const F32 chat_range_say = world->getSayDistance(); + static const F32 chat_range_shout = world->getShoutDistance(); + + static const std::string str_chat_entering = LLTrans::getString("entering_chat_range"); + static const std::string str_chat_leaving = LLTrans::getString("leaving_chat_range"); + static const std::string str_draw_distance_entering = LLTrans::getString("entering_draw_distance"); + static const std::string str_draw_distance_leaving = LLTrans::getString("leaving_draw_distance"); + static const std::string str_region_entering = LLTrans::getString("entering_region"); + static const std::string str_region_entering_distance = LLTrans::getString("entering_region_distance"); + static const std::string str_region_leaving = LLTrans::getString("leaving_region"); + + static LLCachedControl RadarReportChatRangeEnter(gSavedSettings, "RadarReportChatRangeEnter"); + static LLCachedControl RadarReportChatRangeLeave(gSavedSettings, "RadarReportChatRangeLeave"); + static LLCachedControl RadarReportDrawRangeEnter(gSavedSettings, "RadarReportDrawRangeEnter"); + static LLCachedControl RadarReportDrawRangeLeave(gSavedSettings, "RadarReportDrawRangeLeave"); + static LLCachedControl RadarReportSimRangeEnter(gSavedSettings, "RadarReportSimRangeEnter"); + static LLCachedControl RadarReportSimRangeLeave(gSavedSettings, "RadarReportSimRangeLeave"); + static LLCachedControl RadarEnterChannelAlert(gSavedSettings, "RadarEnterChannelAlert"); + static LLCachedControl RadarLeaveChannelAlert(gSavedSettings, "RadarLeaveChannelAlert"); + static LLCachedControl nearMeRange(gSavedSettings, "NearMeRange"); + static LLCachedControl limitRange(gSavedSettings, "LimitRadarByRange"); + static LLCachedControl sUseLSLBridge(gSavedSettings, "UseLSLBridge"); + static LLCachedControl RenderFarClip(gSavedSettings, "RenderFarClip"); + + F32 drawRadius(RenderFarClip); + const LLVector3d& posSelf = gAgent.getPositionGlobal(); + LLViewerRegion* reg = gAgent.getRegion(); + LLUUID regionSelf; + if (reg) + { + regionSelf = reg->getRegionID(); + } + bool alertScripts = mRadarAlertRequest; // save the current value, so it doesn't get changed out from under us by another thread + std::vector items; + time_t now = time(NULL); + + //STEP 0: Clear model data + mRadarEnterAlerts.clear(); + mRadarLeaveAlerts.clear(); + mRadarOffsetRequests.clear(); + mRadarEntriesData.clear(); + mAvatarStats.clear(); + + //STEP 1: Update our basic data model: detect Avatars & Positions in our defined range + std::vector positions; + uuid_vec_t avatar_ids; + if (limitRange) + { + world->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), nearMeRange); + } + else + { + world->getAvatars(&avatar_ids, &positions); + } + mNearbyList->getIDs() = avatar_ids; // copy constructor, refreshing underlying mNearbyList + mNearbyList->setDirty(true, true); // AO: These optional arguements force updating even when we're not a visible window. + mNearbyList->getItems(items); + LLLocalSpeakerMgr::getInstance()->update(TRUE); + + //STEP 2: Transform detected model list data into more flexible multimap data structure; + //TS: Count avatars in chat range and in the same region + U32 inChatRange = 0; + U32 inSameRegion = 0; + std::vector::const_iterator + pos_it = positions.begin(), + pos_end = positions.end(); + uuid_vec_t::const_iterator + item_it = avatar_ids.begin(), + item_end = avatar_ids.end(); + for (;pos_it != pos_end && item_it != item_end; ++pos_it, ++item_it ) + { + // + //2a. For each detected av, gather up all data we would want to display or use to drive alerts + // + + LLUUID avId = static_cast(*item_it); + LLAvatarListItem* av = mNearbyList->getAvatarListItem(avId); + LLVector3d avPos = static_cast(*pos_it); + S32 seentime = 0; + LLUUID avRegion; + + // Skip modelling this avatar if its basic data is either inaccessible, or it's a dummy placeholder + LLViewerRegion *reg = world->getRegionFromPosGlobal(avPos); + if (!reg || !av) // don't update this radar listing if data is inaccessible + { + continue; + } + + // Try to get the avatar's viewer object - we will need it anyway later + LLVOAvatar* avVo = (LLVOAvatar*)gObjectList.findObject(avId); + + static LLUICachedControl showdummyav("FSShowDummyAVsinRadar"); + if (!showdummyav) + { + if (avVo && avVo->mIsDummy) + { + continue; + } + } + + avRegion = reg->getRegionID(); + if (lastRadarSweep.count(avId) > 1) // if we detect a multiple ID situation, get lastSeenTime from our cache instead + { + std::pair::iterator, std::multimap::iterator> dupeAvs; + dupeAvs = lastRadarSweep.equal_range(avId); + for (std::multimap::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2) + { + if (it2->second.lastRegion == avRegion) + { + seentime = (S32)difftime(now, it2->second.firstSeen); + } + } + } + else + { + seentime = (S32)difftime(now, av->getFirstSeen()); + } + //av->setFirstSeen(now - (time_t)seentime); // maintain compatibility with underlying list, deprecated + S32 hours = (S32)(seentime / 3600); + S32 mins = (S32)((seentime - hours * 3600) / 60); + S32 secs = (S32)((seentime - hours * 3600 - mins * 60)); + std::string avSeenStr = llformat("%d:%02d:%02d", hours, mins, secs); + S32 avStatusFlags = av->getAvStatus(); + std::string avFlagStr = ""; + if (avStatusFlags & AVATAR_IDENTIFIED) + { + avFlagStr += "$"; + } + std::string avAgeStr = av->getAvatarAge(); + std::string avName = getRadarName(avId); + av->setAvatarName(avName); // maintain compatibility with underlying list; used in other locations! + U32 lastZOffsetTime = av->getLastZOffsetTime(); + F32 avZOffset = av->getZOffset(); + if (avPos[VZ] == AVATAR_UNKNOWN_Z_OFFSET) // if our official z position is AVATAR_UNKNOWN_Z_OFFSET, we need a correction. + { + // set correction if we have it + if (avZOffset > 0.1) + { + avPos[VZ] = avZOffset; + } + + //schedule offset requests, if needed + if (sUseLSLBridge && (now > (mRadarLastBulkOffsetRequestTime + FSRADAR_COARSE_OFFSET_INTERVAL)) && (now > lastZOffsetTime + FSRADAR_COARSE_OFFSET_INTERVAL)) + { + mRadarOffsetRequests.push_back(avId); + av->setLastZOffsetTime(now); + } + } + F32 avRange = (avPos[VZ] != AVATAR_UNKNOWN_Z_OFFSET ? dist_vec(avPos, posSelf) : AVATAR_UNKNOWN_RANGE); + av->setRange(avRange); // maintain compatibility with underlying list; used in other locations! + av->setPosition(avPos); // maintain compatibility with underlying list; used in other locations! + + // + //2b. Process newly detected avatars + // + if (lastRadarSweep.count(avId) == 0) + { + // chat alerts + if (RadarReportChatRangeEnter && (avRange <= chat_range_say) && avRange > AVATAR_UNKNOWN_RANGE) + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_chat_entering, args); + make_ui_sound("UISndRadarChatEnter"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + if (RadarReportDrawRangeEnter && (avRange <= drawRadius) && avRange > AVATAR_UNKNOWN_RANGE) + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_draw_distance_entering, args); + make_ui_sound("UISndRadarDrawEnter"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + if (RadarReportSimRangeEnter && (avRegion == regionSelf)) + { + make_ui_sound("UISndRadarSimEnter"); // FIRE-6069: Radar alerts sounds + if (avRange != AVATAR_UNKNOWN_RANGE) // Don't report an inaccurate range in localchat, if the true range is not known. + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_region_entering_distance, args); + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else + { + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_region_entering)); + } + } + if (RadarEnterChannelAlert || (alertScripts)) + { + // Autodetect Phoenix chat UUID compatibility. + // If Leave channel alerts are not set, restrict reports to same-sim only. + if (!RadarLeaveChannelAlert) + { + if (avRegion == regionSelf) + { + mRadarEnterAlerts.push_back(avId); + } + } + else + { + mRadarEnterAlerts.push_back(avId); + } + } + } + + // + // 2c. Process previously detected avatars + // + else + { + radarFields rf; // will hold the newest version + // Check for range crossing alert threshholds, being careful to handle double-listings + if (lastRadarSweep.count(avId) == 1) // normal case, check from last position + { + rf = lastRadarSweep.find(avId)->second; + if (RadarReportChatRangeEnter || RadarReportChatRangeLeave) + { + if (RadarReportChatRangeEnter && (avRange <= chat_range_say && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > chat_range_say || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_chat_entering, args); + make_ui_sound("UISndRadarChatEnter"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else if (RadarReportChatRangeLeave && (avRange > chat_range_say || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= chat_range_say && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) + { + make_ui_sound("UISndRadarChatLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_chat_leaving)); + } + } + if (RadarReportDrawRangeEnter || RadarReportDrawRangeLeave) + { + if (RadarReportDrawRangeEnter && (avRange <= drawRadius && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > drawRadius || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_draw_distance_entering, args); + make_ui_sound("UISndRadarDrawEnter"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else if (RadarReportDrawRangeLeave && (avRange > drawRadius || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= drawRadius && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) + { + make_ui_sound("UISndRadarDrawLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_draw_distance_leaving)); + } + } + if (RadarReportSimRangeEnter || RadarReportSimRangeLeave ) + { + if (RadarReportSimRangeEnter && (avRegion == regionSelf) && (avRegion != rf.lastRegion)) + { + make_ui_sound("UISndRadarSimEnter"); // FIRE-6069: Radar alerts sounds + if (avRange != AVATAR_UNKNOWN_RANGE) // Don't report an inaccurate range in localchat, if the true range is not known. + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_region_entering_distance, args); + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else + { + LLAvatarNameCache::get(avId,boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_region_entering)); + } + } + else if (RadarReportSimRangeLeave && (rf.lastRegion == regionSelf) && (avRegion != regionSelf)) + { + make_ui_sound("UISndRadarSimLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_region_leaving)); + } + } + } + else if (lastRadarSweep.count(avId) > 1) // handle duplicates, from sim crossing oddness + { + // iterate through all the duplicates found, searching for the newest. + rf.firstSeen=0; + std::pair::iterator, std::multimap::iterator> dupeAvs; + dupeAvs = lastRadarSweep.equal_range(avId); + for (std::multimap::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2) + { + if (it2->second.firstSeen > rf.firstSeen) + { + rf = it2->second; + } + } + lldebugs << "Duplicates detected for " << avName <<" , most recent is " << rf.firstSeen << llendl; + + if (RadarReportChatRangeEnter || RadarReportChatRangeLeave) + { + if (RadarReportChatRangeEnter && (avRange <= chat_range_say && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > chat_range_say || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_chat_entering, args); + make_ui_sound("UISndRadarChatEnter"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else if (RadarReportChatRangeLeave && (avRange > chat_range_say || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= chat_range_say && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) + { + make_ui_sound("UISndRadarChatLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_chat_leaving)); + } + } + if (RadarReportDrawRangeEnter || RadarReportDrawRangeLeave) + { + if (RadarReportDrawRangeEnter && (avRange <= drawRadius && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > drawRadius || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_draw_distance_entering, args); + make_ui_sound("UISndRadarDrawEnter"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else if (RadarReportDrawRangeLeave && (avRange > drawRadius || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= drawRadius && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) + { + make_ui_sound("UISndRadarDrawLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_draw_distance_leaving)); + } + } + if (RadarReportSimRangeEnter || RadarReportSimRangeLeave) + { + if (RadarReportSimRangeEnter && (avRegion == regionSelf) && (avRegion != rf.lastRegion)) + { + make_ui_sound("UISndRadarSimEnter"); // FIRE-6069: Radar alerts sounds + if (avRange != AVATAR_UNKNOWN_RANGE) // Don't report an inaccurate range in localchat, if the true range is not known. + { + LLStringUtil::format_map_t args; + args["DISTANCE"] = llformat("%3.2f", avRange); + std::string message = formatString(str_region_entering_distance, args); + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, message)); + } + else + { + LLAvatarNameCache::get(avId,boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_region_entering)); + } + } + else if (RadarReportSimRangeLeave && (rf.lastRegion == regionSelf) && (avRegion != regionSelf)) + { + make_ui_sound("UISndRadarSimLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(avId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_region_leaving)); + } + } + } + //If we were manually asked to update an external source for all existing avatars, add them to the queue. + if (alertScripts) + { + mRadarEnterAlerts.push_back(avId); + } + } + + // + //2d. Prepare data for presentation view for this avatar + // + if (regionSelf == avRegion) + { + inSameRegion++; + } + + LLSD entry; + LLSD entry_options; + + entry["id"] = avId; + entry["name"] = avName; + entry["in_region"] = (regionSelf == avRegion); + entry["flags"] = avFlagStr; + entry["age"] = avAgeStr; + entry["seen"] = avSeenStr; + entry["range"] = (avRange > AVATAR_UNKNOWN_RANGE ? llformat("%3.2f", avRange) : llformat(">%3.2f", drawRadius)); + + //AO: Set any range colors / styles + LLUIColor range_color; + if (avRange > AVATAR_UNKNOWN_RANGE) + { + if (avRange <= chat_range_say) + { + range_color = LLUIColorTable::instance().getColor("AvatarListItemChatRange", LLColor4::red); + inChatRange++; + } + else if (avRange <= chat_range_shout) + { + range_color = LLUIColorTable::instance().getColor("AvatarListItemShoutRange", LLColor4::white); + } + else + { + range_color = LLUIColorTable::instance().getColor("AvatarListItemBeyondShoutRange", LLColor4::white); + } + } + else + { + range_color = LLUIColorTable::instance().getColor("AvatarListItemBeyondShoutRange", LLColor4::white); + } + entry_options["range_color"] = range_color.get().getValue(); + + // Check if avatar is in draw distance and a VOAvatar instance actually exists + if (avRange <= drawRadius && avRange > AVATAR_UNKNOWN_RANGE && avVo) + { + entry_options["range_style"] = LLFontGL::BOLD; + } + else + { + entry_options["range_style"] = LLFontGL::NORMAL; + } + + // Set friends colors / styles + LLFontGL::StyleFlags nameCellStyle = LLFontGL::NORMAL; + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(avId); + if (relation) + { + nameCellStyle = (LLFontGL::StyleFlags)(nameCellStyle | LLFontGL::BOLD); + } + if (mutelist->isMuted(avId)) + { + nameCellStyle = (LLFontGL::StyleFlags)(nameCellStyle | LLFontGL::ITALIC); + } + entry_options["name_style"] = nameCellStyle; + + if (LGGContactSets::getInstance()->hasFriendColorThatShouldShow(avId, LGG_CS_RADAR)) + { + LLColor4 name_color = LGGContactSets::getInstance()->getFriendColor(avId); + entry_options["name_color"] = name_color.getValue(); + } + + // Voice power level indicator + LLVoiceClient* voice_client = LLVoiceClient::getInstance(); + if (voice_client->voiceEnabled() && voice_client->isVoiceWorking()) + { + LLSpeaker* speaker = LLLocalSpeakerMgr::getInstance()->findSpeaker(avId); + if (speaker && speaker->isInVoiceChannel()) + { + EVoicePowerLevel power_level = voice_client->getPowerLevel(avId); + + switch (power_level) + { + case VPL_PTT_Off: + entry["voice_level_icon"] = "VoicePTT_Off"; + break; + case VPL_PTT_On: + entry["voice_level_icon"] = "VoicePTT_On"; + break; + case VPL_Level1: + entry["voice_level_icon"] = "VoicePTT_Lvl1"; + break; + case VPL_Level2: + entry["voice_level_icon"] = "VoicePTT_Lvl2"; + break; + case VPL_Level3: + entry["voice_level_icon"] = "VoicePTT_Lvl3"; + break; + default: + break; + } + } + } + + // Save data for our listeners + LLSD entry_data; + entry_data["entry"] = entry; + entry_data["options"] = entry_options; + mRadarEntriesData.push_back(entry_data); + } // End STEP 2, all model/presentation row processing complete. + + // + //STEP 3, process any bulk actions that require the whole model to be known first + // + + // + //3a. dispatch requests for ZOffset updates, working around minimap's inaccurate height + // + if (mRadarOffsetRequests.size() > 0) + { + std::string prefix = "getZOffsets|"; + std::string msg = ""; + U32 updatesPerRequest=0; + while (mRadarOffsetRequests.size() > 0) + { + LLUUID avId = mRadarOffsetRequests.back(); + mRadarOffsetRequests.pop_back(); + msg = llformat("%s%s,", msg.c_str(), avId.asString().c_str()); + if (++updatesPerRequest > FSRADAR_MAX_OFFSET_REQUESTS) + { + msg = msg.substr(0, msg.size() - 1); + FSLSLBridgeRequestResponder* responder = new FSLSLBridgeRequestRadarPosResponder(); + FSLSLBridge::instance().viewerToLSL(prefix +msg, responder); + //llinfos << " OFFSET REQUEST SEGMENT"<< prefix << msg << llendl; + msg = ""; + updatesPerRequest = 0; + } + } + if (updatesPerRequest > 0) + { + msg = msg.substr(0, msg.size() - 1); + FSLSLBridgeRequestResponder* responder = new FSLSLBridgeRequestRadarPosResponder(); + FSLSLBridge::instance().viewerToLSL(prefix + msg, responder); + //llinfos << " OFFSET REQUEST FINAL " << prefix << msg << llendl; + } + + // clear out the dispatch queue + mRadarOffsetRequests.clear(); + mRadarLastBulkOffsetRequestTime = now; + } + + // + //3b: process alerts for avatars that where here last frame, but gone this frame (ie, they left) + // as well as dispatch all earlier detected alerts for crossing range thresholds. + // + + for (std::multimap::const_iterator i = lastRadarSweep.begin(); i != lastRadarSweep.end(); ++i) + { + LLUUID prevId = i->first; + if (!mNearbyList->contains(prevId)) + { + radarFields rf = i->second; + if (RadarReportChatRangeLeave && (rf.lastDistance <= chat_range_say) && rf.lastDistance > AVATAR_UNKNOWN_RANGE) + { + make_ui_sound("UISndRadarChatLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(prevId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_chat_leaving)); + } + if (RadarReportDrawRangeLeave && (rf.lastDistance <= drawRadius) && rf.lastDistance > AVATAR_UNKNOWN_RANGE) + { + make_ui_sound("UISndRadarDrawLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(prevId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_draw_distance_leaving)); + } + if (RadarReportSimRangeLeave && (rf.lastRegion == regionSelf)) + { + make_ui_sound("UISndRadarSimLeave"); // FIRE-6069: Radar alerts sounds + LLAvatarNameCache::get(prevId, boost::bind(&FSRadar::radarAlertMsg, this, _1, _2, str_region_leaving)); + } + + if (RadarLeaveChannelAlert) + { + mRadarLeaveAlerts.push_back(prevId); + } + } + } + + static LLCachedControl RadarAlertChannel(gSavedSettings, "RadarAlertChannel"); + U32 num_entering = mRadarEnterAlerts.size(); + if (num_entering > 0) + { + mRadarFrameCount++; + S32 chan(RadarAlertChannel); + U32 num_this_pass = min(FSRADAR_MAX_AVATARS_PER_ALERT, num_entering); + std::string msg = llformat("%d,%d", mRadarFrameCount, num_this_pass); + U32 loop = 0; + while (loop < num_entering) + { + for (int i = 0; i < num_this_pass; i++) + { + msg = llformat("%s,%s", msg.c_str(), mRadarEnterAlerts[loop + i].asString().c_str()); + } + LLMessageSystem* msgs = gMessageSystem; + msgs->newMessage("ScriptDialogReply"); + msgs->nextBlock("AgentData"); + msgs->addUUID("AgentID", gAgent.getID()); + msgs->addUUID("SessionID", gAgent.getSessionID()); + msgs->nextBlock("Data"); + msgs->addUUID("ObjectID", gAgent.getID()); + msgs->addS32("ChatChannel", chan); + msgs->addS32("ButtonIndex", 1); + msgs->addString("ButtonLabel", msg.c_str()); + gAgent.sendReliableMessage(); + loop += num_this_pass; + num_this_pass = min(FSRADAR_MAX_AVATARS_PER_ALERT, num_entering - loop); + msg = llformat("%d,%d", mRadarFrameCount, num_this_pass); + } + } + U32 num_leaving = mRadarLeaveAlerts.size(); + if (num_leaving > 0) + { + mRadarFrameCount++; + S32 chan(RadarAlertChannel); + U32 num_this_pass = min(FSRADAR_MAX_AVATARS_PER_ALERT, num_leaving); + std::string msg = llformat("%d,-%d", mRadarFrameCount, min(FSRADAR_MAX_AVATARS_PER_ALERT, num_leaving)); + U32 loop = 0; + while (loop < num_leaving) + { + for (int i = 0; i < num_this_pass; i++) + { + msg = llformat("%s,%s", msg.c_str(), mRadarLeaveAlerts[loop + i].asString().c_str()); + } + LLMessageSystem* msgs = gMessageSystem; + msgs->newMessage("ScriptDialogReply"); + msgs->nextBlock("AgentData"); + msgs->addUUID("AgentID", gAgent.getID()); + msgs->addUUID("SessionID", gAgent.getSessionID()); + msgs->nextBlock("Data"); + msgs->addUUID("ObjectID", gAgent.getID()); + msgs->addS32("ChatChannel", chan); + msgs->addS32("ButtonIndex", 1); + msgs->addString("ButtonLabel", msg.c_str()); + gAgent.sendReliableMessage(); + loop += num_this_pass; + num_this_pass = min(FSRADAR_MAX_AVATARS_PER_ALERT, num_leaving - loop); + msg = llformat("%d,-%d", mRadarFrameCount, num_this_pass); + } + } + + // reset any active alert requests + if (alertScripts) + { + mRadarAlertRequest = false; + } + + // + //STEP 4: Cache our current model data, so we can compare it with the next fresh group of model data for fast change detection. + // + + lastRadarSweep.clear(); + for (std::vector::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + LLAvatarListItem* av = static_cast(*itItem); + radarFields rf; + rf.avName = av->getAvatarName(); + rf.lastDistance = av->getRange(); + rf.firstSeen = av->getFirstSeen(); + rf.lastStatus = av->getAvStatus(); + rf.ZOffset = av->getZOffset(); + rf.lastGlobalPos = av->getPosition(); + // Ansariel: This seems to be wrong and isn't needed anywhere + //if ((rf.ZOffset > 0) && (rf.lastGlobalPos[VZ] < 1024)) // if our position may need an offset correction, see if we have one to apply + //{ + // rf.lastGlobalPos[VZ] = rf.lastGlobalPos[VZ] + (1024 * rf.ZOffset); + //} + //rf.lastZOffsetTime = av->getLastZOffsetTime(); + if (rf.lastGlobalPos != LLVector3d(0.0f, 0.0f, 0.0f)) + { + LLViewerRegion* lastRegion = world->getRegionFromPosGlobal(rf.lastGlobalPos); + if (lastRegion) + { + rf.lastRegion = lastRegion->getRegionID(); + } + } + else + { + rf.lastRegion = LLUUID(0); + } + + lastRadarSweep.insert(std::pair(av->getAvatarId(), rf)); + } + + // + //STEP 5: Final data updates and notification of subscribers + // + + mAvatarStats["total"] = llformat("%d", lastRadarSweep.size()); + mAvatarStats["region"] = llformat("%d", inSameRegion); + mAvatarStats["chatrange"] = llformat("%d", inChatRange); + + checkTracking(); + + // Inform our subscribers about updates + if (!mUpdateSignal.empty()) + { + mUpdateSignal(mRadarEntriesData, mAvatarStats); + } +} + +void FSRadar::requestRadarChannelAlertSync() +{ + F32 timeNow = gFrameTimeSeconds; + if ((timeNow - FSRADAR_CHAT_MIN_SPACING) > mRadarLastRequestTime) + { + mRadarLastRequestTime = timeNow; + mRadarAlertRequest = true; + } +} + +void FSRadar::teleportToAvatar(const LLUUID& targetAv) +// Teleports user to last scanned location of nearby avatar +// Note: currently teleportViaLocation is disrupted by enforced landing points set on a parcel. +{ + std::vector items; + mNearbyList->getItems(items); + for (std::vector::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + LLAvatarListItem* av = static_cast(*itItem); + if (av->getAvatarId() == targetAv) + { + LLVector3d avpos = av->getPosition(); + if (avpos.mdV[VZ] == AVATAR_UNKNOWN_Z_OFFSET) + { + LLNotificationsUtil::add("TeleportToAvatarNotPossible"); + } + else + { + gAgent.teleportViaLocation(avpos); + } + return; + } + } +} + +//static +void FSRadar::onRadarNameFmtClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + if (chosen_item == "DN") + { + gSavedSettings.setU32("RadarNameFormat", FSRADAR_NAMEFORMAT_DISPLAYNAME); + } + else if (chosen_item == "UN") + { + gSavedSettings.setU32("RadarNameFormat", FSRADAR_NAMEFORMAT_USERNAME); + } + else if (chosen_item == "DNUN") + { + gSavedSettings.setU32("RadarNameFormat", FSRADAR_NAMEFORMAT_DISPLAYNAME_USERNAME); + } + else if (chosen_item == "UNDN") + { + gSavedSettings.setU32("RadarNameFormat", FSRADAR_NAMEFORMAT_USERNAME_DISPLAYNAME); + } +} + +//static +bool FSRadar::radarNameFmtCheck(const LLSD& userdata) +{ + std::string menu_item = userdata.asString(); + U32 name_format = gSavedSettings.getU32("RadarNameFormat"); + switch (name_format) + { + case FSRADAR_NAMEFORMAT_DISPLAYNAME: + return (menu_item == "DN"); + case FSRADAR_NAMEFORMAT_USERNAME: + return (menu_item == "UN"); + case FSRADAR_NAMEFORMAT_DISPLAYNAME_USERNAME: + return (menu_item == "DNUN"); + case FSRADAR_NAMEFORMAT_USERNAME_DISPLAYNAME: + return (menu_item == "UNDN"); + default: + break; + } + return false; +} + +// Milkshake-style radar alerts +//static +void FSRadar::onRadarReportToClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + if (chosen_item == "radar_toasts") + { + gSavedSettings.setBOOL("FSMilkshakeRadarToasts", TRUE); + } + else if (chosen_item == "radar_nearby_chat") + { + gSavedSettings.setBOOL("FSMilkshakeRadarToasts", FALSE); + } +} + +//static +bool FSRadar::radarReportToCheck(const LLSD& userdata) +{ + std::string menu_item = userdata.asString(); + bool report_to = gSavedSettings.getBOOL("FSMilkshakeRadarToasts"); + if (report_to) + { + return (menu_item == "radar_toasts"); + } + else + { + return (menu_item == "radar_nearby_chat"); + } +} +// + +std::string FSRadar::getRadarName(const LLAvatarName& avname) +{ +// [RLVa:KB-FS] - Checked: 2011-06-11 (RLVa-1.3.1) | Added: RLVa-1.3.1 + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + return RlvStrings::getAnonym(avname); + } +// [/RLVa:KB-FS] + + U32 fmt = gSavedSettings.getU32("RadarNameFormat"); + // if display names are enabled, allow a variety of formatting options, depending on menu selection + if (gSavedSettings.getBOOL("UseDisplayNames")) + { + if (fmt == FSRADAR_NAMEFORMAT_DISPLAYNAME) + { + return avname.mDisplayName; + } + else if (fmt == FSRADAR_NAMEFORMAT_USERNAME) + { + return avname.mUsername; + } + else if (fmt == FSRADAR_NAMEFORMAT_DISPLAYNAME_USERNAME) + { + std::string s1 = avname.mDisplayName; + to_lower(s1); + std::string s2 = avname.mUsername; + replace_all(s2, ".", " "); + if (s1.compare(s2) == 0) + { + return avname.mDisplayName; + } + else + { + return llformat("%s (%s)", avname.mDisplayName.c_str(), avname.mUsername.c_str()); + } + } + else if (fmt == FSRADAR_NAMEFORMAT_USERNAME_DISPLAYNAME) + { + std::string s1 = avname.mDisplayName; + to_lower(s1); + std::string s2 = avname.mUsername; + replace_all(s2, ".", " "); + if (s1.compare(s2) == 0) + { + return avname.mDisplayName; + } + else + { + return llformat("%s (%s)", avname.mUsername.c_str(), avname.mDisplayName.c_str()); + } + } + } + + // else use legacy name lookups + return avname.mDisplayName; // will be mapped to legacyname automatically by the name cache +} + +std::string FSRadar::getRadarName(const LLUUID& avId) +{ + LLAvatarName avname; + + if (LLAvatarNameCache::get(avId, &avname)) // use the synchronous call. We poll every second so there's less value in using the callback form. + { + return getRadarName(avname); + } + + // name not found. Temporarily fill in with the UUID. It's more distinguishable than (loading...) + return avId.asString(); +} + +void FSRadar::startTracking(const LLUUID& avatar_id) +{ + mTrackedAvatarId = avatar_id; + updateTracking(); +} + +void FSRadar::checkTracking() +{ + if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION + && LLTracker::getTrackedLocationType() == LLTracker::LOCATION_AVATAR) + { + updateTracking(); + } +} + +void FSRadar::updateTracking() +{ + std::multimap::const_iterator it; + it = lastRadarSweep.find(mTrackedAvatarId); + if (it != lastRadarSweep.end()) + { + if (LLTracker::getTrackedPositionGlobal() != it->second.lastGlobalPos) + { + std::string targetName(it->second.avName); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + { + targetName = RlvStrings::getAnonym(targetName); + } + LLTracker::trackLocation(it->second.lastGlobalPos, targetName, "", LLTracker::LOCATION_AVATAR); + } + } + else + { + LLTracker::stopTracking(NULL); + } +} + +void FSRadar::zoomAvatar(const LLUUID& avatar_id, const std::string& name) +{ + LLAvatarListItem* avl_item = mNearbyList->getAvatarListItem(avatar_id); + + if (!avl_item) + { + return; + } + + if (avl_item->getRange() <= gSavedSettings.getF32("RenderFarClip")) + { + handle_zoom_to_object(avatar_id, avl_item->getPosition()); + } + else + { + LLStringUtil::format_map_t args; + args["AVATARNAME"] = name.c_str(); + reportToNearbyChat(LLTrans::getString("camera_no_focus", args)); + } +} diff --git a/indra/newview/fsradar.h b/indra/newview/fsradar.h new file mode 100644 index 0000000000..9b5ee2cfeb --- /dev/null +++ b/indra/newview/fsradar.h @@ -0,0 +1,143 @@ +/** + * @file fsradar.h + * @brief Firestorm radar implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Copyright (c) 2013 Ansariel Hiller @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#ifndef FS_RADAR_H +#define FS_RADAR_H + +#include "llsingleton.h" + +class LLAvatarList; +class LLAvatarName; + +const U32 FSRADAR_MAX_AVATARS_PER_ALERT = 6; // maximum number of UUIDs we can cram into a single channel radar alert message +const U32 FSRADAR_COARSE_OFFSET_INTERVAL = 7; // seconds after which we query the bridge for a coarse location adjustment +const U32 FSRADAR_MAX_OFFSET_REQUESTS = 60; // 2048 / UUID size, leaving overhead space +const U32 FSRADAR_CHAT_MIN_SPACING = 6; // minimum delay between radar chat messages + +const U32 FSRADAR_NAMEFORMAT_DISPLAYNAME = 0; +const U32 FSRADAR_NAMEFORMAT_USERNAME = 1; +const U32 FSRADAR_NAMEFORMAT_DISPLAYNAME_USERNAME = 2; +const U32 FSRADAR_NAMEFORMAT_USERNAME_DISPLAYNAME = 3; + + +class FSRadar + : public LLSingleton +{ + LOG_CLASS(FSRadar); + +friend class LLSingleton; + +public: +// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d + LLAvatarList* getNearbyList() { return mNearbyList; } +// [/RLVa:KB] + + void startTracking(const LLUUID& avatar_id); + void zoomAvatar(const LLUUID& avatar_id, const std::string& name); + void teleportToAvatar(const LLUUID& targetAv); + void requestRadarChannelAlertSync(); + + static void onRadarNameFmtClicked(const LLSD& userdata); + static bool radarNameFmtCheck(const LLSD& userdata); + static void onRadarReportToClicked(const LLSD& userdata); + static bool radarReportToCheck(const LLSD& userdata); + + void getCurrentData(std::vector& entries, LLSD& stats) const { entries = mRadarEntriesData; stats = mAvatarStats; } + + // internals + class Updater + { + public: + typedef boost::function callback_t; + Updater(callback_t cb) + : mCallback(cb) + { } + + virtual ~Updater() + { } + + protected: + void update() + { + mCallback(); + } + + callback_t mCallback; + }; + + typedef boost::signals2::signal& entries, const LLSD& stats)> radar_update_callback_t; + boost::signals2::connection setUpdateCallback(const radar_update_callback_t::slot_type& cb) + { + return mUpdateSignal.connect(cb); + } + +private: + FSRadar(); + virtual ~FSRadar(); + + void updateRadarList(); + void updateTracking(); + void checkTracking(); + + std::string getRadarName(const LLUUID& avId); + std::string getRadarName(const LLAvatarName& avName); + void radarAlertMsg(const LLUUID& agent_id, const LLAvatarName& av_name, const std::string& postMsg); + + LLAvatarList* mNearbyList; + + Updater* mRadarListUpdater; + + struct radarFields + { + std::string avName; + F32 lastDistance; + LLVector3d lastGlobalPos; + LLUUID lastRegion; + time_t firstSeen; + S32 lastStatus; + U32 ZOffset; + time_t lastZOffsetTime; + + }; + + std::multimap < LLUUID, radarFields > lastRadarSweep; + std::vector mRadarEnterAlerts; + std::vector mRadarLeaveAlerts; + std::vector mRadarOffsetRequests; + std::vector mRadarEntriesData; + + S32 mRadarFrameCount; + bool mRadarAlertRequest; + F32 mRadarLastRequestTime; + U32 mRadarLastBulkOffsetRequestTime; + + LLUUID mTrackedAvatarId; + LLSD mAvatarStats; + + radar_update_callback_t mUpdateSignal; +}; + +#endif // FS_RADAR_H diff --git a/indra/newview/fsradarmenu.cpp b/indra/newview/fsradarmenu.cpp new file mode 100644 index 0000000000..e57edc382b --- /dev/null +++ b/indra/newview/fsradarmenu.cpp @@ -0,0 +1,250 @@ +/** + * @file fsradarmenu.cpp + * @brief Menu used by Firestorm radar + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (c) 2013 Ansariel Hiller @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +// libs +#include "llmenugl.h" +#include "lluictrlfactory.h" + +#include "fsradarmenu.h" + +// newview +#include "fsradar.h" +#include "llagent.h" +#include "llagentdata.h" // for gAgentID +#include "llavataractions.h" +#include "llcallingcard.h" // for LLAvatarTracker +#include "llviewermenu.h" // for gMenuHolder + +namespace FSFloaterRadarMenu +{ + +FSRadarMenu gFSRadarMenu; + +//== NearbyMenu =============================================================== + +LLContextMenu* FSRadarMenu::createMenu() +{ + // set up the callbacks for all of the avatar menu items + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + + if ( mUUIDs.size() == 1 ) + { + // Set up for one person selected menu + + const LLUUID& id = mUUIDs.front(); + registrar.add("Avatar.Profile", boost::bind(&LLAvatarActions::showProfile, id)); + registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, id)); + registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendDialog, id)); + registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startIM, id)); + registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id)); + registrar.add("Avatar.OfferTeleport", boost::bind(&FSRadarMenu::offerTeleport, this)); + registrar.add("Avatar.GroupInvite", boost::bind(&LLAvatarActions::inviteToGroup, id)); + registrar.add("Avatar.getScriptInfo", boost::bind(&LLAvatarActions::getScriptInfo, id)); + registrar.add("Avatar.ShowOnMap", boost::bind(&LLAvatarActions::showOnMap, id)); + registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id)); + registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id)); + registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id)); + registrar.add("Avatar.ZoomIn", boost::bind(&LLAvatarActions::zoomIn, id)); + registrar.add("Avatar.Report", boost::bind(&LLAvatarActions::report, id)); + registrar.add("Avatar.Eject", boost::bind(&LLAvatarActions::landEject, id)); + registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::landFreeze, id)); + registrar.add("Avatar.Kick", boost::bind(&LLAvatarActions::estateKick, id)); + registrar.add("Avatar.TeleportHome", boost::bind(&LLAvatarActions::estateTeleportHome, id)); + registrar.add("Avatar.EstateBan", boost::bind(&LLAvatarActions::estateBan, id)); + registrar.add("Avatar.Derender", boost::bind(&LLAvatarActions::derender, id, false)); + registrar.add("Avatar.DerenderPermanent", boost::bind(&LLAvatarActions::derender, id, true)); + registrar.add("Nearby.People.TeleportToAvatar", boost::bind(&FSRadarMenu::teleportToAvatar, this)); + registrar.add("Nearby.People.TrackAvatar", boost::bind(&FSRadarMenu::onTrackAvatarMenuItemClick, this)); + + enable_registrar.add("Avatar.EnableItem", boost::bind(&FSRadarMenu::enableContextMenuItem, this, _2)); + enable_registrar.add("Avatar.CheckItem", boost::bind(&FSRadarMenu::checkContextMenuItem, this, _2)); + enable_registrar.add("Avatar.VisibleZoomIn", boost::bind(&LLAvatarActions::canZoomIn, id)); + enable_registrar.add("Avatar.VisibleFreezeEject", boost::bind(&LLAvatarActions::canLandFreezeOrEject, id)); + enable_registrar.add("Avatar.VisibleKickTeleportHome", boost::bind(&LLAvatarActions::canEstateKickOrTeleportHome, id)); + + // create the context menu from the XUI + return createFromFile("menu_fs_radar.xml"); + } + else + { + // Set up for multi-selected People + + // registrar.add("Avatar.AddFriend", boost::bind(&LLAvatarActions::requestFriendshipDialog, mUUIDs)); // *TODO: unimplemented + registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startConference, mUUIDs)); + registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startAdhocCall, mUUIDs)); + registrar.add("Avatar.OfferTeleport", boost::bind(&FSRadarMenu::offerTeleport, this)); + registrar.add("Avatar.RemoveFriend", boost::bind(&LLAvatarActions::removeFriendsDialog, mUUIDs)); + // registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::startIM, mUUIDs)); // *TODO: unimplemented + // registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, mUUIDs)); // *TODO: unimplemented + registrar.add("Avatar.Eject", boost::bind(&LLAvatarActions::landEjectMultiple, mUUIDs)); + registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::landFreezeMultiple, mUUIDs)); + registrar.add("Avatar.Kick", boost::bind(&LLAvatarActions::estateKickMultiple, mUUIDs)); + registrar.add("Avatar.TeleportHome", boost::bind(&LLAvatarActions::estateTeleportHomeMultiple, mUUIDs)); + registrar.add("Avatar.EstateBan", boost::bind(&LLAvatarActions::estateBanMultiple, mUUIDs)); + registrar.add("Avatar.Derender", boost::bind(&LLAvatarActions::derenderMultiple, mUUIDs, false)); + registrar.add("Avatar.DerenderPermanent", boost::bind(&LLAvatarActions::derenderMultiple, mUUIDs, true)); + + enable_registrar.add("Avatar.EnableItem", boost::bind(&FSRadarMenu::enableContextMenuItem, this, _2)); + enable_registrar.add("Avatar.VisibleFreezeEject", boost::bind(&LLAvatarActions::canLandFreezeOrEjectMultiple, mUUIDs, false)); + enable_registrar.add("Avatar.VisibleKickTeleportHome", boost::bind(&LLAvatarActions::canEstateKickOrTeleportHomeMultiple, mUUIDs, false)); + + // create the context menu from the XUI + return createFromFile("menu_fs_radar_multiselect.xml"); + } +} + +bool FSRadarMenu::enableContextMenuItem(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + // Note: can_block and can_delete is used only for one person selected menu + // so we don't need to go over all uuids. + + if (item == std::string("can_block")) + { + const LLUUID& id = mUUIDs.front(); + return LLAvatarActions::canBlock(id); + } + else if (item == std::string("can_add")) + { + // We can add friends if: + // - there are selected people + // - and there are no friends among selection yet. + + //EXT-7389 - disable for more than 1 + if(mUUIDs.size() > 1) + { + return false; + } + + bool result = (mUUIDs.size() > 0); + + uuid_vec_t::const_iterator + id = mUUIDs.begin(), + uuids_end = mUUIDs.end(); + + for (;id != uuids_end; ++id) + { + if ( LLAvatarActions::isFriend(*id) ) + { + result = false; + break; + } + } + + return result; + } + else if (item == std::string("can_delete")) + { + // We can remove friends if: + // - there are selected people + // - and there are only friends among selection. + + bool result = (mUUIDs.size() > 0); + + uuid_vec_t::const_iterator + id = mUUIDs.begin(), + uuids_end = mUUIDs.end(); + + for (;id != uuids_end; ++id) + { + if ( !LLAvatarActions::isFriend(*id) ) + { + result = false; + break; + } + } + + return result; + } + else if (item == std::string("can_call")) + { + return LLAvatarActions::canCall(); + } + else if (item == std::string("can_show_on_map")) + { + const LLUUID& id = mUUIDs.front(); + + return (LLAvatarTracker::instance().isBuddyOnline(id) && is_agent_mappable(id)) + || gAgent.isGodlike(); + } + // Prevent teleport button from being disabled when someone on your + // friends list logs out but is still in the region and you have + // multiple people selected. + //else if(item == std::string("can_offer_teleport")) + //{ + // return LLAvatarActions::canOfferTeleport(mUUIDs); + //} + // + return false; +} + +bool FSRadarMenu::checkContextMenuItem(const LLSD& userdata) +{ + std::string item = userdata.asString(); + const LLUUID& id = mUUIDs.front(); + + if (item == std::string("is_blocked")) + { + return LLAvatarActions::isBlocked(id); + } + + return false; +} + +void FSRadarMenu::offerTeleport() +{ + // boost::bind cannot recognize overloaded method LLAvatarActions::offerTeleport(), + // so we have to use a wrapper. + LLAvatarActions::offerTeleport(mUUIDs); +} + +void FSRadarMenu::teleportToAvatar() +// AO: wrapper for functionality managed by LLPanelPeople, because it manages the nearby avatar list. +// Will only work for avatars within radar range. +{ + FSRadar* radar = FSRadar::getInstance(); + if (radar) + { + radar->teleportToAvatar(mUUIDs.front()); + } +} + +// Ansariel: Avatar tracking feature +void FSRadarMenu::onTrackAvatarMenuItemClick() +{ + FSRadar* radar = FSRadar::getInstance(); + if (radar) + { + radar->startTracking(mUUIDs.front()); + } +} + +} // namespace FSFloaterRadarMenu diff --git a/indra/newview/fsradarmenu.h b/indra/newview/fsradarmenu.h new file mode 100644 index 0000000000..01a0dba4b0 --- /dev/null +++ b/indra/newview/fsradarmenu.h @@ -0,0 +1,55 @@ +/** + * @file fsradarmenu.h + * @brief Menu used by Firestorm radar + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (c) 2013 Ansariel Hiller @ Second Life + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#ifndef FS_RADARMENU_H +#define FS_RADARMENU_H + +#include "lllistcontextmenu.h" + +namespace FSFloaterRadarMenu +{ + +/** + * Menu used in the nearby people list. + */ +class FSRadarMenu : public LLListContextMenu +{ +public: + /*virtual*/ LLContextMenu* createMenu(); +private: + bool enableContextMenuItem(const LLSD& userdata); + bool checkContextMenuItem(const LLSD& userdata); + void offerTeleport(); + void teleportToAvatar(); + void onTrackAvatarMenuItemClick(); +}; + +extern FSRadarMenu gFSRadarMenu; + +} // namespace FSFloaterRadarMenu + +#endif // FS_RADARMENU_H diff --git a/indra/newview/fsslurlcommand.cpp b/indra/newview/fsslurlcommand.cpp index 855193dec8..bdea6cb1c0 100644 --- a/indra/newview/fsslurlcommand.cpp +++ b/indra/newview/fsslurlcommand.cpp @@ -28,22 +28,21 @@ #include "fsslurlcommand.h" #include "fscommon.h" +#include "fsradar.h" #include "llagent.h" #include "llavataractions.h" #include "llavatarlist.h" #include "llavatarlistitem.h" #include "llcommandhandler.h" -#include "llfloatersidepanelcontainer.h" #include "llnotificationsutil.h" -#include "llpanelpeople.h" LLAvatarListItem* getAvatarListItem(const LLUUID& avatar_id) { - LLPanelPeople* panel_people = getPeoplePanel(); - if (panel_people) + FSRadar* radar = FSRadar::getInstance(); + if (radar) { - return panel_people->getNearbyList()->getAvatarListItem(avatar_id); + return radar->getNearbyList()->getAvatarListItem(avatar_id); } return NULL; @@ -118,11 +117,11 @@ public: { if (gAgentID != target_id) { - LLPanelPeople* panel_people = getPeoplePanel(); + FSRadar* radar = FSRadar::getInstance(); LLAvatarListItem* avatar_list_item = getAvatarListItem(target_id); - if (avatar_list_item && panel_people) + if (avatar_list_item && radar) { - panel_people->startTracking(target_id); + radar->startTracking(target_id); return true; } diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index f1e2e15896..22455d0b63 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -77,17 +77,13 @@ // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) #include "rlvhandler.h" // [/RLVa:KB] -#include "lltrans.h" #include "llmutelist.h" // Ansariel: For accessing the radar data #include "llavatarlist.h" #include "llavatarlistitem.h" -#include "llpanelpeople.h" -#include "llfloatersidepanelcontainer.h" +#include "fsradar.h" #include "lggcontactsets.h" - -#include "llavataractions.h" #include "fscommon.h" static LLDefaultChildRegistry::Register r1("net_map"); @@ -1018,10 +1014,10 @@ BOOL LLNetMap::handleToolTipAgent(const LLUUID& avatar_id) // aka radar when above 1020m. if (isHigher1020mBug) { - LLPanelPeople* panel_people = getPeoplePanel(); - if (panel_people) + FSRadar* radar = FSRadar::getInstance(); + if (radar) { - LLAvatarListItem* avatar_list_item = panel_people->getNearbyList()->getAvatarListItem(avatar_id); + LLAvatarListItem* avatar_list_item = radar->getNearbyList()->getAvatarListItem(avatar_id); if (avatar_list_item) { F32 radar_distance = avatar_list_item->getRange(); @@ -1710,10 +1706,10 @@ void LLNetMap::startTracking() { if (mClosestAgentRightClick.notNull()) { - LLPanelPeople* panel_people = getPeoplePanel(); - if (panel_people != NULL) + FSRadar* radar = FSRadar::getInstance(); + if (radar) { - panel_people->startTracking(mClosestAgentRightClick); + radar->startTracking(mClosestAgentRightClick); } } } diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index eb2be08798..a02a3d9266 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -30,20 +30,18 @@ #include "llavatarname.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" +#include "llmenubutton.h" #include "llmenugl.h" #include "llnotificationsutil.h" #include "lleventtimer.h" #include "llfiltereditor.h" #include "lltabcontainer.h" -#include "lluictrlfactory.h" -#include "llmenubutton.h" #include "lltoggleablemenu.h" - +#include "lluictrlfactory.h" #include "llpanelpeople.h" // newview -#include "llavatarpropertiesprocessor.h" #include "llaccordionctrl.h" #include "llaccordionctrltab.h" #include "llagent.h" @@ -66,31 +64,16 @@ #include "llvoiceclient.h" #include "llworld.h" #include "llspeakers.h" -// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.2a) -#include "rlvhandler.h" -// [/RLVa:KB] + +// Firestorm includes #include "fscontactsfloater.h" +#include "fsradar.h" #include "fsradarlistctrl.h" +#include "fsradarmenu.h" #include "llavatarconstants.h" // for range constants -#include -#include "llvoavatar.h" -#include -#include "llnotificationmanager.h" #include "lllayoutstack.h" -// #include "llnearbychatbar.h" // Remove floating chat bar -#include -#include -#include "llcontrol.h" -#include "lggcontactsets.h" -#include "fslslbridge.h" -#include "fslslbridgerequest.h" -#include "lltracker.h" -#include "fscommon.h" - -using namespace std; -using namespace boost; - - +#include "llnotificationmanager.h" +#include "rlvhandler.h" #define FRIEND_LIST_UPDATE_TIMEOUT 0.5 #define NEARBY_LIST_UPDATE_INTERVAL 1 @@ -531,16 +514,19 @@ LLPanelPeople::LLPanelPeople() mNearbyList(NULL), mRecentList(NULL), mGroupList(NULL), - mNearbyGearButton(NULL), - mFriendsGearButton(NULL), - mGroupsGearButton(NULL), + mNearbyGearButton(NULL), + mFriendsGearButton(NULL), + mGroupsGearButton(NULL), mRecentGearButton(NULL), + // Firestorm radar + //mMiniMap(NULL) mMiniMap(NULL), - mRadarList(NULL), - mRadarLastRequestTime(0.f) + mRadarList(NULL) + // Firestorm radar { mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList, this)); - mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); + // Firestorm radar + //mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); mButtonsUpdater = new LLButtonsUpdater(boost::bind(&LLPanelPeople::updateButtons, this)); mCommitCallbackRegistrar.add("People.addFriend", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); @@ -548,8 +534,12 @@ LLPanelPeople::LLPanelPeople() LLPanelPeople::~LLPanelPeople() { + // Firestorm radar + mNearbyUpdateSignalConnection.disconnect(); + delete mButtonsUpdater; - delete mNearbyListUpdater; + // Firestorm radar + //delete mNearbyListUpdater; delete mFriendListUpdater; delete mRecentListUpdater; @@ -598,39 +588,45 @@ BOOL LLPanelPeople::postBuild() mAllFriendList = friends_tab->getChild("avatars_all"); mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); mOnlineFriendList->setShowIcons("FriendsListShowIcons"); + // Firestorm radar + //mOnlineFriendList->showPermissions("FriendsListShowPermissions"); mOnlineFriendList->showPermissions(true); + // Firestorm radar mAllFriendList->setNoItemsCommentText(getString("no_friends")); mAllFriendList->setShowIcons("FriendsListShowIcons"); + // Firestorm radar + //mAllFriendList->showPermissions("FriendsListShowPermissions"); mAllFriendList->showPermissions(true); - + // Firestorm radar + LLPanel* nearby_tab = getChild(NEARBY_TAB_NAME); - nearby_tab->getChildView("NearMeRange")->setVisible(gSavedSettings.getBOOL("LimitRadarByRange")); - - // AO: radarlist takes over for nearbylist for presentation. - mRadarList = nearby_tab->getChild("radar_list"); - mRadarList->sortByColumn("range",TRUE); // sort by range - mRadarList->setFilterColumn(0); - mRadarFrameCount = 0; - mRadarAlertRequest = false; - mRadarLastBulkOffsetRequestTime = 0; - - // AO: mNearbyList is preserved as a data structure model for radar - mNearbyList = nearby_tab->getChild("avatar_list"); - mNearbyListUpdater->setActive(true); // AO: always keep radar active, for chat and channel integration + // Firestorm radar //nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2)); + + // Radarlist takes over for nearbylist for presentation. + mRadarList = nearby_tab->getChild("radar_list"); + mRadarList->sortByColumn("range", TRUE); // sort by range + mRadarList->setFilterColumn(0); + // + + // Firestorm radar + //mNearbyList = nearby_tab->getChild("avatar_list"); + //mNearbyList->setNoItemsCommentText(getString("no_one_near")); + //mNearbyList->setNoItemsMsg(getString("no_one_near")); + //mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); + //mNearbyList->setShowIcons("NearbyListShowIcons"); + // Firestorm radar // [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.2a) | Added: RLVa-1.2.0d - mNearbyList->setRlvCheckShowNames(true); + // Externalized to FSRadar + //mNearbyList->setRlvCheckShowNames(true); // [/RLVa:KB] - LLLayoutPanel* minilayout = (LLLayoutPanel*)getChildView("minimaplayout",true); - minilayout->setMinDim(140); mMiniMap = (LLNetMap*)getChildView("Net Map",true); // Synchronize tooltips throughout instances //mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? // getString("AltMiniMapToolTipMsg") : getString("MiniMapToolTipMsg")); // Synchronize tooltips throughout instances - gSavedSettings.getControl("LimitRadarByRange")->getCommitSignal()->connect(boost::bind(&LLPanelPeople::handleLimitRadarByRange, this, _2)); - + mRecentList = getChild(RECENT_TAB_NAME)->getChild("avatar_list"); mRecentList->setNoItemsCommentText(getString("no_recent_people")); mRecentList->setNoItemsMsg(getString("no_recent_people")); @@ -641,14 +637,18 @@ BOOL LLPanelPeople::postBuild() mGroupList->setNoItemsMsg(getString("no_groups_msg")); mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); - mRadarList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); + // Use Firestorm radar menu handler + //mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); + mRadarList->setContextMenu(&FSFloaterRadarMenu::gFSRadarMenu); + // mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); setSortOrder(mRecentList, (ESortOrder)gSavedSettings.getU32("RecentPeopleSortOrder"), false); setSortOrder(mAllFriendList, (ESortOrder)gSavedSettings.getU32("FriendsSortOrder"), false); - setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false); + // Firestorm radar + //setSortOrder(mNearbyList, (ESortOrder)gSavedSettings.getU32("NearbyPeopleSortOrder"), false); LLPanel* groups_panel = getChild(GROUP_TAB_NAME); groups_panel->childSetAction("activate_btn", boost::bind(&LLPanelPeople::onActivateButtonClicked, this)); @@ -657,21 +657,29 @@ BOOL LLPanelPeople::postBuild() LLPanel* friends_panel = getChild(FRIENDS_TAB_NAME); friends_panel->childSetAction("add_btn", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); friends_panel->childSetAction("del_btn", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); + // Firestorm radar friends_panel->childSetAction("GlobalOnlineStatusToggle", boost::bind(&LLPanelPeople::onGlobalVisToggleButtonClicked, this)); mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); - mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); + // Firestorm radar + //mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); mRadarList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onRadarListDoubleClicked, this)); + // Firestorm radar + mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1)); mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); - mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); + // We only use mRadarList here + //mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); + mRadarList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); // Set openning IM as default on return action for avatar lists mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); + // Firestorm radar + //mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this)); mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this)); @@ -702,22 +710,27 @@ BOOL LLPanelPeople::postBuild() LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - registrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); - registrar.add("People.Group.Minus.Action", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); - registrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); + registrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); + registrar.add("People.Group.Minus.Action", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); + registrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); registrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); registrar.add("People.Groups.ViewSort.Action", boost::bind(&LLPanelPeople::onGroupsViewSortMenuItemClicked, this, _2)); registrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); - registrar.add("Radar.NameFmt", boost::bind(&LLPanelPeople::onRadarNameFmtClicked, this, _2)); - registrar.add("Radar.ReportTo", boost::bind(&LLPanelPeople::onRadarReportToClicked, this, _2)); // Milkshake-style Radar Alerts + // Firestorm radar + registrar.add("Radar.Gear.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); - enable_registrar.add("Radar.NameFmtCheck", boost::bind(&LLPanelPeople::radarNameFmtCheck, this, _2)); - enable_registrar.add("Radar.ReportToCheck", boost::bind(&LLPanelPeople::radarReportToCheck, this, _2)); // Milkshake-style Radar Alerts - enable_registrar.add("People.Group.Minus.Enable", boost::bind(&LLPanelPeople::isRealGroup, this)); + enable_registrar.add("People.Group.Minus.Enable", boost::bind(&LLPanelPeople::isRealGroup, this)); enable_registrar.add("People.Friends.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemCheck, this, _2)); enable_registrar.add("People.Recent.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemCheck, this, _2)); enable_registrar.add("People.Nearby.ViewSort.CheckItem", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemCheck, this, _2)); + // Firestorm radar options + registrar.add("Radar.NameFmt", boost::bind(&FSRadar::onRadarNameFmtClicked, _2)); + registrar.add("Radar.ReportTo", boost::bind(&FSRadar::onRadarReportToClicked, _2)); // Milkshake-style Radar Alerts + enable_registrar.add("Radar.NameFmtCheck", boost::bind(&FSRadar::radarNameFmtCheck, _2)); + enable_registrar.add("Radar.ReportToCheck", boost::bind(&FSRadar::radarReportToCheck, _2)); // Milkshake-style Radar Alerts + // + mNearbyGearButton = getChild("nearby_view_sort_btn"); mFriendsGearButton = getChild("friends_viewsort_btn"); mGroupsGearButton = getChild("groups_viewsort_btn"); @@ -726,12 +739,16 @@ BOOL LLPanelPeople::postBuild() LLMenuGL* plus_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_group_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mGroupPlusMenuHandle = plus_menu->getHandle(); - LLToggleableMenu* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_people_nearby_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + // Use Firestorm gear menu + //LLToggleableMenu* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_people_nearby_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + LLToggleableMenu* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_fs_radar_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + // if(nearby_view_sort) { mNearbyViewSortMenuHandle = nearby_view_sort->getHandle(); mNearbyGearButton->setMenu(nearby_view_sort); } + LLToggleableMenu* friend_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_people_friends_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); if(friend_view_sort) { @@ -754,13 +771,16 @@ BOOL LLPanelPeople::postBuild() } LLVoiceClient::getInstance()->addObserver(this); - + // call this method in case some list is empty and buttons can be in inconsistent state updateButtons(); mOnlineFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); mAllFriendList->setRefreshCompleteCallback(boost::bind(&LLPanelPeople::onFriendListRefreshComplete, this, _1, _2)); - + + // Register for radar updates + mNearbyUpdateSignalConnection = FSRadar::getInstance()->setUpdateCallback(boost::bind(&LLPanelPeople::updateNearby, this, _1, _2)); + return TRUE; } @@ -775,55 +795,6 @@ void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, updateButtons(); } - -void LLPanelPeople::radarAlertMsg(const LLUUID& agent_id, const LLAvatarName& av_name,std::string postMsg) -{ - // FS:LO FIRE-1439 - Clickable avatar names on local chat radar crossing reports - //LLStringUtil::format_map_t formatargs; - //formatargs["AVATARNAME"] = getRadarName(av_name); - //LLStringUtil::format(postMsg, formatargs); - -// Milkshake-style radar alerts - LLCachedControl milkshake_radar(gSavedSettings, "FSMilkshakeRadarToasts", false); - - if (milkshake_radar) - { - LLSD payload = agent_id; - LLSD args; - args["NAME"] = getRadarName(av_name); - args["MESSAGE"] = postMsg; - LLNotificationPtr notification; - notification = LLNotificationsUtil::add("RadarAlert", - args, - payload.with("respond_on_mousedown", TRUE), - boost::bind(&LLAvatarActions::zoomIn, agent_id)); - } - else - { -// - LLChat chat; - chat.mText = postMsg; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - chat.mFromName = getRadarName(av_name); - chat.mFromID = agent_id; - chat.mChatType = CHAT_TYPE_RADAR; - // FS:LO FIRE-1439 - Clickable avatar names on local chat radar crossing reports - LLSD args; - args["type"] = LLNotificationsUI::NT_NEARBYCHAT; - LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); - } // -} - - -void LLPanelPeople::handleLimitRadarByRange(const LLSD& newvalue) -{ - LLPanel* cur_panel = mTabContainer->getCurrentPanel(); - if (cur_panel) - { - cur_panel->getChildView("NearMeRange")->setVisible(newvalue.asBoolean()); - } -} - void LLPanelPeople::updateFriendListHelpText() { // show special help text for just created account to help finding friends. EXT-4836 @@ -847,7 +818,7 @@ void LLPanelPeople::updateFriendList() { if (!mOnlineFriendList || !mAllFriendList) return; - + // get all buddies we know about const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); LLAvatarTracker::buddy_map_t all_buddies; @@ -876,7 +847,6 @@ void LLPanelPeople::updateFriendList() } else { - llwarns << "Friends Cards failed to load" << llendl; lldebugs << "No friends found" << llendl; } @@ -902,708 +872,16 @@ void LLPanelPeople::updateFriendList() void LLPanelPeople::updateNearbyList() { - //AO : Warning, reworked heavily for Firestorm. Do not merge into here without understanding what it's doing. - if (!mNearbyList) - { return; - } - - //Configuration - LLWorld* world = LLWorld::getInstance(); - LLMuteList* mutelist = LLMuteList::getInstance(); - static const F32 chat_range_say = world->getSayDistance(); - static const F32 chat_range_shout = world->getShoutDistance(); - - static LLCachedControl RadarReportChatRangeEnter(gSavedSettings, "RadarReportChatRangeEnter"); - static LLCachedControl RadarReportChatRangeLeave(gSavedSettings, "RadarReportChatRangeLeave"); - static LLCachedControl RadarReportDrawRangeEnter(gSavedSettings, "RadarReportDrawRangeEnter"); - static LLCachedControl RadarReportDrawRangeLeave(gSavedSettings, "RadarReportDrawRangeLeave"); - static LLCachedControl RadarReportSimRangeEnter(gSavedSettings, "RadarReportSimRangeEnter"); - static LLCachedControl RadarReportSimRangeLeave(gSavedSettings, "RadarReportSimRangeLeave"); - static LLCachedControl RadarEnterChannelAlert(gSavedSettings, "RadarEnterChannelAlert"); - static LLCachedControl RadarLeaveChannelAlert(gSavedSettings, "RadarLeaveChannelAlert"); - static LLCachedControl nearMeRange(gSavedSettings, "NearMeRange"); - static LLCachedControl limitRange(gSavedSettings, "LimitRadarByRange"); - static LLCachedControl sUseLSLBridge(gSavedSettings, "UseLSLBridge"); - static LLCachedControl RenderFarClip(gSavedSettings, "RenderFarClip"); - - F32 drawRadius = F32(RenderFarClip); - const LLVector3d& posSelf = gAgent.getPositionGlobal(); - LLViewerRegion* reg = gAgent.getRegion(); - LLUUID regionSelf; - if (reg) - { - regionSelf = reg->getRegionID(); - } - bool alertScripts = mRadarAlertRequest; // save the current value, so it doesn't get changed out from under us by another thread - std::vector items; - time_t now = time(NULL); - - //STEP 0: Clear model data, saving pieces as needed. - static S32 uuidColumnIndex = mRadarList->getColumn("uuid")->mIndex; - std::vector selected_items = mRadarList->getAllSelected(); - std::vector selected_ids; - for (size_t i = 0; i < selected_items.size(); i++) - { - selected_ids.push_back(selected_items.at(i)->getColumn(uuidColumnIndex)->getValue().asUUID()); - } - S32 lastScroll = mRadarList->getScrollPos(); - mRadarList->clearRows(); - mRadarEnterAlerts.clear(); - mRadarLeaveAlerts.clear(); - mRadarOffsetRequests.clear(); - - - //STEP 1: Update our basic data model: detect Avatars & Positions in our defined range std::vector positions; - std::vector avatar_ids; - if (limitRange) - { - world->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), nearMeRange); - } - else - { - world->getAvatars(&avatar_ids, &positions); - } - mNearbyList->getIDs() = avatar_ids; // copy constructor, refreshing underlying mNearbyList - mNearbyList->setDirty(true, true); // AO: These optional arguements force updating even when we're not a visible window. - mNearbyList->getItems(items); - LLLocalSpeakerMgr::getInstance()->update(TRUE); - - //STEP 2: Transform detected model list data into more flexible multimap data structure; - //TS: Count avatars in chat range and in the same region - U32 inChatRange = 0; - U32 inSameRegion = 0; - std::vector::const_iterator - pos_it = positions.begin(), - pos_end = positions.end(); - std::vector::const_iterator - item_it = avatar_ids.begin(), - item_end = avatar_ids.end(); - for (;pos_it != pos_end && item_it != item_end; ++pos_it, ++item_it ) - { - // - //2a. For each detected av, gather up all data we would want to display or use to drive alerts - // - - LLUUID avId = static_cast(*item_it); - LLAvatarListItem* av = mNearbyList->getAvatarListItem(avId); - LLVector3d avPos = static_cast(*pos_it); - S32 seentime = 0; - LLUUID avRegion; - - // Skip modelling this avatar if its basic data is either inaccessible, or it's a dummy placeholder - LLViewerRegion *reg = world->getRegionFromPosGlobal(avPos); - if ((!reg) || (!av)) // don't update this radar listing if data is inaccessible - { - continue; - } - // Try to get the avatar's viewer object - we will need it anyway later - LLVOAvatar* avVo = (LLVOAvatar*)gObjectList.findObject(avId); + LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + mNearbyList->setDirty(); - static LLUICachedControl showdummyav("FSShowDummyAVsinRadar"); - if (!showdummyav) - { - if (avVo && avVo->mIsDummy) - { - continue; - } - } - - avRegion = reg->getRegionID(); - if (lastRadarSweep.count(avId) > 1) // if we detect a multiple ID situation, get lastSeenTime from our cache instead - { - pair::iterator,multimap::iterator> dupeAvs; - dupeAvs = lastRadarSweep.equal_range(avId); - for (multimap::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2) - { - if (it2->second.lastRegion == avRegion) - { - seentime = (S32)difftime(now, it2->second.firstSeen); - } - } - } - else - { - seentime = (S32)difftime(now,av->getFirstSeen()); - } - //av->setFirstSeen(now - (time_t)seentime); // maintain compatibility with underlying list, deprecated - S32 hours = (S32)(seentime / 3600); - S32 mins = (S32)((seentime - hours * 3600) / 60); - S32 secs = (S32)((seentime - hours * 3600 - mins * 60)); - std::string avSeenStr = llformat("%d:%02d:%02d", hours, mins, secs); - S32 avStatusFlags = av->getAvStatus(); - std::string avFlagStr = ""; - if (avStatusFlags & AVATAR_IDENTIFIED) - { - avFlagStr += "$"; - } - std::string avAgeStr = av->getAvatarAge(); - std::string avName = getRadarName(avId); - av->setAvatarName(avName); // maintain compatibility with underlying list; used in other locations! - U32 lastZOffsetTime = av->getLastZOffsetTime(); - F32 avZOffset = av->getZOffset(); - if (avPos[VZ] == AVATAR_UNKNOWN_Z_OFFSET) // if our official z position is AVATAR_UNKNOWN_Z_OFFSET, we need a correction. - { - // set correction if we have it - if (avZOffset > 0.1) - { - avPos[VZ] = avZOffset; - } - - //schedule offset requests, if needed - if (sUseLSLBridge && (now > (mRadarLastBulkOffsetRequestTime + COARSE_OFFSET_INTERVAL)) && (now > lastZOffsetTime + COARSE_OFFSET_INTERVAL)) - { - mRadarOffsetRequests.push_back(avId); - av->setLastZOffsetTime(now); - } - } - F32 avRange = (avPos[VZ] != AVATAR_UNKNOWN_Z_OFFSET ? dist_vec(avPos, posSelf) : AVATAR_UNKNOWN_RANGE); - av->setRange(avRange); // maintain compatibility with underlying list; used in other locations! - av->setPosition(avPos); // maintain compatibility with underlying list; used in other locations! - - // - //2b. Process newly detected avatars - // - if (lastRadarSweep.count(avId) == 0) - { - // chat alerts - if (RadarReportChatRangeEnter && (avRange <= chat_range_say) && avRange > AVATAR_UNKNOWN_RANGE) - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_chat_range", args); - make_ui_sound("UISndRadarChatEnter"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - if (RadarReportDrawRangeEnter && (avRange <= drawRadius) && avRange > AVATAR_UNKNOWN_RANGE) - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_draw_distance", args); - make_ui_sound("UISndRadarDrawEnter"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - if (RadarReportSimRangeEnter && (avRegion == regionSelf)) - { - make_ui_sound("UISndRadarSimEnter"); // FIRE-6069: Radar alerts sounds - if (avRange != AVATAR_UNKNOWN_RANGE) // Don't report an inaccurate range in localchat, if the true range is not known. - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_region_distance", args); - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else - { - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("entering_region"))); - } - } - if (RadarEnterChannelAlert || (alertScripts)) - { - // Autodetect Phoenix chat UUID compatibility. - // If Leave channel alerts are not set, restrict reports to same-sim only. - if (!RadarLeaveChannelAlert) - { - if (avRegion == regionSelf) - { - mRadarEnterAlerts.push_back(avId); - } - } - else - { - mRadarEnterAlerts.push_back(avId); - } - } - } - - // - // 2c. Process previously detected avatars - // - else - { - radarFields rf; // will hold the newest version - // Check for range crossing alert threshholds, being careful to handle double-listings - if (lastRadarSweep.count(avId) == 1) // normal case, check from last position - { - rf = lastRadarSweep.find(avId)->second; - if (RadarReportChatRangeEnter || RadarReportChatRangeLeave ) - { - if (RadarReportChatRangeEnter && (avRange <= chat_range_say && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > chat_range_say || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_chat_range", args); - make_ui_sound("UISndRadarChatEnter"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else if (RadarReportChatRangeLeave && (avRange > chat_range_say || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= chat_range_say && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) - { - make_ui_sound("UISndRadarChatLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_chat_range"))); - } - } - if ( RadarReportDrawRangeEnter || RadarReportDrawRangeLeave ) - { - if (RadarReportDrawRangeEnter && (avRange <= drawRadius && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > drawRadius || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_draw_distance", args); - make_ui_sound("UISndRadarDrawEnter"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else if (RadarReportDrawRangeLeave && (avRange > drawRadius || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= drawRadius && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) - { - make_ui_sound("UISndRadarDrawLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_draw_distance"))); - } - } - if (RadarReportSimRangeEnter || RadarReportSimRangeLeave ) - { - if ( RadarReportSimRangeEnter && (avRegion == regionSelf) && (avRegion != rf.lastRegion)) - { - make_ui_sound("UISndRadarSimEnter"); // FIRE-6069: Radar alerts sounds - if (avRange != AVATAR_UNKNOWN_RANGE) // Don't report an inaccurate range in localchat, if the true range is not known. - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_region_distance", args); - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else - { - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("entering_region"))); - } - } - else if (RadarReportSimRangeLeave && (rf.lastRegion == regionSelf) && (avRegion != regionSelf)) - { - make_ui_sound("UISndRadarSimLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_region"))); - } - } - } - else if (lastRadarSweep.count(avId) > 1) // handle duplicates, from sim crossing oddness - { - // iterate through all the duplicates found, searching for the newest. - rf.firstSeen=0; - pair::iterator,multimap::iterator> dupeAvs; - dupeAvs = lastRadarSweep.equal_range(avId); - for (multimap::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2) - { - if (it2->second.firstSeen > rf.firstSeen) - { - rf = it2->second; - } - } - llinfos << "AO: Duplicates detected for " << avName <<" , most recent is " << rf.firstSeen << llendl; - - if (RadarReportChatRangeEnter || RadarReportChatRangeLeave) - { - if (RadarReportChatRangeEnter && (avRange <= chat_range_say && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > chat_range_say || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_chat_range", args); - make_ui_sound("UISndRadarChatEnter"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else if (RadarReportChatRangeLeave && (avRange > chat_range_say || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= chat_range_say && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) - { - make_ui_sound("UISndRadarChatLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_chat_range"))); - } - } - if (RadarReportDrawRangeEnter || RadarReportDrawRangeLeave) - { - if (RadarReportDrawRangeEnter && (avRange <= drawRadius && avRange > AVATAR_UNKNOWN_RANGE) && (rf.lastDistance > drawRadius || rf.lastDistance == AVATAR_UNKNOWN_RANGE)) - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_draw_distance", args); - make_ui_sound("UISndRadarDrawEnter"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else if (RadarReportDrawRangeLeave && (avRange > drawRadius || avRange == AVATAR_UNKNOWN_RANGE) && (rf.lastDistance <= drawRadius && rf.lastDistance > AVATAR_UNKNOWN_RANGE)) - { - make_ui_sound("UISndRadarDrawLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_draw_distance"))); - } - } - if (RadarReportSimRangeEnter || RadarReportSimRangeLeave) - { - if (RadarReportSimRangeEnter && (avRegion == regionSelf) && (avRegion != rf.lastRegion)) - { - make_ui_sound("UISndRadarSimEnter"); // FIRE-6069: Radar alerts sounds - if (avRange != AVATAR_UNKNOWN_RANGE) // Don't report an inaccurate range in localchat, if the true range is not known. - { - LLStringUtil::format_map_t args; - args["DISTANCE"] = llformat("%3.2f", avRange); - std::string message = getString("entering_region_distance", args); - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, message)); - } - else - { - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("entering_region"))); - } - } - else if (RadarReportSimRangeLeave && (rf.lastRegion == regionSelf) && (avRegion != regionSelf)) - { - make_ui_sound("UISndRadarSimLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_region"))); - } - } - } - //If we were manually asked to update an external source for all existing avatars, add them to the queue. - if (alertScripts) - { - mRadarEnterAlerts.push_back(avId); - } - } - - // - //2d. Build out scrollist-style presentation view for this avatar row - // - LLSD row; - row["value"] = avId; - row["columns"][0]["column"] = "name"; - row["columns"][0]["value"] = avName; - row["columns"][1]["column"] = "voice_level"; - row["columns"][1]["type"] = "icon"; - row["columns"][1]["value"] = ""; - row["columns"][2]["column"] = "in_region"; - row["columns"][2]["type"] = "icon"; - row["columns"][2]["value"] = ""; - if (regionSelf == avRegion) - { - row["columns"][2]["value"] = "avatar_in_region"; - inSameRegion++; - } - row["columns"][3]["column"] = "flags"; - row["columns"][3]["value"] = avFlagStr; - row["columns"][4]["column"] = "age"; - row["columns"][4]["value"] = avAgeStr; - row["columns"][5]["column"] = "seen"; - row["columns"][5]["value"] = avSeenStr; - row["columns"][6]["column"] = "range"; - row["columns"][6]["value"] = (avRange > AVATAR_UNKNOWN_RANGE ? llformat("%3.2f", avRange) : llformat(">%3.2f", drawRadius)); - row["columns"][7]["column"] = "uuid"; // invisible column for referencing av-key the row belongs to - row["columns"][7]["value"] = avId; - LLScrollListItem* radarRow = mRadarList->addElement(row); - - //AO: Set any range colors / styles - static S32 rangeColumnIndex = mRadarList->getColumn("range")->mIndex; - LLScrollListText* radarRangeCell = (LLScrollListText*)radarRow->getColumn(rangeColumnIndex); - if (avRange > AVATAR_UNKNOWN_RANGE) - { - if (avRange <= chat_range_say) - { - radarRangeCell->setColor(LLUIColorTable::instance().getColor("AvatarListItemChatRange", LLColor4::red)); - inChatRange++; - } - else if (avRange <= chat_range_shout) - { - radarRangeCell->setColor(LLUIColorTable::instance().getColor("AvatarListItemShoutRange", LLColor4::white)); - } - else - { - radarRangeCell->setColor(LLUIColorTable::instance().getColor("AvatarListItemBeyondShoutRange", LLColor4::white)); - } - } - else - { - radarRangeCell->setColor(LLUIColorTable::instance().getColor("AvatarListItemBeyondShoutRange", LLColor4::white)); - } - - // Check if avatar is in draw distance and a VOAvatar instance actually exists - if (avRange <= drawRadius && avRange > AVATAR_UNKNOWN_RANGE && avVo) - { - radarRangeCell->setFontStyle(LLFontGL::BOLD); - } - else - { - radarRangeCell->setFontStyle(LLFontGL::NORMAL); - } - - // Set friends colors / styles - LLFontGL::StyleFlags nameCellStyle = LLFontGL::NORMAL; - static S32 nameColumnIndex = mRadarList->getColumn("name")->mIndex; - LLScrollListText* radarNameCell = (LLScrollListText*)radarRow->getColumn(nameColumnIndex); - const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(avId); - if (relation) - { - nameCellStyle = (LLFontGL::StyleFlags)(nameCellStyle | LLFontGL::BOLD); - } - if (mutelist->isMuted(avId)) - { - nameCellStyle = (LLFontGL::StyleFlags)(nameCellStyle | LLFontGL::ITALIC); - } - radarNameCell->setFontStyle(nameCellStyle); - - if (LGGContactSets::getInstance()->hasFriendColorThatShouldShow(avId, LGG_CS_RADAR)) - { - radarNameCell->setColor(LGGContactSets::getInstance()->getFriendColor(avId)); - } - - // Voice power level indicator - LLVoiceClient* voice_client = LLVoiceClient::getInstance(); - if (voice_client->voiceEnabled() && voice_client->isVoiceWorking()) - { - LLSpeaker* speaker = LLLocalSpeakerMgr::getInstance()->findSpeaker(avId); - if (speaker && speaker->isInVoiceChannel()) - { - static S32 voiceLevelColumnIndex = mRadarList->getColumn("voice_level")->mIndex; - LLScrollListText* voiceLevelCell = (LLScrollListText*)radarRow->getColumn(voiceLevelColumnIndex); - EVoicePowerLevel power_level = voice_client->getPowerLevel(avId); - - switch (power_level) - { - case VPL_PTT_Off: - voiceLevelCell->setValue("VoicePTT_Off"); - break; - case VPL_PTT_On: - voiceLevelCell->setValue("VoicePTT_On"); - break; - case VPL_Level1: - voiceLevelCell->setValue("VoicePTT_Lvl1"); - break; - case VPL_Level2: - voiceLevelCell->setValue("VoicePTT_Lvl2"); - break; - case VPL_Level3: - voiceLevelCell->setValue("VoicePTT_Lvl3"); - break; - default: - break; - } - } - } - - //AO: Preserve selection - /*if (lastRadarSelectedItem) - { - if (avId == selected_id) - { - mRadarList->selectByID(avId); - updateButtons(); // TODO: only update on change, instead of every tick - } - }*/ - } // End STEP 2, all model/presentation row processing complete. - //Reset scroll position - mRadarList->setScrollPos(lastScroll); - - //Reset selection list - //AO: Preserve selection - if(!selected_ids.empty()) - { - mRadarList->selectMultiple(selected_ids); - } - updateButtons(); - - // - //STEP 3 , process any bulk actions that require the whole model to be known first - // - - // - //3a. dispatch requests for ZOffset updates, working around minimap's inaccurate height - // - if (mRadarOffsetRequests.size() > 0) - { - std::string prefix = "getZOffsets|"; - std::string msg = ""; - U32 updatesPerRequest=0; - while(mRadarOffsetRequests.size() > 0) - { - LLUUID avId = mRadarOffsetRequests.back(); - mRadarOffsetRequests.pop_back(); - msg = llformat("%s%s,",msg.c_str(),avId.asString().c_str()); - if (++updatesPerRequest > MAX_OFFSET_REQUESTS) - { - msg = msg.substr(0,msg.size()-1); - FSLSLBridgeRequestResponder* responder = new FSLSLBridgeRequestRadarPosResponder(); - FSLSLBridge::instance().viewerToLSL(prefix+msg,responder); - //llinfos << " OFFSET REQUEST SEGMENT"<< prefix << msg << llendl; - msg=""; - updatesPerRequest = 0; - } - } - if (updatesPerRequest > 0) - { - msg = msg.substr(0,msg.size()-1); - FSLSLBridgeRequestResponder* responder = new FSLSLBridgeRequestRadarPosResponder(); - FSLSLBridge::instance().viewerToLSL(prefix+msg,responder); - //llinfos << " OFFSET REQUEST FINAL " << prefix << msg << llendl; - } - - // clear out the dispatch queue - mRadarOffsetRequests.clear(); - mRadarLastBulkOffsetRequestTime = now; - } - - // - //3b: process alerts for avatars that where here last frame, but gone this frame (ie, they left) - // as well as dispatch all earlier detected alerts for crossing range thresholds. - // - - for (std::multimap ::const_iterator i = lastRadarSweep.begin(); i != lastRadarSweep.end(); ++i) - { - LLUUID prevId = i->first; - if (!mNearbyList->contains(prevId)) - { - radarFields rf = i->second; - if (RadarReportChatRangeLeave && (rf.lastDistance <= chat_range_say) && rf.lastDistance > AVATAR_UNKNOWN_RANGE) - { - make_ui_sound("UISndRadarChatLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(prevId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_chat_range"))); - } - if (RadarReportDrawRangeLeave && (rf.lastDistance <= drawRadius) && rf.lastDistance > AVATAR_UNKNOWN_RANGE) - { - make_ui_sound("UISndRadarDrawLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(prevId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_draw_distance"))); - } - if (RadarReportSimRangeLeave && (rf.lastRegion == regionSelf)) - { - make_ui_sound("UISndRadarSimLeave"); // FIRE-6069: Radar alerts sounds - LLAvatarNameCache::get(prevId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, getString("leaving_region"))); - } - - if (RadarLeaveChannelAlert) - { - mRadarLeaveAlerts.push_back(prevId); - } - } - } - - static LLCachedControl RadarAlertChannel(gSavedSettings, "RadarAlertChannel"); - U32 num_entering = mRadarEnterAlerts.size(); - if (num_entering > 0) - { - mRadarFrameCount++; - S32 chan = S32(RadarAlertChannel); - U32 num_this_pass = min(MAX_AVATARS_PER_ALERT,num_entering); - std::string msg = llformat("%d,%d",mRadarFrameCount,num_this_pass); - U32 loop = 0; - while (loop < num_entering) - { - for (int i = 0; i < num_this_pass; i++) - { - msg = llformat("%s,%s",msg.c_str(),mRadarEnterAlerts[loop + i].asString().c_str()); - } - LLMessageSystem* msgs = gMessageSystem; - msgs->newMessage("ScriptDialogReply"); - msgs->nextBlock("AgentData"); - msgs->addUUID("AgentID", gAgent.getID()); - msgs->addUUID("SessionID", gAgent.getSessionID()); - msgs->nextBlock("Data"); - msgs->addUUID("ObjectID", gAgent.getID()); - msgs->addS32("ChatChannel", chan); - msgs->addS32("ButtonIndex", 1); - msgs->addString("ButtonLabel", msg.c_str()); - gAgent.sendReliableMessage(); - loop += num_this_pass; - num_this_pass = min(MAX_AVATARS_PER_ALERT,num_entering-loop); - msg = llformat("%d,%d",mRadarFrameCount,num_this_pass); - } - } - U32 num_leaving = mRadarLeaveAlerts.size(); - if (num_leaving > 0) - { - mRadarFrameCount++; - S32 chan = S32(RadarAlertChannel); - U32 num_this_pass = min(MAX_AVATARS_PER_ALERT,num_leaving); - std::string msg = llformat("%d,-%d",mRadarFrameCount,min(MAX_AVATARS_PER_ALERT,num_leaving)); - U32 loop = 0; - while (loop < num_leaving) - { - for (int i = 0; i < num_this_pass; i++) - { - msg = llformat("%s,%s",msg.c_str(),mRadarLeaveAlerts[loop + i].asString().c_str()); - } - LLMessageSystem* msgs = gMessageSystem; - msgs->newMessage("ScriptDialogReply"); - msgs->nextBlock("AgentData"); - msgs->addUUID("AgentID", gAgent.getID()); - msgs->addUUID("SessionID", gAgent.getSessionID()); - msgs->nextBlock("Data"); - msgs->addUUID("ObjectID", gAgent.getID()); - msgs->addS32("ChatChannel", chan); - msgs->addS32("ButtonIndex", 1); - msgs->addString("ButtonLabel", msg.c_str()); - gAgent.sendReliableMessage(); - loop += num_this_pass; - num_this_pass = min(MAX_AVATARS_PER_ALERT,num_leaving-loop); - msg = llformat("%d,-%d",mRadarFrameCount,num_this_pass); - } - } - - // reset any active alert requests - if (alertScripts) - { - mRadarAlertRequest = false; - } - - // - //STEP 4: Cache our current model data, so we can compare it with the next fresh group of model data for fast change detection. - // - - lastRadarSweep.clear(); - for (std::vector::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) - { - LLAvatarListItem* av = static_cast(*itItem); - radarFields rf; - rf.avName = av->getAvatarName(); - rf.lastDistance = av->getRange(); - rf.firstSeen = av->getFirstSeen(); - rf.lastStatus = av->getAvStatus(); - rf.ZOffset = av->getZOffset(); - rf.lastGlobalPos = av->getPosition(); - // Ansariel: This seems to be wrong and isn't needed anywhere - //if ((rf.ZOffset > 0) && (rf.lastGlobalPos[VZ] < 1024)) // if our position may need an offset correction, see if we have one to apply - //{ - // rf.lastGlobalPos[VZ] = rf.lastGlobalPos[VZ] + (1024 * rf.ZOffset); - //} - //rf.lastZOffsetTime = av->getLastZOffsetTime(); - if (rf.lastGlobalPos != LLVector3d(0.0f,0.0f,0.0f)) - { - LLViewerRegion* lastRegion = world->getRegionFromPosGlobal(rf.lastGlobalPos); - if (lastRegion) - { - rf.lastRegion = lastRegion->getRegionID(); - } - } - else - { - rf.lastRegion = LLUUID(0); - } - - lastRadarSweep.insert(pair(av->getAvatarId(),rf)); - } - - // - //STEP 5: Final presentation updates - // - - // update header w/number of avs detected in this sweep - LLStringUtil::format_map_t name_count_args; - name_count_args["[TOTAL]"] = llformat("%d", lastRadarSweep.size()); - name_count_args["[IN_REGION]"] = llformat("%d", inSameRegion); - name_count_args["[IN_CHAT_RANGE]"] = llformat("%d", inChatRange); - LLScrollListColumn* column = mRadarList->getColumn("name"); - column->mHeader->setLabel(getString("avatar_name_count", name_count_args)); - column->mHeader->setToolTipArgs(name_count_args); - // update minimap with selected avatars - uuid_vec_t selected_uuids; - LLUUID sVal = mRadarList->getSelectedValue().asUUID(); - if (sVal != LLUUID::null) - { - selected_uuids.push_back(sVal); - mMiniMap->setSelected(selected_uuids); - } - - checkTracking(); + DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); + LLActiveSpeakerMgr::instance().update(TRUE); } void LLPanelPeople::updateRecentList() @@ -1642,13 +920,14 @@ void LLPanelPeople::updateButtons() bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME); bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); bool group_tab_active = (cur_tab == GROUP_TAB_NAME); + //bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); + // Firestorm changes bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); - LLPanel* cur_panel = mTabContainer->getCurrentPanel(); + // Firestorm changes LLUUID selected_id; uuid_vec_t selected_uuids; getCurrentItemIDs(selected_uuids); - bool item_selected = (selected_uuids.size() == 1); bool multiple_selected = (selected_uuids.size() >= 1); @@ -1658,9 +937,12 @@ void LLPanelPeople::updateButtons() buttonSetVisible("im_btn", !group_tab_active); buttonSetVisible("call_btn", !group_tab_active); buttonSetVisible("group_call_btn", group_tab_active); + // Firestorm changes + //buttonSetVisible("teleport_btn", friends_tab_active); buttonSetVisible("teleport_btn", nearby_tab_active || friends_tab_active); + // Firestorm changes buttonSetVisible("share_btn", nearby_tab_active || friends_tab_active); - + if (group_tab_active) { bool cur_group_active = true; @@ -1670,13 +952,14 @@ void LLPanelPeople::updateButtons() selected_id = mGroupList->getSelectedUUID(); cur_group_active = (gAgent.getGroupID() == selected_id); } - cur_panel->getChildView("activate_btn")->setEnabled(item_selected && !cur_group_active); // "none" or a non-active group selected - cur_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); -// cur_panel->getChildView("activate_btn")->setEnabled(item_selected && !cur_group_active); // "none" or a non-active group selected + + LLPanel* groups_panel = mTabContainer->getCurrentPanel(); +// groups_panel->getChildView("activate_btn")->setEnabled(item_selected && !cur_group_active); // "none" or a non-active group selected // [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f - cur_panel->getChildView("activate_btn")->setEnabled( + groups_panel->getChildView("activate_btn")->setEnabled( item_selected && !cur_group_active && !gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP)); // "none" or a non-active group selected // [/RLVa:KB] + groups_panel->getChildView("minus_btn")->setEnabled(item_selected && selected_id.notNull()); } else { @@ -1689,16 +972,11 @@ void LLPanelPeople::updateButtons() is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; } + LLPanel* cur_panel = mTabContainer->getCurrentPanel(); if (cur_panel) { // cur_panel->getChildView("add_friend_btn")->setEnabled(!is_friend); // [RLVa:KB] - Checked: 2010-07-20 (RLVa-1.2.2a) | Added: RLVa-1.2.0h - - // Ansariel: Changed after add_friend_btn buttons got renamed - //if ( - //cur_panel->getChildView("add_friend_btn")->setEnabled( - // !is_friend && ((!nearby_tab_active) || (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)))); - if (nearby_tab_active) { cur_panel->getChildView("add_friend_btn_nearby")->setEnabled(!is_friend && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); @@ -1757,14 +1035,20 @@ LLUUID LLPanelPeople::getCurrentItemID() const } if (cur_tab == NEARBY_TAB_NAME) + // Adapted for scrolllist + //return mNearbyList->getSelectedUUID(); { LLScrollListItem* item = mRadarList->getFirstSelected(); if (item) + { return item->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID(); + } else + { return LLUUID::null; - //return mNearbyList->getSelectedUUID(); + } } + // if (cur_tab == RECENT_TAB_NAME) return mRecentList->getSelectedUUID(); @@ -1787,14 +1071,15 @@ void LLPanelPeople::getCurrentItemIDs(uuid_vec_t& selected_uuids) const mAllFriendList->getSelectedUUIDs(selected_uuids); } else if (cur_tab == NEARBY_TAB_NAME) - { - // AO, adapted for scrolllist. No multiselect yet + // Adapted for scrolllist //mNearbyList->getSelectedUUIDs(selected_uuids); - for(size_t i=0;igetAllSelected().size();i++) + { + for (size_t i = 0; i < mRadarList->getAllSelected().size(); ++i) { selected_uuids.push_back(mRadarList->getAllSelected().at(i)->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID()); } } + // else if (cur_tab == RECENT_TAB_NAME) mRecentList->getSelectedUUIDs(selected_uuids); else if (cur_tab == GROUP_TAB_NAME) @@ -1810,7 +1095,7 @@ void LLPanelPeople::showGroupMenu(LLMenuGL* menu) // Calculate its coordinates. // (assumes that groups panel is the current tab) - LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild("bottom_panel"); + LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild("bottom_panel"); LLPanel* parent_panel = mTabContainer->getCurrentPanel(); menu->arrangeAndClear(); S32 menu_height = menu->getRect().getHeight(); @@ -1859,8 +1144,10 @@ void LLPanelPeople::setSortOrder(LLAvatarList* list, ESortOrder order, bool save setting = "FriendsSortOrder"; else if (list == mRecentList) setting = "RecentPeopleSortOrder"; - else if (list == mNearbyList) - setting = "NearbyPeopleSortOrder"; + // Not used in Firestorm radar + //else if (list == mNearbyList) + // setting = "NearbyPeopleSortOrder"; + // if (!setting.empty()) gSavedSettings.setU32(setting, order); @@ -1921,10 +1208,10 @@ void LLPanelPeople::onTabSelected(const LLSD& param) showFriendsAccordionsIfNeeded(); - // AO Layout panels will not initialize at a constant size, force it here. + // Layout panels will not initialize at a constant size, force it here. if (tab_name == NEARBY_TAB_NAME) { - LLLayoutPanel* minilayout = (LLLayoutPanel*)getChildView("minimaplayout",true); + LLLayoutPanel* minilayout = (LLLayoutPanel*)getChildView("minimaplayout", true); if (minilayout->getVisible()) { LLRect rec = minilayout->getRect(); @@ -1933,6 +1220,7 @@ void LLPanelPeople::onTabSelected(const LLSD& param) minilayout->setShape(rec,true); } } + // if (GROUP_TAB_NAME == tab_name) mFilterEditor->setLabel(getString("groups_filter_label")); @@ -1949,65 +1237,30 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl) } LLUUID clicked_id = item->getAvatarId(); - LLAvatarActions::startIM(clicked_id); -} - -// Not used; see LLPanelPeople::onRadarListDoubleClicked() -#if 0 -void LLPanelPeople::onNearbyListDoubleClicked(LLUICtrl* ctrl) -{ - LLAvatarListItem* item = dynamic_cast(ctrl); - if(!item) - { - return; - } - LLUUID clicked_id = item->getAvatarId(); - LLAvatarActions::zoomIn(clicked_id); -} +#if 0 // SJB: Useful for testing, but not currently functional or to spec + LLAvatarActions::showProfile(clicked_id); +#else // spec says open IM window + LLAvatarActions::startIM(clicked_id); #endif -// - -void LLPanelPeople::onRadarListDoubleClicked() -{ - LLScrollListItem* item = mRadarList->getFirstSelected(); - if (!item) - { - return; - } - - LLUUID clicked_id = item->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID(); - LLAvatarListItem* avl_item = mNearbyList->getAvatarListItem(clicked_id); - - if (!avl_item) - { - return; - } - - if (avl_item->getRange() <= gSavedSettings.getF32("RenderFarClip")) - { - handle_zoom_to_object(clicked_id, avl_item->getPosition()); - } - else - { - LLStringUtil::format_map_t args; - args["AVATARNAME"] = item->getColumn(mRadarList->getColumn("name")->mIndex)->getValue().asString(); - reportToNearbyChat(getString("camera_no_focus", args)); - } } + void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) { if (getActiveTabName() == NEARBY_TAB_NAME) { uuid_vec_t selected_uuids; + // Firestorm radar //getCurrentItemIDs(selected_uuids); + //mMiniMap->setSelected(selected_uuids) LLUUID sVal = mRadarList->getSelectedValue().asUUID(); - if (sVal != LLUUID::null) + if (sVal.notNull()) { selected_uuids.push_back(sVal); mMiniMap->setSelected(selected_uuids); } + // Firestorm radar } else // Make sure only one of the friends lists (online/all) has selection. if (getActiveTabName() == FRIENDS_TAB_NAME) @@ -2073,45 +1326,6 @@ void LLPanelPeople::onAddFriendWizButtonClicked() } } -void LLPanelPeople::onGlobalVisToggleButtonClicked() -// Iterate through friends lists, toggling status permission on or off -{ - bool vis = getChild("GlobalOnlineStatusToggle")->getValue().asBoolean(); - gSavedSettings.setBOOL("GlobalOnlineStatusToggle", vis); - - const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); - LLAvatarTracker::buddy_map_t all_buddies; - av_tracker.copyBuddyList(all_buddies); - LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); - for (; buddy_it != all_buddies.end(); ++buddy_it) - { - LLUUID buddy_id = buddy_it->first; - const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(buddy_id); - if (relation == NULL) - { - // Lets have a warning log message instead of having a crash. EXT-4947. - llwarns << "Trying to modify rights for non-friend avatar. Skipped." << llendl; - return; - } - - S32 cur_rights = relation->getRightsGrantedTo(); - S32 new_rights = 0; - if (vis) - new_rights = LLRelationship::GRANT_ONLINE_STATUS + (cur_rights & LLRelationship::GRANT_MAP_LOCATION) + (cur_rights & LLRelationship::GRANT_MODIFY_OBJECTS); - else - new_rights = (cur_rights & LLRelationship::GRANT_MAP_LOCATION) + (cur_rights & LLRelationship::GRANT_MODIFY_OBJECTS); - - LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(buddy_id,new_rights); - } - - mAllFriendList->showPermissions(true); - mOnlineFriendList->showPermissions(true); - - LLSD args; - args["MESSAGE"] = getString("high_server_load"); - LLNotificationsUtil::add("GenericAlert", args); -} - void LLPanelPeople::onDeleteFriendButtonClicked() { uuid_vec_t selected_uuids; @@ -2138,40 +1352,6 @@ void LLPanelPeople::onChatButtonClicked() if (group_id.notNull()) LLGroupActions::startIM(group_id); } -void LLPanelPeople::requestRadarChannelAlertSync() -{ - F32 timeNow = gFrameTimeSeconds; - if( (timeNow - RADAR_CHAT_MIN_SPACING)>mRadarLastRequestTime) - { - mRadarLastRequestTime=timeNow; - mRadarAlertRequest = true; - } -} - -void LLPanelPeople::teleportToAvatar(LLUUID targetAv) -// Teleports user to last scanned location of nearby avatar -// Note: currently teleportViaLocation is disrupted by enforced landing points set on a parcel. -{ - std::vector items; - mNearbyList->getItems(items); - for (std::vector::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) - { - LLAvatarListItem* av = static_cast(*itItem); - if (av->getAvatarId() == targetAv) - { - LLVector3d avpos = av->getPosition(); - if (avpos.mdV[VZ] == -1) - { - LLNotificationsUtil::add("TeleportToAvatarNotPossible"); - } - else - { - gAgent.teleportViaLocation(avpos); - } - return; - } - } -} void LLPanelPeople::onImButtonClicked() { @@ -2288,23 +1468,26 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata) { std::string chosen_item = userdata.asString(); - if (chosen_item == "sort_by_recent_speakers") - { - setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS); - } - else if (chosen_item == "sort_name") - { - setSortOrder(mNearbyList, E_SORT_BY_NAME); - } - else if (chosen_item == "view_icons") - { - mNearbyList->toggleIcons(); - } - else if (chosen_item == "sort_distance") - { - setSortOrder(mNearbyList, E_SORT_BY_DISTANCE); - } - else if (chosen_item == "panel_block_list_sidetray") + // Firestorm radar + //if (chosen_item == "sort_by_recent_speakers") + //{ + // setSortOrder(mNearbyList, E_SORT_BY_RECENT_SPEAKERS); + //} + //else if (chosen_item == "sort_name") + //{ + // setSortOrder(mNearbyList, E_SORT_BY_NAME); + //} + //else if (chosen_item == "view_icons") + //{ + // mNearbyList->toggleIcons(); + //} + //else if (chosen_item == "sort_distance") + //{ + // setSortOrder(mNearbyList, E_SORT_BY_DISTANCE); + //} + //else if (chosen_item == "panel_block_list_sidetray") + if (chosen_item == "panel_block_list_sidetray") + // Firestorm radar { // Optional standalone blocklist floater //LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD()); @@ -2367,121 +1550,6 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata) } } -void LLPanelPeople::onRadarNameFmtClicked(const LLSD& userdata) -{ - std::string chosen_item = userdata.asString(); - if (chosen_item == "DN") - gSavedSettings.setU32("RadarNameFormat", NAMEFORMAT_DISPLAYNAME); - else if (chosen_item == "UN") - gSavedSettings.setU32("RadarNameFormat", NAMEFORMAT_USERNAME); - else if (chosen_item == "DNUN") - gSavedSettings.setU32("RadarNameFormat", NAMEFORMAT_DISPLAYNAME_USERNAME); - else if (chosen_item == "UNDN") - gSavedSettings.setU32("RadarNameFormat", NAMEFORMAT_USERNAME_DISPLAYNAME); -} - -bool LLPanelPeople::radarNameFmtCheck(const LLSD& userdata) -{ - std::string menu_item = userdata.asString(); - U32 name_format = gSavedSettings.getU32("RadarNameFormat"); - switch (name_format) - { - case NAMEFORMAT_DISPLAYNAME: - return (menu_item == "DN"); - case NAMEFORMAT_USERNAME: - return (menu_item == "UN"); - case NAMEFORMAT_DISPLAYNAME_USERNAME: - return (menu_item == "DNUN"); - case NAMEFORMAT_USERNAME_DISPLAYNAME: - return (menu_item == "UNDN"); - default: - break; - } - return false; -} - -// Milkshake-style radar alerts -void LLPanelPeople::onRadarReportToClicked(const LLSD& userdata) -{ - std::string chosen_item = userdata.asString(); - if (chosen_item == "radar_toasts") - gSavedSettings.setBOOL("FSMilkshakeRadarToasts", TRUE); - else if (chosen_item == "radar_nearby_chat") - gSavedSettings.setBOOL("FSMilkshakeRadarToasts", FALSE); -} - -bool LLPanelPeople::radarReportToCheck(const LLSD& userdata) -{ - std::string menu_item = userdata.asString(); - bool report_to = gSavedSettings.getBOOL("FSMilkshakeRadarToasts"); - if (report_to) - return (menu_item == "radar_toasts"); - else - return (menu_item == "radar_nearby_chat"); -} -// - -std::string LLPanelPeople::getRadarName(LLAvatarName avname) -{ -// [RLVa:KB-FS] - Checked: 2011-06-11 (RLVa-1.3.1) | Added: RLVa-1.3.1 - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - return RlvStrings::getAnonym(avname); - } -// [/RLVa:KB-FS] - - U32 fmt = gSavedSettings.getU32("RadarNameFormat"); - // if display names are enabled, allow a variety of formatting options, depending on menu selection - if (gSavedSettings.getBOOL("UseDisplayNames")) - { - if (fmt == NAMEFORMAT_DISPLAYNAME) - { - return avname.mDisplayName; - } - else if (fmt == NAMEFORMAT_USERNAME) - { - return avname.mUsername; - } - else if (fmt == NAMEFORMAT_DISPLAYNAME_USERNAME) - { - std::string s1 = avname.mDisplayName; - to_lower(s1); - std::string s2 = avname.mUsername; - replace_all(s2,"."," "); - if (s1.compare(s2) == 0) - return avname.mDisplayName; - else - return llformat("%s (%s)",avname.mDisplayName.c_str(),avname.mUsername.c_str()); - } - else if (fmt == NAMEFORMAT_USERNAME_DISPLAYNAME) - { - std::string s1 = avname.mDisplayName; - to_lower(s1); - std::string s2 = avname.mUsername; - replace_all(s2,"."," "); - if (s1.compare(s2) == 0) - return avname.mDisplayName; - else - return llformat("%s (%s)",avname.mUsername.c_str(),avname.mDisplayName.c_str()); - } - } - - // else use legacy name lookups - return avname.mDisplayName; // will be mapped to legacyname automatically by the name cache -} - -std::string LLPanelPeople::getRadarName(LLUUID avId) -{ - LLAvatarName avname; - - if (LLAvatarNameCache::get(avId,&avname)) // use the synchronous call. We poll every second so there's less value in using the callback form. - return getRadarName(avname); - - // name not found. Temporarily fill in with the UUID. It's more distinguishable than (loading...) - return avId.asString(); - -} - bool LLPanelPeople::onFriendsViewSortMenuItemCheck(const LLSD& userdata) { std::string item = userdata.asString(); @@ -2534,7 +1602,10 @@ void LLPanelPeople::onTeleportButtonClicked() { uuid_vec_t selected_uuids; getCurrentItemIDs(selected_uuids); + // Firestorm change + //LLAvatarActions::offerTeleport(selected_uuids); LLAvatarActions::offerTeleport(LLAvatarActions::canOfferTeleport(selected_uuids)); + // Firestorm change } void LLPanelPeople::onShareButtonClicked() @@ -2547,38 +1618,6 @@ void LLPanelPeople::onMoreButtonClicked() // *TODO: not implemented yet } -void LLPanelPeople::onFriendsViewSortButtonClicked() -{ - LLMenuGL* menu = (LLMenuGL*)mFriendsViewSortMenuHandle.get(); - if (!menu) - return; - showGroupMenu(menu); -} - -void LLPanelPeople::onGroupsViewSortButtonClicked() -{ - LLMenuGL* menu = (LLMenuGL*)mGroupsViewSortMenuHandle.get(); - if (!menu) - return; - showGroupMenu(menu); -} - -void LLPanelPeople::onRecentViewSortButtonClicked() -{ - LLMenuGL* menu = (LLMenuGL*)mRecentViewSortMenuHandle.get(); - if (!menu) - return; - showGroupMenu(menu); -} - -void LLPanelPeople::onNearbyViewSortButtonClicked() -{ - LLMenuGL* menu = (LLMenuGL*)mNearbyViewSortMenuHandle.get(); - if (!menu) - return; - showGroupMenu(menu); -} - void LLPanelPeople::onOpen(const LLSD& key) { std::string tab_name = key["people_panel_tab_name"]; @@ -2702,43 +1741,159 @@ bool LLPanelPeople::isAccordionCollapsedByUser(const std::string& name) return isAccordionCollapsedByUser(getChild(name)); } -// Avatar tracking feature -void LLPanelPeople::startTracking(const LLUUID& avatar_id) +// Firestorm radar +void LLPanelPeople::onRadarListDoubleClicked() { - mTrackedAvatarId = avatar_id; - updateTracking(); -} - -void LLPanelPeople::checkTracking() -{ - if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION - && LLTracker::getTrackedLocationType() == LLTracker::LOCATION_AVATAR) + LLScrollListItem* item = mRadarList->getFirstSelected(); + if (!item) { - updateTracking(); + return; + } + + LLUUID clicked_id = item->getColumn(mRadarList->getColumn("uuid")->mIndex)->getValue().asUUID(); + std::string name = item->getColumn(mRadarList->getColumn("name")->mIndex)->getValue().asString(); + + FSRadar* radar = FSRadar::getInstance(); + if (radar) + { + radar->zoomAvatar(clicked_id, name); } } -void LLPanelPeople::updateTracking() +void LLPanelPeople::updateNearby(const std::vector& entries, const LLSD& stats) { - std::multimap::const_iterator it; - it = lastRadarSweep.find(mTrackedAvatarId); - if (it != lastRadarSweep.end()) + if (!LLFloaterReg::instanceVisible("people") || getActiveTabName() != NEARBY_TAB_NAME) { - if (LLTracker::getTrackedPositionGlobal() != it->second.lastGlobalPos) + return; + } + + if (!mRadarList) + { + return; + } + + // Store current selection and scroll position + static S32 uuidColumnIndex = mRadarList->getColumn("uuid")->mIndex; + std::vector selected_items = mRadarList->getAllSelected(); + uuid_vec_t selected_ids; + for (size_t i = 0; i < selected_items.size(); i++) + { + selected_ids.push_back(selected_items.at(i)->getColumn(uuidColumnIndex)->getValue().asUUID()); + } + S32 lastScroll = mRadarList->getScrollPos(); + + // Update list + mRadarList->clearRows(); + const std::vector::const_iterator it_end = entries.end(); + for (std::vector::const_iterator it = entries.begin(); it != it_end; ++it) + { + LLSD entry = (*it)["entry"]; + LLSD options = (*it)["options"]; + + LLSD row_data; + row_data["value"] = entry["id"]; + row_data["columns"][0]["column"] = "name"; + row_data["columns"][0]["value"] = entry["name"]; + row_data["columns"][1]["column"] = "voice_level"; + row_data["columns"][1]["type"] = "icon"; + row_data["columns"][1]["value"] = ""; // Need to set it after the row has been created because it's to big for the row + row_data["columns"][2]["column"] = "in_region"; + row_data["columns"][2]["type"] = "icon"; + row_data["columns"][2]["value"] = (entry["in_region"].asBoolean() ? "avatar_in_region" : ""); + row_data["columns"][3]["column"] = "flags"; + row_data["columns"][3]["value"] = entry["flags"]; + row_data["columns"][4]["column"] = "age"; + row_data["columns"][4]["value"] = entry["age"]; + row_data["columns"][5]["column"] = "seen"; + row_data["columns"][5]["value"] = entry["seen"]; + row_data["columns"][6]["column"] = "range"; + row_data["columns"][6]["value"] = entry["range"]; + row_data["columns"][7]["column"] = "uuid"; // invisible column for referencing av-key the row belongs to + row_data["columns"][7]["value"] = entry["id"]; + + LLScrollListItem* row = mRadarList->addElement(row_data); + + static S32 rangeColumnIndex = mRadarList->getColumn("range")->mIndex; + static S32 nameColumnIndex = mRadarList->getColumn("name")->mIndex; + static S32 voiceLevelColumnIndex = mRadarList->getColumn("voice_level")->mIndex; + + LLScrollListText* radarRangeCell = (LLScrollListText*)row->getColumn(rangeColumnIndex); + radarRangeCell->setColor(LLColor4(options["range_color"])); + radarRangeCell->setFontStyle(options["range_style"].asInteger()); + + LLScrollListText* radarNameCell = (LLScrollListText*)row->getColumn(nameColumnIndex); + radarNameCell->setFontStyle(options["name_style"].asInteger()); + if (options.has("name_color")) { - std::string targetName(it->second.avName); - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - targetName = RlvStrings::getAnonym(targetName); - } - LLTracker::trackLocation(it->second.lastGlobalPos, targetName, "", LLTracker::LOCATION_AVATAR); + radarNameCell->setColor(LLColor4(options["name_color"])); + } + + LLScrollListText* voiceLevelCell = (LLScrollListText*)row->getColumn(voiceLevelColumnIndex); + if (entry.has("voice_level_icon")) + { + voiceLevelCell->setValue(entry["voice_level_icon"].asString()); } } - else + + LLStringUtil::format_map_t name_count_args; + name_count_args["[TOTAL]"] = stats["total"].asString(); + name_count_args["[IN_REGION]"] = stats["region"].asString(); + name_count_args["[IN_CHAT_RANGE]"] = stats["chatrange"].asString(); + LLScrollListColumn* column = mRadarList->getColumn("name"); + column->mHeader->setLabel(getString("avatar_name_count", name_count_args)); + column->mHeader->setToolTipArgs(name_count_args); + + // Restore scroll position + mRadarList->setScrollPos(lastScroll); + + // Restore selection list + if (!selected_ids.empty()) { - LLTracker::stopTracking(NULL); + mRadarList->selectMultiple(selected_ids); } + + updateButtons(); } -// Avatar tracking feature + + +void LLPanelPeople::onGlobalVisToggleButtonClicked() +// Iterate through friends lists, toggling status permission on or off +{ + bool vis = getChild("GlobalOnlineStatusToggle")->getValue().asBoolean(); + gSavedSettings.setBOOL("GlobalOnlineStatusToggle", vis); + + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + LLAvatarTracker::buddy_map_t all_buddies; + av_tracker.copyBuddyList(all_buddies); + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + for (; buddy_it != all_buddies.end(); ++buddy_it) + { + LLUUID buddy_id = buddy_it->first; + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(buddy_id); + if (relation == NULL) + { + // Lets have a warning log message instead of having a crash. EXT-4947. + llwarns << "Trying to modify rights for non-friend avatar. Skipped." << llendl; + return; + } + + S32 cur_rights = relation->getRightsGrantedTo(); + S32 new_rights = 0; + if (vis) + new_rights = LLRelationship::GRANT_ONLINE_STATUS + (cur_rights & LLRelationship::GRANT_MAP_LOCATION) + (cur_rights & LLRelationship::GRANT_MODIFY_OBJECTS); + else + new_rights = (cur_rights & LLRelationship::GRANT_MAP_LOCATION) + (cur_rights & LLRelationship::GRANT_MODIFY_OBJECTS); + + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(buddy_id,new_rights); + } + + mAllFriendList->showPermissions(true); + mOnlineFriendList->showPermissions(true); + + LLSD args; + args["MESSAGE"] = getString("high_server_load"); + LLNotificationsUtil::add("GenericAlert", args); +} +// Firestorm radar // EOF diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 26521162ea..01aed84839 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -31,29 +31,17 @@ #include "llcallingcard.h" // for avatar tracker #include "llvoiceclient.h" -#include "llavatarnamecache.h" -#include "llscrolllistctrl.h" -#include "fsradarlistctrl.h" -#include -#include class LLAvatarList; class LLAvatarName; class LLFilterEditor; class LLGroupList; -class LLTabContainer; class LLMenuButton; +class LLTabContainer; + +// Firestorm declarations class LLMenuGL; - -const U32 MAX_AVATARS_PER_ALERT = 6; // maximum number of UUIDs we can cram into a single channel radar alert message -const U32 COARSE_OFFSET_INTERVAL = 7; // seconds after which we query the bridge for a coarse location adjustment -const U32 MAX_OFFSET_REQUESTS = 60; // 2048 / UUID size, leaving overhead space -const U32 NAMEFORMAT_DISPLAYNAME = 0; -const U32 RADAR_CHAT_MIN_SPACING = 6; //minimum delay between radar chat messages - -const U32 NAMEFORMAT_USERNAME = 1; -const U32 NAMEFORMAT_DISPLAYNAME_USERNAME = 2; -const U32 NAMEFORMAT_USERNAME_DISPLAYNAME = 3; +class FSRadarListCtrl; class LLPanelPeople : public LLPanel @@ -67,17 +55,17 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ bool notifyChildren(const LLSD& info); - void teleportToAvatar(LLUUID targetAv); - void requestRadarChannelAlertSync(); // Implements LLVoiceClientStatusObserver::onChange() to enable call buttons // when voice is available /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); // [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.0d) | Added: RLVa-1.2.0d - LLAvatarList* getNearbyList() { return mNearbyList; } + // Externalized to FSRadar + //LLAvatarList* getNearbyList() { return mNearbyList; } // [/RLVa:KB] - void startTracking(const LLUUID& avatar_id); + // Firestorm radar + void updateNearby(const std::vector& entries, const LLSD& stats); // internals class Updater; @@ -97,10 +85,7 @@ private: void updateFriendList(); void updateNearbyList(); void updateRecentList(); - void updateNearbyRange(); - void updateTracking(); - void checkTracking(); - + bool isItemsFreeOfFriends(const uuid_vec_t& uuids); void updateButtons(); @@ -112,10 +97,6 @@ private: void buttonSetAction(const std::string& btn_name, const commit_signal_t::slot_type& cb); void showGroupMenu(LLMenuGL* menu); void setSortOrder(LLAvatarList* list, ESortOrder order, bool save = true); - void handleLimitRadarByRange(const LLSD& newalue); - std::string getRadarName(LLUUID avId); - std::string getRadarName(LLAvatarName avName); - void radarAlertMsg(const LLUUID& agent_id, const LLAvatarName& av_name,std::string postMsg); // UI callbacks void onFilterEdit(const std::string& search_string); @@ -123,7 +104,6 @@ private: void onViewProfileButtonClicked(); void onAddFriendButtonClicked(); void onAddFriendWizButtonClicked(); - void onGlobalVisToggleButtonClicked(); void onDeleteFriendButtonClicked(); void onGroupInfoButtonClicked(); void onChatButtonClicked(); @@ -134,14 +114,8 @@ private: void onShareButtonClicked(); void onMoreButtonClicked(); void onActivateButtonClicked(); - void onRecentViewSortButtonClicked(); - void onNearbyViewSortButtonClicked(); - void onFriendsViewSortButtonClicked(); - void onGroupsViewSortButtonClicked(); void onAvatarListDoubleClicked(LLUICtrl* ctrl); - void onNearbyListDoubleClicked(LLUICtrl* ctrl); void onAvatarListCommitted(LLAvatarList* list); - void onRadarListDoubleClicked(); void onGroupPlusButtonClicked(); void onGroupMinusButtonClicked(); void onGroupPlusMenuItemClicked(const LLSD& userdata); @@ -150,10 +124,6 @@ private: void onNearbyViewSortMenuItemClicked(const LLSD& userdata); void onGroupsViewSortMenuItemClicked(const LLSD& userdata); void onRecentViewSortMenuItemClicked(const LLSD& userdata); - void onRadarNameFmtClicked(const LLSD& userdata); - bool radarNameFmtCheck(const LLSD& userdata); - void onRadarReportToClicked(const LLSD& userdata); // Milkshake-style Radar Alerts - bool radarReportToCheck(const LLSD& userdata); // Milkshake-style Radar Alerts //returns false only if group is "none" bool isRealGroup(); @@ -177,14 +147,21 @@ private: bool isAccordionCollapsedByUser(LLUICtrl* acc_tab); bool isAccordionCollapsedByUser(const std::string& name); + // Firestorm callback handler + void onRadarListDoubleClicked(); + void onGlobalVisToggleButtonClicked(); + // Firestorm callback handler + LLFilterEditor* mFilterEditor; LLTabContainer* mTabContainer; LLAvatarList* mOnlineFriendList; LLAvatarList* mAllFriendList; LLAvatarList* mNearbyList; + // Firestorm radar + FSRadarListCtrl* mRadarList; + // Firestorm radar LLAvatarList* mRecentList; LLGroupList* mGroupList; - FSRadarListCtrl* mRadarList; LLNetMap* mMiniMap; LLHandle mGroupPlusMenuHandle; @@ -194,7 +171,9 @@ private: LLHandle mRecentViewSortMenuHandle; Updater* mFriendListUpdater; - Updater* mNearbyListUpdater; + // Firestorm radar + //Updater* mNearbyListUpdater; + // Firestorm radar Updater* mRecentListUpdater; Updater* mButtonsUpdater; @@ -205,34 +184,9 @@ private: std::string mFilterSubString; std::string mFilterSubStringOrig; - - LLUIColor mChatRangeColor; - LLUIColor mShoutRangeColor; - LLUIColor mFarRangeColor; - - struct radarFields - { - std::string avName; - F32 lastDistance; - LLVector3d lastGlobalPos; - LLUUID lastRegion; - time_t firstSeen; - S32 lastStatus; - U32 ZOffset; - time_t lastZOffsetTime; - - }; - std::multimap < LLUUID, radarFields > lastRadarSweep; - std::vector mRadarEnterAlerts; - std::vector mRadarLeaveAlerts; - std::vector mRadarOffsetRequests; - - S32 mRadarFrameCount; - bool mRadarAlertRequest; - F32 mRadarLastRequestTime; - U32 mRadarLastBulkOffsetRequestTime; - LLUUID mTrackedAvatarId; + // Firestorm radar + boost::signals2::connection mNearbyUpdateSignalConnection; }; #endif //LL_LLPANELPEOPLE_H diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp index e633d43f7a..0508d41875 100644 --- a/indra/newview/llpanelpeoplemenus.cpp +++ b/indra/newview/llpanelpeoplemenus.cpp @@ -38,9 +38,6 @@ #include "llavataractions.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llviewermenu.h" // for gMenuHolder -#include "llpanelpeople.h" - -#include "fscommon.h" namespace LLPanelPeopleMenus { @@ -66,35 +63,13 @@ LLContextMenu* NearbyMenu::createMenu() registrar.add("Avatar.IM", boost::bind(&LLAvatarActions::startIM, id)); registrar.add("Avatar.Call", boost::bind(&LLAvatarActions::startCall, id)); registrar.add("Avatar.OfferTeleport", boost::bind(&NearbyMenu::offerTeleport, this)); - registrar.add("Avatar.GroupInvite", boost::bind(&LLAvatarActions::inviteToGroup, id)); - registrar.add("Avatar.getScriptInfo", boost::bind(&LLAvatarActions::getScriptInfo, id)); registrar.add("Avatar.ShowOnMap", boost::bind(&LLAvatarActions::showOnMap, id)); registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::share, id)); registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, id)); registrar.add("Avatar.BlockUnblock", boost::bind(&LLAvatarActions::toggleBlock, id)); - // [SL:KB] - Patch: UI-SidepanelPeople | Checked: 2010-12-03 (Catznip-2.4.0g) | Modified: Catznip-2.4.0g - registrar.add("Avatar.ZoomIn", boost::bind(&LLAvatarActions::zoomIn, id)); - enable_registrar.add("Avatar.VisibleZoomIn", boost::bind(&LLAvatarActions::canZoomIn, id)); - registrar.add("Avatar.Report", boost::bind(&LLAvatarActions::report, id)); - registrar.add("Avatar.Eject", boost::bind(&LLAvatarActions::landEject, id)); - registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::landFreeze, id)); - enable_registrar.add("Avatar.VisibleFreezeEject", boost::bind(&LLAvatarActions::canLandFreezeOrEject, id)); - registrar.add("Avatar.Kick", boost::bind(&LLAvatarActions::estateKick, id)); - registrar.add("Avatar.TeleportHome", boost::bind(&LLAvatarActions::estateTeleportHome, id)); - enable_registrar.add("Avatar.VisibleKickTeleportHome", boost::bind(&LLAvatarActions::canEstateKickOrTeleportHome, id)); - // [/SL:KB] - // Estate ban user - registrar.add("Avatar.EstateBan", boost::bind(&LLAvatarActions::estateBan, id)); - // Derender - registrar.add("Avatar.Derender", boost::bind(&LLAvatarActions::derender, id, false)); - registrar.add("Avatar.DerenderPermanent", boost::bind(&LLAvatarActions::derender, id, true)); - // Derender - - registrar.add("Nearby.People.TeleportToAvatar", boost::bind(&NearbyMenu::teleportToAvatar, this)); - registrar.add("Nearby.People.TrackAvatar", boost::bind(&NearbyMenu::onTrackAvatarMenuItemClick, this)); + // Firestorm additions + registrar.add("Avatar.GroupInvite", boost::bind(&LLAvatarActions::inviteToGroup, id)); - registrar.add("Avatar.ZoomIn", boost::bind(&LLAvatarActions::zoomIn, id)); - enable_registrar.add("Avatar.VisibleZoomIn", boost::bind(&LLAvatarActions::canZoomIn, id)); enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2)); enable_registrar.add("Avatar.CheckItem", boost::bind(&NearbyMenu::checkContextMenuItem, this, _2)); @@ -113,21 +88,7 @@ LLContextMenu* NearbyMenu::createMenu() // registrar.add("Avatar.Share", boost::bind(&LLAvatarActions::startIM, mUUIDs)); // *TODO: unimplemented // registrar.add("Avatar.Pay", boost::bind(&LLAvatarActions::pay, mUUIDs)); // *TODO: unimplemented enable_registrar.add("Avatar.EnableItem", boost::bind(&NearbyMenu::enableContextMenuItem, this, _2)); - // [SL:KB] - Patch: UI-SidepanelPeople | Checked: 2010-11-05 (Catznip-2.4.0g) | Added: Catznip-2.4.0g - registrar.add("Avatar.Eject", boost::bind(&LLAvatarActions::landEjectMultiple, mUUIDs)); - registrar.add("Avatar.Freeze", boost::bind(&LLAvatarActions::landFreezeMultiple, mUUIDs)); - enable_registrar.add("Avatar.VisibleFreezeEject", boost::bind(&LLAvatarActions::canLandFreezeOrEjectMultiple, mUUIDs, false)); - registrar.add("Avatar.Kick", boost::bind(&LLAvatarActions::estateKickMultiple, mUUIDs)); - registrar.add("Avatar.TeleportHome", boost::bind(&LLAvatarActions::estateTeleportHomeMultiple, mUUIDs)); - enable_registrar.add("Avatar.VisibleKickTeleportHome", boost::bind(&LLAvatarActions::canEstateKickOrTeleportHomeMultiple, mUUIDs, false)); - // [/SL:KB] - // Estate ban user - registrar.add("Avatar.EstateBan", boost::bind(&LLAvatarActions::estateBanMultiple, mUUIDs)); - // Derender - registrar.add("Avatar.Derender", boost::bind(&LLAvatarActions::derenderMultiple, mUUIDs, false)); - registrar.add("Avatar.DerenderPermanent", boost::bind(&LLAvatarActions::derenderMultiple, mUUIDs, true)); - // Derender - + // create the context menu from the XUI return createFromFile("menu_people_nearby_multiselect.xml"); } @@ -238,26 +199,5 @@ void NearbyMenu::offerTeleport() // so we have to use a wrapper. LLAvatarActions::offerTeleport(mUUIDs); } - -void NearbyMenu::teleportToAvatar() -// AO: wrapper for functionality managed by LLPanelPeople, because it manages the nearby avatar list. -// Will only work for avatars within radar range. -{ - LLPanelPeople* peoplePanel = getPeoplePanel(); - if (peoplePanel) - { - peoplePanel->teleportToAvatar(mUUIDs.front()); - } -} - -// Ansariel: Avatar tracking feature -void NearbyMenu::onTrackAvatarMenuItemClick() -{ - LLPanelPeople* peoplePanel = getPeoplePanel(); - if (peoplePanel) - { - peoplePanel->startTracking(mUUIDs.front()); - } -} } // namespace LLPanelPeopleMenus diff --git a/indra/newview/llpanelpeoplemenus.h b/indra/newview/llpanelpeoplemenus.h index 6bdff42e02..d51eaec716 100644 --- a/indra/newview/llpanelpeoplemenus.h +++ b/indra/newview/llpanelpeoplemenus.h @@ -43,8 +43,6 @@ private: bool enableContextMenuItem(const LLSD& userdata); bool checkContextMenuItem(const LLSD& userdata); void offerTeleport(); - void teleportToAvatar(); - void onTrackAvatarMenuItemClick(); }; extern NearbyMenu gNearbyMenu; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 2a4c77ae38..64e9e85f31 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -219,6 +219,7 @@ #include "fsdata.h" #include "fsfloatersearch.h" #include "fslslbridge.h" +#include "fsradar.h" #include "fswsassetblacklist.h" #include "llfloatersearch.h" #include "llfloatersidepanelcontainer.h" @@ -1680,12 +1681,15 @@ LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim, first_sim_size_x, llinfos << "Constructed " << pContacts->getTitle() << llendl; // - // FIRE-8560/FIRE-8592: We neet to create the instance of the people - // floater for the radar functions and the V2 friendlist here. + // FIRE-8560/FIRE-8592: We neet to create the instance of the radar + // for the radar functions and the V2 friendlist here. // This is because of the standalone group panels that will // prevent doing this at login when receiving the agent group // data update. LLFloaterSidePanelContainer::getPanel("people", "panel_people"); + FSRadar::instance(); + llinfos << "Radar initialized" << llendl; + // //gCacheName is required for nearby chat history loading //so I just moved nearby history loading a few states further diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 92dfdf982e..5f069b679c 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -162,6 +162,7 @@ #include "fsfloaterplacedetails.h" #include "fsfloaterposestand.h" #include "fsfloaterprofile.h" +#include "fsfloaterradar.h" #include "fsfloatersearch.h" #include "fsfloaterteleporthistory.h" #include "fsfloatervolumecontrols.h" @@ -395,6 +396,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("fs_import", "floater_fs_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_posestand", "floater_fs_posestand.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_placedetails", "floater_fs_placedetails.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("fs_radar", "floater_fs_radar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_teleporthistory", "floater_fs_teleporthistory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_volume_controls", "floater_fs_volume_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("group_titles", "floater_fs_group_titles.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 40836fc1c6..ef41e7e5c3 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -153,6 +153,7 @@ const static boost::regex NEWLINES("\\n{1}"); #include "tea.h" // #include "fscommon.h" #include "fslightshare.h" // FIRE-5118 - Lightshare support +#include "fsradar.h" #if LL_MSVC // disable boost::lexical_cast warning @@ -5591,10 +5592,10 @@ void process_sound_trigger(LLMessageSystem *msg, void **) // sound assets as a request for a full radar update to a channel if ((owner_id == gAgent.getID()) && (sound_id.asString() == gSavedSettings.getString("RadarLegacyChannelAlertRefreshUUID"))) { - LLPanelPeople* pPeoplePanel = getPeoplePanel(); - if (pPeoplePanel) + FSRadar* radar = FSRadar::getInstance(); + if (radar) { - pPeoplePanel->requestRadarChannelAlertSync(); + radar->requestRadarChannelAlertSync(); } return; } diff --git a/indra/newview/rlvui.cpp b/indra/newview/rlvui.cpp index 0e47ef9221..d75f32b9e0 100644 --- a/indra/newview/rlvui.cpp +++ b/indra/newview/rlvui.cpp @@ -47,6 +47,8 @@ #include "rlvhandler.h" #include "rlvextensions.h" +#include "fsradar.h" + // ============================================================================ // Checked: 2010-02-28 (RLVa-1.4.0a) | Added: RLVa-1.2.0a @@ -364,10 +366,16 @@ void RlvUIEnabler::onToggleShowNames(bool fQuitting) bool fEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); // Refresh the nearby people list - LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel("people", "panel_people"); - RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); - if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ) - pPeoplePanel->getNearbyList()->updateAvatarNames(); + // [Standalone radar] + //LLPanelPeople* pPeoplePanel = LLFloaterSidePanelContainer::getPanel("people", "panel_people"); + //RLV_ASSERT( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ); + //if ( (pPeoplePanel) && (pPeoplePanel->getNearbyList()) ) + // pPeoplePanel->getNearbyList()->updateAvatarNames(); + FSRadar* pRadar = FSRadar::getInstance(); + RLV_ASSERT( (pRadar) && (pRadar->getNearbyList()) ); + if ( (pRadar) && (pRadar->getNearbyList()) ) + pRadar->getNearbyList()->updateAvatarNames(); + // [Standalone radar] // Refresh the speaker list // [FS communication UI] diff --git a/indra/newview/skins/ansastorm/xui/en/floater_fs_radar.xml b/indra/newview/skins/ansastorm/xui/en/floater_fs_radar.xml new file mode 100644 index 0000000000..a7bf7e35cc --- /dev/null +++ b/indra/newview/skins/ansastorm/xui/en/floater_fs_radar.xml @@ -0,0 +1,342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +