summaryrefslogtreecommitdiff
path: root/indra/newview/llviewermenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewermenu.cpp')
-rw-r--r--indra/newview/llviewermenu.cpp258
1 files changed, 244 insertions, 14 deletions
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ce4c32e34e..86e3fe6eca 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -33,6 +33,7 @@
#include "llviewermenu.h"
// linden library includes
+#include "indra_constants.h"
#include "llavatarnamecache.h" // IDEVO (I Are Not Men!)
#include "llcombobox.h"
#include "llcoros.h"
@@ -56,6 +57,7 @@
// [SL:KB] - Patch: Appearance-PhantomAttach | Checked: Catznip-5.0
#include "llattachmentsmgr.h"
// [/SL:KB]
+#include "llavataractions.h"
#include "llcompilequeue.h"
#include "llconsole.h"
#include "lldebugview.h"
@@ -75,6 +77,7 @@
#include "llfloaterpathfindingcharacters.h"
#include "llfloaterpathfindinglinksets.h"
#include "llfloaterpay.h"
+#include "llfloaterpreference.h"
#include "llfloaterreporter.h"
#include "llfloatersearch.h"
#include "llfloaterscriptdebug.h"
@@ -83,9 +86,8 @@
#include "llfloatertools.h"
#include "llfloaterworldmap.h"
#include "llfloaterbuildoptions.h"
-#include "llavataractions.h"
-#include "lllandmarkactions.h"
#include "llgroupmgr.h"
+#include "lllandmarkactions.h"
#include "lltooltip.h"
#include "lltoolface.h"
#include "llhints.h"
@@ -1009,17 +1011,36 @@ class LLAdvancedToggleFeature : public view_listener_t
class LLAdvancedCheckFeature : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
-{
- U32 feature = feature_from_string( userdata.asString() );
- bool new_value = false;
+ {
+ U32 feature = feature_from_string( userdata.asString() );
+ bool new_value = false;
- if ( feature != 0 )
+ if ( feature != 0 )
+ {
+ new_value = LLPipeline::toggleRenderDebugFeatureControl( feature );
+ }
+
+ return new_value;
+ }
+};
+
+class LLAdvancedToggleExperiment : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
{
- new_value = LLPipeline::toggleRenderDebugFeatureControl( feature );
+ std::string feature = userdata.asString();
+ return false;
}
+};
- return new_value;
-}
+class LLAdvancedCheckExperiment : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool value = false;
+ std::string feature = userdata.asString();
+ return value;
+ }
};
class LLAdvancedCheckDisplayTextureDensity : public view_listener_t
@@ -3409,6 +3430,161 @@ bool enable_attachment_touch(const LLUUID& inv_item_id)
return false;
}
+static void copy_text_to_clipboard(const std::string& text)
+{
+ if (text.empty() || !gViewerWindow || !gViewerWindow->getWindow())
+ {
+ return;
+ }
+ gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(text));
+}
+
+static LLViewerObject* selected_pick_object()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ return selection ? selection->getPrimaryObject() : nullptr;
+}
+
+// Root first, then each non-avatar child in child-list order. That is the
+// same order the viewer uses for link numbers (root is link 1).
+static void collect_linkset_objects(LLViewerObject* object, std::vector<LLViewerObject*>& links)
+{
+ links.clear();
+ if (!object || object->isAvatar())
+ {
+ return;
+ }
+ LLViewerObject* root = object->getRootEdit();
+ if (!root || root->isAvatar())
+ {
+ return;
+ }
+ root->addThisAndNonJointChildren(links);
+}
+
+static bool object_is_linkset()
+{
+ std::vector<LLViewerObject*> links;
+ collect_linkset_objects(selected_pick_object(), links);
+ return links.size() > 1;
+}
+
+static void handle_object_copy_uuid()
+{
+ LLViewerObject* object = selected_pick_object();
+ if (!object || object->isAvatar())
+ {
+ return;
+ }
+ copy_text_to_clipboard(object->getID().asString());
+}
+
+static void handle_object_copy_linkset_uuids()
+{
+ std::vector<LLViewerObject*> links;
+ collect_linkset_objects(selected_pick_object(), links);
+ if (links.size() < 2)
+ {
+ return;
+ }
+
+ std::string text;
+ for (LLViewerObject* link : links)
+ {
+ if (!link)
+ {
+ continue;
+ }
+ if (!text.empty())
+ {
+ text += ", ";
+ }
+ text += link->getID().asString();
+ }
+ copy_text_to_clipboard(text);
+}
+
+static void append_unique_selected_object(std::vector<LLViewerObject*>& objects, LLViewerObject* object)
+{
+ if (!object || object->isAvatar())
+ {
+ return;
+ }
+ for (LLViewerObject* existing : objects)
+ {
+ if (existing == object)
+ {
+ return;
+ }
+ }
+ objects.push_back(object);
+}
+
+// Family roots cover shift-selected objects. Individual nodes cover
+// Edit Linked Parts, where each prim is selected on its own.
+static void collect_multi_selected_objects(std::vector<LLViewerObject*>& objects)
+{
+ objects.clear();
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ if (!selection)
+ {
+ return;
+ }
+
+ for (LLObjectSelection::root_iterator it = selection->root_begin(); it != selection->root_end(); ++it)
+ {
+ append_unique_selected_object(objects, (*it)->getObject());
+ }
+ for (LLObjectSelection::iterator it = selection->begin(); it != selection->end(); ++it)
+ {
+ LLSelectNode* node = *it;
+ if (!node || !node->mIndividualSelection)
+ {
+ continue;
+ }
+ append_unique_selected_object(objects, node->getObject());
+ }
+}
+
+static bool selection_has_multiple_objects()
+{
+ std::vector<LLViewerObject*> objects;
+ collect_multi_selected_objects(objects);
+ return objects.size() > 1;
+}
+
+static void handle_object_copy_selected_uuids()
+{
+ std::vector<LLViewerObject*> objects;
+ collect_multi_selected_objects(objects);
+ if (objects.size() < 2)
+ {
+ return;
+ }
+
+ std::string text;
+ for (LLViewerObject* object : objects)
+ {
+ if (!text.empty())
+ {
+ text += ", ";
+ }
+ text += object->getID().asString();
+ }
+ copy_text_to_clipboard(text);
+}
+
+static void handle_avatar_copy_uuid()
+{
+ LLUUID id = gAgent.getID();
+ LLViewerObject* object = selected_pick_object();
+ if (object && object->isAvatar())
+ {
+ id = object->getID();
+ }
+ copy_text_to_clipboard(id.asString());
+}
+
void handle_object_inspect()
{
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
@@ -4708,6 +4884,51 @@ void handle_object_sit(const LLUUID& object_id)
handle_object_sit(obj, offset);
}
+// Looks for the nearest sittable object -- one whose click-action is set to
+// CLICK_ACTION_SIT, the flag content creators set (usually alongside a custom
+// llSetSitText() label) to mark a prim as a seat -- within a hard-coded
+// multiple of the avatar's height. Used by the game-control "toggle sit"
+// action to find something to sit on before falling back to sitting on the
+// ground. Returns NULL if nothing qualifies.
+LLViewerObject* find_nearby_seat()
+{
+ if (!isAgentAvatarValid())
+ {
+ return NULL;
+ }
+
+ constexpr F32 SEAT_SEARCH_RANGE_HEIGHTS = 2.f;
+ const F32 max_dist = SEAT_SEARCH_RANGE_HEIGHTS * gAgentAvatarp->mBodySize.mV[VZ];
+ const LLVector3 agent_pos = gAgentAvatarp->getPositionAgent();
+
+ LLViewerObject* nearest_seat = NULL;
+ F32 nearest_dist_squared = max_dist * max_dist;
+
+ S32 num_objects = gObjectList.getNumObjects();
+ for (S32 i = 0; i < num_objects; ++i)
+ {
+ LLViewerObject* object = gObjectList.getObject(i);
+ if (!object || object->isDead() || object->isAttachment())
+ {
+ continue;
+ }
+
+ if (object->getPCode() != LL_PCODE_VOLUME || object->getClickAction() != CLICK_ACTION_SIT)
+ {
+ continue;
+ }
+
+ F32 dist_squared = dist_vec_squared(agent_pos, object->getPositionAgent());
+ if (dist_squared <= nearest_dist_squared)
+ {
+ nearest_seat = object;
+ nearest_dist_squared = dist_squared;
+ }
+ }
+
+ return nearest_seat;
+}
+
void near_sit_down_point(bool success, void*)
{
if (success)
@@ -6993,8 +7214,8 @@ class LLAvatarResetSkeleton : public view_listener_t
}
else
{
- avatar->resetSkeleton(false);
- }
+ avatar->resetSkeleton(false);
+ }
}
return true;
}
@@ -7059,9 +7280,9 @@ class LLAvatarResetSelfSkeletonAndAnimations : public view_listener_t
effectp->setSourceObject(gAgentAvatarp);
effectp->setTargetObject((LLViewerObject*)avatar);
effectp->setResetAnimations(true);
- }
- else
- {
+ }
+ else
+ {
avatar->resetSkeleton(true);
}
}
@@ -10310,6 +10531,9 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature");
view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature");
+ view_listener_t::addMenu(new LLAdvancedToggleExperiment(), "Advanced.ToggleExperiment");
+ view_listener_t::addMenu(new LLAdvancedCheckExperiment(), "Advanced.CheckExperiment");
+
view_listener_t::addMenu(new LLAdvancedCheckDisplayTextureDensity(), "Advanced.CheckDisplayTextureDensity");
view_listener_t::addMenu(new LLAdvancedSetDisplayTextureDensity(), "Advanced.SetDisplayTextureDensity");
@@ -10577,6 +10801,12 @@ void initialize_menus()
commit.add("Object.Edit", boost::bind(&handle_object_edit));
commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material));
commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
+ commit.add("Object.CopyUUID", boost::bind(&handle_object_copy_uuid));
+ commit.add("Object.CopyLinksetUUIDs", boost::bind(&handle_object_copy_linkset_uuids));
+ enable.add("Object.VisibleCopyLinksetUUIDs", boost::bind(&object_is_linkset));
+ commit.add("Object.CopySelectedUUIDs", boost::bind(&handle_object_copy_selected_uuids));
+ enable.add("Object.VisibleCopySelectedUUIDs", boost::bind(&selection_has_multiple_objects));
+ commit.add("Avatar.CopyUUID", boost::bind(&handle_avatar_copy_uuid));
commit.add("Object.Open", boost::bind(&handle_object_open));
commit.add("Object.Take", boost::bind(&handle_take, false));
commit.add("Object.TakeSeparate", boost::bind(&handle_take, true));