FIRE-3192: Predictive name completion in nearby chat, derived from Satomi Ahn's implementation
parent
bbdb1929b2
commit
2ba94087cd
|
|
@ -18755,7 +18755,7 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>FSChatbarGestureAutoCompleteEnable</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Toggles the auto complete in chat bar</string>
|
||||
<string>Toggles gesture auto complete in chat bar</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
@ -18763,6 +18763,17 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FSChatBarNamePrediction</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Toggles name prediction in nearby chat</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSDisableAvatarTrackerAtCloseIn</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@
|
|||
// #include "llanimationstates.h" // ANIM_AGENT_WHISPER, ANIM_AGENT_TALK, ANIM_AGENT_SHOUT
|
||||
// #include "llviewerstats.h"
|
||||
// </FS:Zi>
|
||||
// <FS:CR> FIRE-3192 - Name Prediction
|
||||
#include "llworld.h"
|
||||
|
||||
#define NAME_PREDICTION_MINIMUM_LENGTH 2
|
||||
// </FS:CR>
|
||||
|
||||
static LLDefaultChildRegistry::Register<FSNearbyChatControl> r("fs_nearby_chat_control");
|
||||
|
||||
|
|
@ -199,6 +204,114 @@ void FSNearbyChatControl::onKeystroke(LLLineEditor* caller,void* userdata)
|
|||
caller->setCursorToEnd();
|
||||
}
|
||||
}
|
||||
// <FS:CR> FIRE-3192 - Predictive name completion, based on code by Satomi Ahn
|
||||
static LLCachedControl<bool> sNameAutocomplete(gSavedSettings, "FSChatBarNamePrediction");
|
||||
if (length > NAME_PREDICTION_MINIMUM_LENGTH && sNameAutocomplete && key < KEY_SPECIAL)
|
||||
{
|
||||
std::string text = caller->getText();
|
||||
S32 cur_pos = caller->getCursor();
|
||||
if (cur_pos && (text.at(cur_pos - 1) != ' ' || caller->hasSelection()))
|
||||
{
|
||||
// Get a list of avatars within range
|
||||
std::vector<LLUUID> avatar_ids;
|
||||
std::vector<LLVector3d> positions;
|
||||
LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
|
||||
|
||||
if (avatar_ids.empty()) return; // Nobody's in range!
|
||||
|
||||
// Parse text for a pattern to search
|
||||
std::string prefix = text.substr(0, cur_pos); // Text before search string
|
||||
std::string suffix = text.substr(cur_pos, text.length() - cur_pos); // Text after search string
|
||||
U32 last_space = prefix.rfind(" ");
|
||||
std::string pattern = prefix.substr(last_space + 1, prefix.length() - last_space - 1); // Search pattern
|
||||
|
||||
prefix = prefix.substr(0, last_space + 1);
|
||||
std::string match_pattern = "";
|
||||
|
||||
if (pattern.size() < NAME_PREDICTION_MINIMUM_LENGTH) return;
|
||||
|
||||
match_pattern = prefix.substr(last_space + 1, prefix.length() - last_space -1);
|
||||
prefix = prefix.substr(0, last_space + 1);
|
||||
LLStringUtil::toLower(pattern);
|
||||
|
||||
std::string name;
|
||||
bool found = false;
|
||||
bool full_name = false;
|
||||
std::vector<LLUUID>::iterator iter = avatar_ids.begin();
|
||||
|
||||
if (last_space != std::string::npos && !prefix.empty())
|
||||
{
|
||||
last_space = prefix.substr(0, prefix.length() - 2).rfind(" ");
|
||||
match_pattern = prefix.substr(last_space + 1, prefix.length() - last_space -1);
|
||||
prefix = prefix.substr(0, last_space + 1);
|
||||
// prepare search pattern
|
||||
std::string full_pattern(match_pattern + pattern);
|
||||
LLStringUtil::toLower(full_pattern);
|
||||
// Look for a match
|
||||
while (iter != avatar_ids.end() && !found)
|
||||
{
|
||||
if ((bool)gCacheName->getFullName(*iter++, name))
|
||||
{
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
||||
{
|
||||
name = RlvStrings::getAnonym(name);
|
||||
}
|
||||
LLStringUtil::toLower(name);
|
||||
found = (name.find(full_pattern) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
full_name = true; // ignore OnlyFirstName in case we want to disambiguate
|
||||
}
|
||||
else if (!pattern.empty()) // if first search did not work, try matching with last word before cursor only
|
||||
{
|
||||
prefix += match_pattern; // first part of the pattern wasn't a pattern, so keep it in prefix
|
||||
LLStringUtil::toLower(pattern);
|
||||
iter = avatar_ids.begin();
|
||||
// Look for a match
|
||||
while (iter != avatar_ids.end() && !found)
|
||||
{
|
||||
if ((bool)gCacheName->getFullName(*iter++, name))
|
||||
{
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
||||
{
|
||||
name = RlvStrings::getAnonym(name);
|
||||
}
|
||||
LLStringUtil::toLower(name);
|
||||
found = (name.find(pattern) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we found something by either method, replace the pattern by the avatar name
|
||||
if (found)
|
||||
{
|
||||
std::string name;
|
||||
gCacheName->getFullName(*(iter - 1), name);
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
||||
{
|
||||
prefix += RlvStrings::getAnonym(name) + " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!full_name)
|
||||
{
|
||||
U32 space = name.find(" ");
|
||||
if (space != std::string::npos)
|
||||
name = name.substr(0, space);
|
||||
}
|
||||
|
||||
prefix += name + " ";
|
||||
}
|
||||
caller->setText(prefix + suffix);
|
||||
caller->setSelection(prefix.length(), cur_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// </FS:CR>
|
||||
}
|
||||
|
||||
BOOL FSNearbyChatControl::matchChatTypeTrigger(const std::string& in_str, std::string* out_str)
|
||||
|
|
|
|||
Loading…
Reference in New Issue