Make the nearby chat floater use the expandable chat bars
parent
8e98883f76
commit
5ae32941dd
|
|
@ -33,14 +33,16 @@
|
|||
|
||||
#include "chatbar_as_cmdline.h"
|
||||
#include "fschathistory.h"
|
||||
#include "fscommon.h"
|
||||
#include "fsfloaterim.h"
|
||||
#include "fsfloaterimcontainer.h"
|
||||
#include "fsnearbychathub.h"
|
||||
#include "llagent.h" // gAgent
|
||||
#include "llanimationstates.h" // ANIM_AGENT_WHISPER, ANIM_AGENT_TALK, ANIM_AGENT_SHOUT
|
||||
#include "llautoreplace.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llbutton.h"
|
||||
#include "llchannelmanager.h"
|
||||
#include "llchatentry.h"
|
||||
#include "llcommandhandler.h"
|
||||
#include "llconsole.h"
|
||||
#include "lldraghandle.h"
|
||||
|
|
@ -51,7 +53,6 @@
|
|||
#include "lliconctrl.h"
|
||||
#include "llkeyboard.h"
|
||||
#include "lllayoutstack.h"
|
||||
#include "lllineeditor.h"
|
||||
#include "lllogchat.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llmultigesture.h"
|
||||
|
|
@ -66,9 +67,26 @@
|
|||
#include "llviewermenu.h"//for gMenuHolder
|
||||
#include "llviewerstats.h"
|
||||
#include "llviewerwindow.h"
|
||||
#include "llworld.h"
|
||||
#include "rlvhandler.h"
|
||||
|
||||
static const S32 RESIZE_BAR_THICKNESS = 3;
|
||||
#define NAME_PREDICTION_MINIMUM_LENGTH 3
|
||||
S32 FSFloaterNearbyChat::sLastSpecialChatChannel = 0;
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-02-27 (RLVa-0.2.2)
|
||||
void send_chat_from_nearby_floater(std::string utf8_out_text, EChatType type, S32 channel);
|
||||
// [/RLVa:KB]
|
||||
void really_send_chat_from_nearby_floater(std::string utf8_out_text, EChatType type, S32 channel);
|
||||
|
||||
struct LLChatTypeTrigger {
|
||||
std::string name;
|
||||
EChatType type;
|
||||
};
|
||||
|
||||
static LLChatTypeTrigger sChatTypeTriggers[] = {
|
||||
{ "/whisper" , CHAT_TYPE_WHISPER},
|
||||
{ "/shout" , CHAT_TYPE_SHOUT}
|
||||
};
|
||||
|
||||
FSFloaterNearbyChat::FSFloaterNearbyChat(const LLSD& key)
|
||||
: LLDockableFloater(NULL, false, false, key)
|
||||
|
|
@ -76,6 +94,9 @@ FSFloaterNearbyChat::FSFloaterNearbyChat(const LLSD& key)
|
|||
,mInputEditor(NULL)
|
||||
// <FS:Ansariel> Optional muted chat history
|
||||
,mChatHistoryMuted(NULL)
|
||||
,mChatLayoutPanel(NULL)
|
||||
,mInputPanels(NULL)
|
||||
,mChatLayoutPanelHeight(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -105,13 +126,14 @@ void FSFloaterNearbyChat::updateFSUseNearbyChatConsole(const LLSD &data)
|
|||
|
||||
BOOL FSFloaterNearbyChat::postBuild()
|
||||
{
|
||||
setIsSingleInstance(TRUE);
|
||||
|
||||
//menu
|
||||
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
|
||||
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
|
||||
|
||||
enable_registrar.add("NearbyChat.Check", boost::bind(&FSFloaterNearbyChat::onNearbyChatCheckContextMenuItem, this, _2));
|
||||
registrar.add("NearbyChat.Action", boost::bind(&FSFloaterNearbyChat::onNearbyChatContextMenuItemClicked, this, _2));
|
||||
|
||||
|
||||
LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_nearby_chat.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
|
||||
if(menu)
|
||||
|
|
@ -119,9 +141,22 @@ BOOL FSFloaterNearbyChat::postBuild()
|
|||
|
||||
gSavedSettings.declareS32("nearbychat_showicons_and_names",2,"NearByChat header settings",true);
|
||||
|
||||
mInputEditor = getChild<LLLineEditor>("chat_box");
|
||||
|
||||
mInputEditor->setEnabled(TRUE);
|
||||
mInputEditor = getChild<LLChatEntry>("chat_box");
|
||||
if (mInputEditor)
|
||||
{
|
||||
mInputEditor->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2, _3, _4, _5));
|
||||
mInputEditor->setCommitCallback(boost::bind(&FSFloaterNearbyChat::onChatBoxCommit, this));
|
||||
mInputEditor->setKeystrokeCallback(boost::bind(&FSFloaterNearbyChat::onChatBoxKeystroke, this));
|
||||
mInputEditor->setFocusLostCallback(boost::bind(&FSFloaterNearbyChat::onChatBoxFocusLost, this));
|
||||
mInputEditor->setFocusReceivedCallback(boost::bind(&FSFloaterNearbyChat::onChatBoxFocusReceived, this));
|
||||
mInputEditor->setTextExpandedCallback(boost::bind(&FSFloaterNearbyChat::reshapeChatLayoutPanel, this));
|
||||
mInputEditor->setPassDelete(TRUE);
|
||||
mInputEditor->setFont(LLViewerChat::getChatFont());
|
||||
}
|
||||
mChatLayoutPanel = getChild<LLLayoutPanel>("chat_layout_panel");
|
||||
mInputPanels = getChild<LLLayoutStack>("input_panels");
|
||||
mChatLayoutPanelHeight = mChatLayoutPanel->getRect().getHeight();
|
||||
mInputEditorPad = mChatLayoutPanelHeight - mInputEditor->getRect().getHeight();
|
||||
|
||||
gSavedSettings.getControl("FSNearbyChatbar")->getCommitSignal()->connect(boost::bind(&FSFloaterNearbyChat::onChatBarVisibilityChanged, this));
|
||||
gSavedSettings.getControl("FSShowChatChannel")->getCommitSignal()->connect(boost::bind(&FSFloaterNearbyChat::onChatChannelVisibilityChanged, this));
|
||||
|
|
@ -173,7 +208,6 @@ std::string appendTime()
|
|||
return timeStr;
|
||||
}
|
||||
|
||||
|
||||
void FSFloaterNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args)
|
||||
{
|
||||
LLChat& tmp_chat = const_cast<LLChat&>(chat);
|
||||
|
|
@ -279,7 +313,6 @@ void FSFloaterNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD
|
|||
// virtual
|
||||
BOOL FSFloaterNearbyChat::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
|
||||
{
|
||||
mInputEditor->setFocus(TRUE);
|
||||
onTabInto();
|
||||
if (focus_flash)
|
||||
{
|
||||
|
|
@ -392,12 +425,6 @@ void FSFloaterNearbyChat::setVisible(BOOL visible)
|
|||
// </Ansariel> Support for chat console
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onFocusReceived()
|
||||
{
|
||||
// <FS:Ansariel> Give focus to input textbox
|
||||
mInputEditor->setFocus(TRUE);
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onOpen(const LLSD& key )
|
||||
{
|
||||
// <FS:Ansariel> [FS communication UI]
|
||||
|
|
@ -498,6 +525,25 @@ bool FSFloaterNearbyChat::isWordsName(const std::string& name)
|
|||
}
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::reloadMessages(bool clean_messages/* = false*/)
|
||||
{
|
||||
if (clean_messages)
|
||||
{
|
||||
mMessageArchive.clear();
|
||||
loadHistory();
|
||||
}
|
||||
|
||||
mChatHistory->clear();
|
||||
|
||||
LLSD do_not_log;
|
||||
do_not_log["do_not_log"] = true;
|
||||
for(std::vector<LLChat>::iterator it = mMessageArchive.begin();it!=mMessageArchive.end();++it)
|
||||
{
|
||||
// Update the messages without re-writing them to a log file.
|
||||
addMessage(*it,false, do_not_log);
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::loadHistory()
|
||||
{
|
||||
LLSD do_not_log;
|
||||
|
|
@ -639,3 +685,701 @@ void FSFloaterNearbyChat::enableTranslationButton(bool enabled)
|
|||
{
|
||||
getChildView("translate_btn")->setEnabled(enabled);
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL FSFloaterNearbyChat::handleKeyHere( KEY key, MASK mask )
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
|
||||
if( KEY_RETURN == key && mask == MASK_CONTROL)
|
||||
{
|
||||
// shout
|
||||
sendChat(CHAT_TYPE_SHOUT);
|
||||
handled = TRUE;
|
||||
}
|
||||
else if (KEY_RETURN == key && mask == MASK_SHIFT)
|
||||
{
|
||||
// whisper
|
||||
sendChat(CHAT_TYPE_WHISPER);
|
||||
handled = TRUE;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
BOOL FSFloaterNearbyChat::matchChatTypeTrigger(const std::string& in_str, std::string* out_str)
|
||||
{
|
||||
U32 in_len = in_str.length();
|
||||
S32 cnt = sizeof(sChatTypeTriggers) / sizeof(*sChatTypeTriggers);
|
||||
|
||||
bool string_was_found = false;
|
||||
|
||||
for (S32 n = 0; n < cnt && !string_was_found; n++)
|
||||
{
|
||||
if (in_len <= sChatTypeTriggers[n].name.length())
|
||||
{
|
||||
std::string trigger_trunc = sChatTypeTriggers[n].name;
|
||||
LLStringUtil::truncate(trigger_trunc, in_len);
|
||||
|
||||
if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc))
|
||||
{
|
||||
*out_str = sChatTypeTriggers[n].name;
|
||||
string_was_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string_was_found;
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onChatBoxKeystroke()
|
||||
{
|
||||
LLWString raw_text = mInputEditor->getWText();
|
||||
|
||||
// Can't trim the end, because that will cause autocompletion
|
||||
// to eat trailing spaces that might be part of a gesture.
|
||||
LLWStringUtil::trimHead(raw_text);
|
||||
|
||||
S32 length = raw_text.length();
|
||||
|
||||
S32 channel=0;
|
||||
if (gSavedSettings.getBOOL("FSNearbyChatbar") &&
|
||||
gSavedSettings.getBOOL("FSShowChatChannel"))
|
||||
{
|
||||
// <FS:Ansariel> [FS communication UI]
|
||||
//channel = (S32)(LLFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
|
||||
channel = (S32)(FSFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
|
||||
// </FS:Ansariel> [FS communication UI]
|
||||
}
|
||||
// -Zi
|
||||
|
||||
// if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences
|
||||
// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d
|
||||
if ( (length > 0) && (raw_text[0] != '/') && (!(gSavedSettings.getBOOL("AllowMUpose") && raw_text[0] == ':')) && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) )
|
||||
// [/RLVa:KB]
|
||||
{
|
||||
// only start typing animation if we are chatting without / on channel 0 -Zi
|
||||
if(channel==0)
|
||||
gAgent.startTyping();
|
||||
}
|
||||
else
|
||||
{
|
||||
gAgent.stopTyping();
|
||||
}
|
||||
|
||||
KEY key = gKeyboard->currentKey();
|
||||
MASK mask = gKeyboard->currentMask(FALSE);
|
||||
|
||||
// Ignore "special" keys, like backspace, arrows, etc.
|
||||
if (length > 1
|
||||
&& raw_text[0] == '/'
|
||||
&& key < KEY_SPECIAL
|
||||
&& gSavedSettings.getBOOL("FSChatbarGestureAutoCompleteEnable"))
|
||||
{
|
||||
// we're starting a gesture, attempt to autocomplete
|
||||
|
||||
std::string utf8_trigger = wstring_to_utf8str(raw_text);
|
||||
std::string utf8_out_str(utf8_trigger);
|
||||
|
||||
if (LLGestureMgr::instance().matchPrefix(utf8_trigger, &utf8_out_str))
|
||||
{
|
||||
std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
|
||||
if (!rest_of_match.empty())
|
||||
{
|
||||
mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
|
||||
|
||||
// Select to end of line, starting from the character
|
||||
// after the last one the user typed.
|
||||
mInputEditor->selectNext(rest_of_match, false);
|
||||
}
|
||||
}
|
||||
else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str))
|
||||
{
|
||||
std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
|
||||
mInputEditor->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part
|
||||
mInputEditor->endOfDoc();
|
||||
}
|
||||
}
|
||||
|
||||
// <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 && mask != MASK_CONTROL)
|
||||
{
|
||||
S32 cur_pos = mInputEditor->getCursorPos();
|
||||
if (cur_pos && (raw_text[cur_pos - 1] != ' '))
|
||||
{
|
||||
// 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 = wstring_to_utf8str(raw_text.substr(0, cur_pos)); // Text before search string
|
||||
std::string suffix = "";
|
||||
if (cur_pos <= raw_text.length()) // Is there anything after the cursor?
|
||||
{
|
||||
suffix = wstring_to_utf8str(raw_text.substr(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);
|
||||
std::string match = pattern;
|
||||
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
|
||||
prefix += match_pattern;
|
||||
}
|
||||
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 first_name, last_name;
|
||||
gCacheName->getFirstLastName(*(iter - 1), first_name, last_name);
|
||||
std::string rest_of_match;
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))
|
||||
{
|
||||
prefix += RlvStrings::getAnonym(first_name + " " + last_name) + " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (full_name)
|
||||
{
|
||||
rest_of_match = /*first_name + " " +*/ last_name.substr(pattern.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
rest_of_match = first_name.substr(pattern.size());
|
||||
}
|
||||
prefix += match + rest_of_match + " ";
|
||||
}
|
||||
mInputEditor->setText(prefix + suffix);
|
||||
mInputEditor->selectNext(rest_of_match, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// </FS:CR>
|
||||
}
|
||||
|
||||
// static
|
||||
void FSFloaterNearbyChat::onChatBoxFocusLost()
|
||||
{
|
||||
// stop typing animation
|
||||
gAgent.stopTyping();
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onChatBoxFocusReceived()
|
||||
{
|
||||
mInputEditor->setEnabled(!gDisconnected);
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::reshapeChatLayoutPanel()
|
||||
{
|
||||
mChatLayoutPanel->reshape(mChatLayoutPanel->getRect().getWidth(), mInputEditor->getRect().getHeight() + mInputEditorPad, FALSE);
|
||||
}
|
||||
|
||||
EChatType FSFloaterNearbyChat::processChatTypeTriggers(EChatType type, std::string &str)
|
||||
{
|
||||
U32 length = str.length();
|
||||
S32 cnt = sizeof(sChatTypeTriggers) / sizeof(*sChatTypeTriggers);
|
||||
|
||||
for (S32 n = 0; n < cnt; n++)
|
||||
{
|
||||
if (length >= sChatTypeTriggers[n].name.length())
|
||||
{
|
||||
std::string trigger = str.substr(0, sChatTypeTriggers[n].name.length());
|
||||
|
||||
if (!LLStringUtil::compareInsensitive(trigger, sChatTypeTriggers[n].name))
|
||||
{
|
||||
U32 trigger_length = sChatTypeTriggers[n].name.length();
|
||||
|
||||
// It's to remove space after trigger name
|
||||
if (length > trigger_length && str[trigger_length] == ' ')
|
||||
trigger_length++;
|
||||
|
||||
str = str.substr(trigger_length, length);
|
||||
|
||||
if (CHAT_TYPE_NORMAL == type)
|
||||
return sChatTypeTriggers[n].type;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::sendChat( EChatType type )
|
||||
{
|
||||
if (mInputEditor)
|
||||
{
|
||||
LLWString text = mInputEditor->getWText();
|
||||
LLWStringUtil::trim(text);
|
||||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if (!text.empty())
|
||||
{
|
||||
if(type == CHAT_TYPE_OOC)
|
||||
{
|
||||
std::string tempText = wstring_to_utf8str( text );
|
||||
tempText = gSavedSettings.getString("FSOOCPrefix") + " " + tempText + " " + gSavedSettings.getString("FSOOCPostfix");
|
||||
text = utf8str_to_wstring(tempText);
|
||||
}
|
||||
|
||||
// Check if this is destined for another channel
|
||||
S32 channel = 0;
|
||||
stripChannelNumber(text, &channel);
|
||||
// If "/<number>" is not specified, see if a channel has been set in
|
||||
// the spinner.
|
||||
if (gSavedSettings.getBOOL("FSNearbyChatbar") &&
|
||||
gSavedSettings.getBOOL("FSShowChatChannel") &&
|
||||
(channel == 0))
|
||||
{
|
||||
channel = (S32)(FSFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
|
||||
}
|
||||
|
||||
std::string utf8text = wstring_to_utf8str(text);
|
||||
// Try to trigger a gesture, if not chat to a script.
|
||||
std::string utf8_revised_text;
|
||||
if (0 == channel)
|
||||
{
|
||||
// Convert OOC and MU* style poses
|
||||
utf8text = applyAutoCloseOoc(utf8text);
|
||||
utf8text = applyMuPose(utf8text);
|
||||
|
||||
// discard returned "found" boolean
|
||||
LLGestureMgr::instance().triggerAndReviseString(utf8text, &utf8_revised_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
utf8_revised_text = utf8text;
|
||||
}
|
||||
|
||||
utf8_revised_text = utf8str_trim(utf8_revised_text);
|
||||
|
||||
EChatType nType;
|
||||
if(type == CHAT_TYPE_OOC)
|
||||
nType = CHAT_TYPE_NORMAL;
|
||||
else
|
||||
nType = type;
|
||||
|
||||
type = processChatTypeTriggers(nType, utf8_revised_text);
|
||||
|
||||
if (!utf8_revised_text.empty() && cmd_line_chat(utf8_revised_text, type))
|
||||
{
|
||||
// Chat with animation
|
||||
sendChatFromViewer(utf8_revised_text, type, gSavedSettings.getBOOL("FSPlayChatAnimation"));
|
||||
}
|
||||
}
|
||||
|
||||
mInputEditor->setText(LLStringExplicit(""));
|
||||
}
|
||||
|
||||
gAgent.stopTyping();
|
||||
|
||||
// If the user wants to stop chatting on hitting return, lose focus
|
||||
// and go out of chat mode.
|
||||
if (gSavedSettings.getBOOL("CloseChatOnReturn"))
|
||||
{
|
||||
stopChat();
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onChatBoxCommit()
|
||||
{
|
||||
if (mInputEditor->getText().length() > 0)
|
||||
{
|
||||
sendChat(CHAT_TYPE_NORMAL);
|
||||
}
|
||||
|
||||
gAgent.stopTyping();
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate)
|
||||
{
|
||||
sendChatFromViewer(utf8str_to_wstring(utf8text), type, animate);
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate)
|
||||
{
|
||||
S32 channel = 0;
|
||||
LLWString out_text = stripChannelNumber(wtext, &channel);
|
||||
// If "/<number>" is not specified, see if a channel has been set in
|
||||
// the spinner.
|
||||
if (gSavedSettings.getBOOL("FSNearbyChatbar") &&
|
||||
gSavedSettings.getBOOL("FSShowChatChannel") &&
|
||||
(channel == 0))
|
||||
{
|
||||
// <FS:Ansariel> [FS communication UI]
|
||||
//channel = (S32)(LLFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
|
||||
channel = (S32)(FSFloaterNearbyChat::getInstance()->getChild<LLSpinCtrl>("ChatChannel")->get());
|
||||
// </FS:Ansariel> [FS communication UI]
|
||||
}
|
||||
std::string utf8_out_text = wstring_to_utf8str(out_text);
|
||||
std::string utf8_text = wstring_to_utf8str(wtext);
|
||||
|
||||
utf8_text = utf8str_trim(utf8_text);
|
||||
if (!utf8_text.empty())
|
||||
{
|
||||
utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1);
|
||||
}
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b
|
||||
if ( (0 == channel) && (rlv_handler_t::isEnabled()) )
|
||||
{
|
||||
// Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation)
|
||||
if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
|
||||
type = CHAT_TYPE_WHISPER;
|
||||
else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
|
||||
type = CHAT_TYPE_NORMAL;
|
||||
else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
|
||||
type = CHAT_TYPE_NORMAL;
|
||||
|
||||
animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE );
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
// Don't animate for chats people can't hear (chat to scripts)
|
||||
if (animate && (channel == 0))
|
||||
{
|
||||
if (type == CHAT_TYPE_WHISPER)
|
||||
{
|
||||
lldebugs << "You whisper " << utf8_text << llendl;
|
||||
gAgent.sendAnimationRequest(ANIM_AGENT_WHISPER, ANIM_REQUEST_START);
|
||||
}
|
||||
else if (type == CHAT_TYPE_NORMAL)
|
||||
{
|
||||
lldebugs << "You say " << utf8_text << llendl;
|
||||
gAgent.sendAnimationRequest(ANIM_AGENT_TALK, ANIM_REQUEST_START);
|
||||
}
|
||||
else if (type == CHAT_TYPE_SHOUT)
|
||||
{
|
||||
lldebugs << "You shout " << utf8_text << llendl;
|
||||
gAgent.sendAnimationRequest(ANIM_AGENT_SHOUT, ANIM_REQUEST_START);
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos << "send_chat_from_viewer() - invalid volume" << llendl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type != CHAT_TYPE_START && type != CHAT_TYPE_STOP)
|
||||
{
|
||||
lldebugs << "Channel chat: " << utf8_text << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
send_chat_from_nearby_floater(utf8_out_text, type, channel);
|
||||
}
|
||||
|
||||
// Exit "chat mode" and do the appropriate focus changes
|
||||
// static
|
||||
void FSFloaterNearbyChat::stopChat()
|
||||
{
|
||||
FSFloaterNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<FSFloaterNearbyChat>("nearby_chat");
|
||||
if (nearby_chat)
|
||||
{
|
||||
nearby_chat->mInputEditor->setFocus(FALSE);
|
||||
gAgent.stopTyping();
|
||||
}
|
||||
}
|
||||
|
||||
// If input of the form "/20foo" or "/20 foo", returns "foo" and channel 20.
|
||||
// Otherwise returns input and channel 0.
|
||||
LLWString FSFloaterNearbyChat::stripChannelNumber(const LLWString &mesg, S32* channel)
|
||||
{
|
||||
if (mesg[0] == '/'
|
||||
&& mesg[1] == '/')
|
||||
{
|
||||
// This is a "repeat channel send"
|
||||
*channel = sLastSpecialChatChannel;
|
||||
return mesg.substr(2, mesg.length() - 2);
|
||||
}
|
||||
else if (mesg[0] == '/'
|
||||
&& mesg[1]
|
||||
&& LLStringOps::isDigit(mesg[1]))
|
||||
{
|
||||
// This a special "/20" speak on a channel
|
||||
S32 pos = 0;
|
||||
|
||||
// Copy the channel number into a string
|
||||
LLWString channel_string;
|
||||
llwchar c;
|
||||
do
|
||||
{
|
||||
c = mesg[pos+1];
|
||||
channel_string.push_back(c);
|
||||
pos++;
|
||||
}
|
||||
while(c && pos < 64 && LLStringOps::isDigit(c));
|
||||
|
||||
// Move the pointer forward to the first non-whitespace char
|
||||
// Check isspace before looping, so we can handle "/33foo"
|
||||
// as well as "/33 foo"
|
||||
while(c && iswspace(c))
|
||||
{
|
||||
c = mesg[pos+1];
|
||||
pos++;
|
||||
}
|
||||
|
||||
sLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), NULL, 10);
|
||||
*channel = sLastSpecialChatChannel;
|
||||
return mesg.substr(pos, mesg.length() - pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is normal chat.
|
||||
*channel = 0;
|
||||
return mesg;
|
||||
}
|
||||
}
|
||||
|
||||
//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel)
|
||||
// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a
|
||||
void send_chat_from_nearby_floater(std::string utf8_out_text, EChatType type, S32 channel)
|
||||
// [/RLVa:KB]
|
||||
{
|
||||
// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a
|
||||
// Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc)
|
||||
if ( (rlv_handler_t::isEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) )
|
||||
{
|
||||
if (0 == channel)
|
||||
{
|
||||
// (We already did this before, but LLChatHandler::handle() calls this directly)
|
||||
if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) )
|
||||
type = CHAT_TYPE_WHISPER;
|
||||
else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) )
|
||||
type = CHAT_TYPE_NORMAL;
|
||||
else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) )
|
||||
type = CHAT_TYPE_NORMAL;
|
||||
|
||||
// Redirect chat if needed
|
||||
if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) &&
|
||||
(gRlvHandler.redirectChatOrEmote(utf8_out_text)) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter public chat if sendchat restricted
|
||||
if (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT))
|
||||
gRlvHandler.filterChat(utf8_out_text, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception)
|
||||
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) && (!gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, channel)) )
|
||||
return;
|
||||
|
||||
// Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers)
|
||||
if (CHAT_CHANNEL_DEBUG == channel)
|
||||
{
|
||||
bool fIsEmote = RlvUtil::isEmote(utf8_out_text);
|
||||
if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHAT)) ||
|
||||
((!fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT))) ||
|
||||
((fIsEmote) && (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE))) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// [/RLVa:KB]
|
||||
|
||||
//<FS:TS> FIRE-787: break up too long chat lines into multiple messages
|
||||
U32 split = MAX_MSG_BUF_SIZE - 1;
|
||||
U32 pos = 0;
|
||||
U32 total = utf8_out_text.length();
|
||||
|
||||
// Don't break null messages
|
||||
if(total == 0)
|
||||
{
|
||||
really_send_chat_from_nearby_floater(utf8_out_text, type, channel);
|
||||
}
|
||||
|
||||
while(pos < total)
|
||||
{
|
||||
U32 next_split = split;
|
||||
|
||||
if (pos + next_split > total)
|
||||
{
|
||||
// just send the rest of the message
|
||||
next_split = total - pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// first, try to split at a space
|
||||
while((U8(utf8_out_text[pos + next_split]) != ' ')
|
||||
&& (next_split > 0))
|
||||
{
|
||||
--next_split;
|
||||
}
|
||||
|
||||
if (next_split == 0)
|
||||
{
|
||||
next_split = split;
|
||||
// no space found, split somewhere not in the middle of UTF-8
|
||||
while((U8(utf8_out_text[pos + next_split]) >= 0x80)
|
||||
&& (U8(utf8_out_text[pos + next_split]) < 0xC0)
|
||||
&& (next_split > 0))
|
||||
{
|
||||
--next_split;
|
||||
}
|
||||
}
|
||||
|
||||
if(next_split == 0)
|
||||
{
|
||||
next_split = split;
|
||||
LL_WARNS("Splitting") << "utf-8 couldn't be split correctly" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string send = utf8_out_text.substr(pos, next_split);
|
||||
pos += next_split;
|
||||
|
||||
// *FIXME: Queue messages and wait for server
|
||||
really_send_chat_from_nearby_floater(send, type, channel);
|
||||
}
|
||||
|
||||
// moved here so we don't bump the count for every message segment
|
||||
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT);
|
||||
//</FS:TS> FIRE-787
|
||||
}
|
||||
|
||||
//<FS:TS> FIRE-787: break up too long chat lines into multiple messages
|
||||
// This function just sends the message, with no other processing. Moved out
|
||||
// of send_chat_from_viewer.
|
||||
void really_send_chat_from_nearby_floater(std::string utf8_out_text, EChatType type, S32 channel)
|
||||
{
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
|
||||
// <FS:ND> gMessageSystem can be 0, not sure how it is exactly to reproduce, maybe during viewer shutdown?
|
||||
if( !msg )
|
||||
return;
|
||||
// </FS:ND>
|
||||
|
||||
if(channel >= 0)
|
||||
{
|
||||
msg->newMessageFast(_PREHASH_ChatFromViewer);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||
msg->nextBlockFast(_PREHASH_ChatData);
|
||||
msg->addStringFast(_PREHASH_Message, utf8_out_text);
|
||||
msg->addU8Fast(_PREHASH_Type, type);
|
||||
msg->addS32("Channel", channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->newMessage("ScriptDialogReply");
|
||||
msg->nextBlock("AgentData");
|
||||
msg->addUUID("AgentID", gAgent.getID());
|
||||
msg->addUUID("SessionID", gAgent.getSessionID());
|
||||
msg->nextBlock("Data");
|
||||
msg->addUUID("ObjectID", gAgent.getID());
|
||||
msg->addS32("ChatChannel", channel);
|
||||
msg->addS32("ButtonIndex", 0);
|
||||
msg->addString("ButtonLabel", utf8_out_text);
|
||||
}
|
||||
|
||||
gAgent.sendReliableMessage();
|
||||
}
|
||||
//</FS:TS> FIRE-787
|
||||
|
||||
class LLChatCommandHandler : public LLCommandHandler
|
||||
{
|
||||
public:
|
||||
// not allowed from outside the app
|
||||
LLChatCommandHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { }
|
||||
|
||||
// Your code here
|
||||
bool handle(const LLSD& tokens, const LLSD& query_map,
|
||||
LLMediaCtrl* web)
|
||||
{
|
||||
bool retval = false;
|
||||
// Need at least 2 tokens to have a valid message.
|
||||
if (tokens.size() < 2)
|
||||
{
|
||||
retval = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 channel = tokens[0].asInteger();
|
||||
// VWR-19499 Restrict function to chat channels greater than 0.
|
||||
if ((channel > 0) && (channel < CHAT_CHANNEL_DEBUG))
|
||||
{
|
||||
retval = true;
|
||||
// Send unescaped message, see EXT-6353.
|
||||
std::string unescaped_mesg (LLURI::unescape(tokens[1].asString()));
|
||||
send_chat_from_nearby_floater(unescaped_mesg, CHAT_TYPE_NORMAL, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = false;
|
||||
// Tell us this is an unsupported SLurl.
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,11 +36,9 @@
|
|||
|
||||
class LLResizeBar;
|
||||
class FSChatHistory;
|
||||
// <FS:Zi> Nearby chat bar class
|
||||
// class LLLineEditor;
|
||||
#include "lllineeditor.h"
|
||||
#include "llsingleton.h"
|
||||
// </FS:Zi>
|
||||
#include "llchatentry.h"
|
||||
//#include "llsingleton.h"
|
||||
#include "lllayoutstack.h"
|
||||
|
||||
class FSFloaterNearbyChat: public LLDockableFloater
|
||||
{
|
||||
|
|
@ -58,16 +56,6 @@ public:
|
|||
void onChatBarVisibilityChanged();
|
||||
void onChatChannelVisibilityChanged();
|
||||
|
||||
// This doesn't seem to apply anymore? It makes the chat and spin box colors
|
||||
// appear wrong when focused and unfocused, so disable this. -Zi
|
||||
#if 0
|
||||
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
virtual void draw();
|
||||
|
||||
// focus overrides
|
||||
/*virtual*/ void onFocusLost();
|
||||
#endif
|
||||
/*virtual*/ void onFocusReceived();
|
||||
/*virtual*/ void onOpen (const LLSD& key);
|
||||
|
||||
/*virtual*/ void setVisible(BOOL visible);
|
||||
|
|
@ -81,6 +69,7 @@ public:
|
|||
static void processChatHistoryStyleUpdate(const LLSD& newvalue);
|
||||
|
||||
void loadHistory();
|
||||
void reloadMessages(bool clean_messages = false);
|
||||
|
||||
static FSFloaterNearbyChat* getInstance();
|
||||
|
||||
|
|
@ -99,6 +88,31 @@ public:
|
|||
static bool isWordsName(const std::string& name);
|
||||
|
||||
void enableTranslationButton(bool enabled);
|
||||
LLChatEntry* getChatBox() { return mInputEditor; }
|
||||
|
||||
virtual BOOL handleKeyHere( KEY key, MASK mask );
|
||||
|
||||
static void startChat(const char* line);
|
||||
static void stopChat();
|
||||
|
||||
static void sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate);
|
||||
static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate);
|
||||
|
||||
protected:
|
||||
static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str);
|
||||
void onChatBoxKeystroke();
|
||||
void onChatBoxFocusLost();
|
||||
void onChatBoxFocusReceived();
|
||||
|
||||
void sendChat( EChatType type );
|
||||
void onChatBoxCommit();
|
||||
|
||||
static LLWString stripChannelNumber(const LLWString &mesg, S32* channel);
|
||||
EChatType processChatTypeTriggers(EChatType type, std::string &str);
|
||||
void reshapeFloater(bool collapse);
|
||||
void reshapeChatLayoutPanel();
|
||||
|
||||
static S32 sLastSpecialChatChannel;
|
||||
|
||||
private:
|
||||
void getAllowedRect (LLRect& rect);
|
||||
|
|
@ -110,9 +124,15 @@ private:
|
|||
FSChatHistory* mChatHistory;
|
||||
// <FS:Ansariel> Optional muted chat history
|
||||
FSChatHistory* mChatHistoryMuted;
|
||||
LLChatEntry* mInputEditor;
|
||||
LLLayoutPanel* mChatLayoutPanel;
|
||||
LLLayoutStack* mInputPanels;
|
||||
|
||||
S32 mInputEditorPad;
|
||||
S32 mChatLayoutPanelHeight;
|
||||
S32 mFloaterHeight;
|
||||
|
||||
std::vector<LLChat> mMessageArchive;
|
||||
LLLineEditor* mInputEditor;
|
||||
|
||||
BOOL FSUseNearbyChatConsole;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,213 +1,234 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
legacy_header_height="18"
|
||||
background_visible="true"
|
||||
default_tab_group="1"
|
||||
follows="all"
|
||||
height="225"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="nearby_chat"
|
||||
title="Nearby Chat"
|
||||
top="0"
|
||||
can_dock="false"
|
||||
can_close="true"
|
||||
can_minimize="false"
|
||||
can_tear_off="true"
|
||||
single_instance="true"
|
||||
save_rect="true"
|
||||
save_visibility="true"
|
||||
save_dock_state="true"
|
||||
save_tearoff_state="true"
|
||||
visible="false"
|
||||
width="394"
|
||||
can_resize="true"
|
||||
min_width="250"
|
||||
min_height="150">
|
||||
|
||||
<layout_stack
|
||||
border_size="0"
|
||||
follows="all"
|
||||
height="203"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="main_layout_stack"
|
||||
orientation="vertical"
|
||||
top="20"
|
||||
width="394">
|
||||
|
||||
<layout_panel
|
||||
follows="all"
|
||||
height="200"
|
||||
layout="topleft"
|
||||
name="chat_history_and_buttons_panel"
|
||||
right="394"
|
||||
user_resize="false">
|
||||
|
||||
<button
|
||||
height="20"
|
||||
follows="left|top"
|
||||
top="0"
|
||||
left="2"
|
||||
image_overlay="TabIcon_Open_Off"
|
||||
layout="topleft"
|
||||
width="25"
|
||||
name="slide_left_btn" />
|
||||
<button
|
||||
height="20"
|
||||
follows="left|top"
|
||||
top_delta="0"
|
||||
left="2"
|
||||
image_overlay="TabIcon_Close_Off"
|
||||
layout="topleft"
|
||||
width="25"
|
||||
name="slide_right_btn" />
|
||||
<button
|
||||
height="20"
|
||||
follows="left|top"
|
||||
top_delta="0"
|
||||
left="2"
|
||||
image_overlay="TabIcon_Translate_Off"
|
||||
layout="topleft"
|
||||
width="25"
|
||||
control_name="TranslateChat"
|
||||
is_toggle="true"
|
||||
image_pressed="PushButton_Press"
|
||||
image_pressed_selected="PushButton_Selected_Press"
|
||||
image_selected="PushButton_Selected_Press"
|
||||
tool_tip="Use selected translation service"
|
||||
name="translate_btn"/>
|
||||
<button
|
||||
height="20"
|
||||
follows="left|top"
|
||||
left_pad="2"
|
||||
image_overlay="List_View_On"
|
||||
layout="topleft"
|
||||
width="25"
|
||||
image_pressed="PushButton_Press"
|
||||
image_pressed_selected="PushButton_Selected_Press"
|
||||
image_selected="PushButton_Selected_Press"
|
||||
tool_tip="Open the nearby chat history."
|
||||
name="chat_history_btn"/>
|
||||
<button
|
||||
height="20"
|
||||
follows="left|top"
|
||||
left_pad="2"
|
||||
image_overlay="Muted_Chat"
|
||||
layout="topleft"
|
||||
width="25"
|
||||
control_name="FSShowMutedChatHistory"
|
||||
image_pressed="PushButton_Press"
|
||||
image_pressed_selected="PushButton_Selected_Press"
|
||||
image_selected="PushButton_Selected_Press"
|
||||
tool_tip="Shows the muted chat in nearby chat history."
|
||||
name="chat_history_muted_btn">
|
||||
<button.commit_callback
|
||||
function="ToggleControl"
|
||||
parameter="FSShowMutedChatHistory"/>
|
||||
</button>
|
||||
<fs_chat_history
|
||||
invisibility_control="FSShowMutedChatHistory"
|
||||
top_pad="4"
|
||||
font="SansSerifSmall"
|
||||
follows="all"
|
||||
height="174"
|
||||
mouse_opaque="false"
|
||||
name="chat_history"
|
||||
parse_highlights="true"
|
||||
parse_urls="true"
|
||||
layout="topleft"
|
||||
left="2"
|
||||
right="-2" />
|
||||
<fs_chat_history
|
||||
visibility_control="FSShowMutedChatHistory"
|
||||
top_delta="0"
|
||||
font="SansSerifSmall"
|
||||
follows="all"
|
||||
height="174"
|
||||
mouse_opaque="false"
|
||||
name="chat_history_muted"
|
||||
parse_highlights="true"
|
||||
parse_urls="true"
|
||||
layout="topleft"
|
||||
left="2"
|
||||
right="-2" />
|
||||
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
legacy_header_height="18"
|
||||
background_visible="true"
|
||||
follows="all"
|
||||
height="350"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="nearby_chat"
|
||||
title="Nearby Chat"
|
||||
top="0"
|
||||
can_dock="false"
|
||||
can_close="true"
|
||||
can_minimize="false"
|
||||
can_tear_off="true"
|
||||
single_instance="true"
|
||||
save_rect="true"
|
||||
save_visibility="true"
|
||||
save_dock_state="true"
|
||||
save_tearoff_state="true"
|
||||
visible="false"
|
||||
width="394"
|
||||
can_resize="true"
|
||||
min_width="250"
|
||||
min_height="150">
|
||||
|
||||
<layout_stack
|
||||
border_size="0"
|
||||
animate="false"
|
||||
follows="top|left"
|
||||
clip="false"
|
||||
height="27"
|
||||
width="200"
|
||||
left_pad="0"
|
||||
layout="topleft"
|
||||
orientation="horizontal"
|
||||
name="ls_control_panel"
|
||||
top="14"
|
||||
left="3">
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
follows="all"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
name="chat_bar_visibility_panel"
|
||||
right="394"
|
||||
user_resize="false"
|
||||
visible="true">
|
||||
top="0"
|
||||
layout="topleft"
|
||||
height="26"
|
||||
width="26"
|
||||
follows="left|top">
|
||||
<button
|
||||
follows="left|top"
|
||||
top="2"
|
||||
width="24"
|
||||
height="24"
|
||||
image_overlay="TabIcon_Translate_Off"
|
||||
control_name="TranslateChat"
|
||||
is_toggle="true"
|
||||
image_pressed="PushButton_Press"
|
||||
image_pressed_selected="PushButton_Selected_Press"
|
||||
image_selected="PushButton_Selected_Press"
|
||||
tool_tip="Use selected translation service"
|
||||
name="translate_btn"/>
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
layout="topleft"
|
||||
height="26"
|
||||
width="24"
|
||||
follows="left|top">
|
||||
<button
|
||||
follows="left|top"
|
||||
top="2"
|
||||
width="24"
|
||||
height="24"
|
||||
image_overlay="List_View_On"
|
||||
image_pressed="PushButton_Press"
|
||||
image_pressed_selected="PushButton_Selected_Press"
|
||||
image_selected="PushButton_Selected_Press"
|
||||
tool_tip="Open the nearby chat history."
|
||||
name="chat_history_btn"/>
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
top="0"
|
||||
layout="topleft"
|
||||
height="26"
|
||||
width="26"
|
||||
follows="left|top">
|
||||
<button
|
||||
follows="left|top"
|
||||
top="2"
|
||||
width="24"
|
||||
height="24"
|
||||
image_overlay="Muted_Chat"
|
||||
control_name="FSShowMutedChatHistory"
|
||||
is_toggle="true"
|
||||
image_pressed="PushButton_Press"
|
||||
image_pressed_selected="PushButton_Selected_Press"
|
||||
image_selected="PushButton_Selected_Press"
|
||||
tool_tip="Shows the muted chat in nearby chat history."
|
||||
name="chat_history_muted_btn">
|
||||
</button>
|
||||
|
||||
</layout_panel>
|
||||
|
||||
</layout_stack>
|
||||
<layout_stack
|
||||
animate="false"
|
||||
follows="all"
|
||||
height="308"
|
||||
width="394"
|
||||
layout="topleft"
|
||||
orientation="horizontal"
|
||||
name="im_panels"
|
||||
top="40"
|
||||
left="0">
|
||||
<layout_panel
|
||||
name="panel_im_control_lp"
|
||||
left="0"
|
||||
top="0"
|
||||
bottom="-1"
|
||||
right="0"
|
||||
user_resize="true">
|
||||
<layout_stack
|
||||
orientation="horizontal"
|
||||
border_size="0"
|
||||
follows="left|right|bottom"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
name="chat_bar_channel_spinner_layout_stack"
|
||||
right="-2"
|
||||
top_pad="0">
|
||||
|
||||
<layout_panel
|
||||
follows="all"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
name="chat_bar_layout_panel"
|
||||
user_resize="false"
|
||||
width="300">
|
||||
|
||||
<fs_nearby_chat_control
|
||||
layout="topleft"
|
||||
top="0"
|
||||
left="3"
|
||||
right="-1"
|
||||
follows="all"
|
||||
font="SansSerifSmall"
|
||||
height="20"
|
||||
label="To nearby chat"
|
||||
name="chat_box"
|
||||
spellcheck="true"
|
||||
tab_group="3" />
|
||||
</layout_panel>
|
||||
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
follows="all"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
name="channel_spinner_visibility_panel"
|
||||
user_resize="false"
|
||||
visible="true"
|
||||
width="90">
|
||||
|
||||
<spinner
|
||||
layout="topleft"
|
||||
top="0"
|
||||
left="0"
|
||||
width="90"
|
||||
decimal_digits="0"
|
||||
follows="all"
|
||||
height="20"
|
||||
increment="1.00"
|
||||
initial_value="0"
|
||||
label="Chan"
|
||||
label_width="29"
|
||||
max_val="2147483647"
|
||||
min_val="-2147483647"
|
||||
mouse_opaque="true"
|
||||
name="ChatChannel"
|
||||
tool_tip="Channel to send chat on. Enabled in Preferences -> Chat -> Firestorm -> Show channel selection in chat bar." />
|
||||
|
||||
</layout_panel>
|
||||
animate="false"
|
||||
follows="all"
|
||||
height="308"
|
||||
width="394"
|
||||
layout="topleft"
|
||||
orientation="vertical"
|
||||
name="im_panels"
|
||||
top="4"
|
||||
left="0"
|
||||
right="0"
|
||||
bottom="-1">
|
||||
<layout_panel
|
||||
name="chat_holder">
|
||||
<fs_chat_history
|
||||
invisibility_control="FSShowMutedChatHistory"
|
||||
font="SansSerifSmall"
|
||||
follows="all"
|
||||
name="chat_history"
|
||||
parse_highlights="true"
|
||||
parse_urls="true"
|
||||
right="-4"
|
||||
left="4"
|
||||
top="0"
|
||||
bottom="-1" />
|
||||
<fs_chat_history
|
||||
visibility_control="FSShowMutedChatHistory"
|
||||
font="SansSerifSmall"
|
||||
follows="all"
|
||||
name="chat_history_muted"
|
||||
parse_highlights="true"
|
||||
parse_urls="true"
|
||||
right="-4"
|
||||
left="4"
|
||||
top="0"
|
||||
bottom="-1" />
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
top_delta="0"
|
||||
top="0"
|
||||
height="26"
|
||||
bottom="-1"
|
||||
auto_resize="false"
|
||||
name="chat_layout_panel">
|
||||
<layout_stack
|
||||
animate="false"
|
||||
default_tab_group="2"
|
||||
follows="all"
|
||||
orientation="horizontal"
|
||||
name="input_panels"
|
||||
top="0"
|
||||
bottom="-2"
|
||||
left="0"
|
||||
right="-1">
|
||||
<layout_panel
|
||||
name="input_editor_layout_panel"
|
||||
auto_resize="true"
|
||||
user_resize="false"
|
||||
top="0"
|
||||
bottom="-1">
|
||||
<chat_editor
|
||||
layout="topleft"
|
||||
expand_lines_count="5"
|
||||
follows="left|right|bottom"
|
||||
font="SansSerifSmall"
|
||||
height="20"
|
||||
is_expandable="true"
|
||||
text_tentative_color="TextFgTentativeColor"
|
||||
name="chat_box"
|
||||
max_length="3070"
|
||||
spellcheck="true"
|
||||
tab_group="3"
|
||||
top="1"
|
||||
bottom="-2"
|
||||
left="4"
|
||||
right="-4"
|
||||
wrap="true" />
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
visibility_control="FSShowChatChannel"
|
||||
auto_resize="false"
|
||||
user_resize="false"
|
||||
name="input_button_layout_panel"
|
||||
width="50"
|
||||
top="0"
|
||||
bottom="-1">
|
||||
<spinner
|
||||
layout="topleft"
|
||||
top="1"
|
||||
left="1"
|
||||
right="-1"
|
||||
height="22"
|
||||
width="90"
|
||||
decimal_digits="0"
|
||||
follows="all"
|
||||
increment="1.00"
|
||||
initial_value="0"
|
||||
label=""
|
||||
label_width="29"
|
||||
max_val="2147483647"
|
||||
min_val="-2147483647"
|
||||
mouse_opaque="true"
|
||||
name="ChatChannel"
|
||||
tool_tip="Channel to send chat on. Enabled in Preferences -> Chat -> Firestorm -> Show channel selection in chat bar." />
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
|
|||
Loading…
Reference in New Issue