# Conflicts:
#	indra/newview/skins/default/xui/en/floater_emoji_picker.xml
meow-7.2.2
Ansariel 2023-08-30 19:04:09 +02:00
commit e7549d3951
23 changed files with 618 additions and 182 deletions

View File

@ -178,6 +178,10 @@ void LLSearchEditor::setFocus( BOOL b )
void LLSearchEditor::onClearButtonClick(const LLSD& data)
{
setText(LLStringUtil::null);
if (mTextChangedCallback)
{
mTextChangedCallback(this, getValue());
}
mSearchEditor->onCommit(); // force keystroke callback
}

View File

@ -33,6 +33,8 @@
#include "llagentbenefits.h"
#include "llavataractions.h"
#include "llavatarnamecache.h"
#include "llemojidictionary.h"
#include "llfloateremojipicker.h"
#include "llfloaterperms.h"
#include "llgroupactions.h"
#include "llgroupmgr.h"
@ -519,3 +521,16 @@ LLUUID FSCommon::getGroupForRezzing()
return group_id;
}
void FSCommon::updateUsedEmojis(LLWString text)
{
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
for (llwchar& c : text)
{
if (dictionary->isEmoji(c))
{
LLFloaterEmojiPicker::onEmojiUsed(c);
}
}
}

View File

@ -93,6 +93,8 @@ namespace FSCommon
bool isFilterEditorKeyCombo(KEY key, MASK mask);
LLUUID getGroupForRezzing();
void updateUsedEmojis(LLWString text);
};
#endif // FS_COMMON_H

View File

@ -64,6 +64,7 @@
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llnotificationtemplate.h" // <FS:Zi> Viewer version popup
#include "llpanelemojicomplete.h"
#include "llrootview.h"
#include "llscreenchannel.h"
#include "llspeakers.h"
@ -376,6 +377,8 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type)
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
if (!text.empty())
{
FSCommon::updateUsedEmojis(text);
if (type == CHAT_TYPE_OOC)
{
std::string tempText = wstring_to_utf8str( text );
@ -950,9 +953,22 @@ BOOL FSFloaterIM::postBuild()
mInputEditor->enableSingleLineMode(gSavedSettings.getBOOL("FSUseSingleLineChatEntry"));
mInputEditor->setCommitCallback(boost::bind(&FSFloaterIM::sendMsgFromInputEditor, this, CHAT_TYPE_NORMAL));
mEmojiButton = getChild<LLButton>("emoji_panel_btn");
mEmojiButton->setLabel(LLUIString(LLWString(1, 128512)));
mEmojiButton->setClickedCallback(boost::bind(&FSFloaterIM::onEmojiPanelBtnClicked, this));
mEmojiRecentPanelToggleBtn = getChild<LLButton>("emoji_recent_panel_toggle_btn");
mEmojiRecentPanelToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiRecentPanelToggleBtnClicked(this); });
mEmojiRecentPanel = getChild<LLLayoutPanel>("emoji_recent_layout_panel");
mEmojiRecentPanel->setVisible(false);
mEmojiRecentEmptyText = getChildView("emoji_recent_empty_text");
mEmojiRecentEmptyText->setVisible(false);
mEmojiRecentIconsCtrl = getChild<LLPanelEmojiComplete>("emoji_recent_icons_ctrl");
mEmojiRecentIconsCtrl->setCommitCallback([this](LLUICtrl*, const LLSD& value) { onRecentEmojiPicked(value); });
mEmojiRecentIconsCtrl->setVisible(false);
mEmojiPickerToggleBtn = getChild<LLButton>("emoji_picker_toggle_btn");
mEmojiPickerToggleBtn->setLabel(LLUIString(LLWString(1, 128512)));
mEmojiPickerToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerToggleBtnClicked(this); });
getChild<LLButton>("send_chat")->setCommitCallback(boost::bind(&FSFloaterIM::sendMsgFromInputEditor, this, CHAT_TYPE_NORMAL));
getChild<LLButton>("chat_search_btn")->setCommitCallback(boost::bind(&FSFloaterIM::onChatSearchButtonClicked, this));
@ -2448,7 +2464,54 @@ bool FSFloaterIM::applyRectControl()
return res;
}
void FSFloaterIM::onEmojiPanelBtnClicked(FSFloaterIM* self)
void FSFloaterIM::onEmojiRecentPanelToggleBtnClicked(FSFloaterIM* self)
{
BOOL show = !self->mEmojiRecentPanel->getVisible();
if (show)
{
self->onEmojiRecentPanelOpening();
}
self->mEmojiRecentPanel->setVisible(show);
self->mEmojiRecentPanelToggleBtn->setImageOverlay(show ? "Arrow_Up" : "Arrow_Down");
}
void FSFloaterIM::onEmojiRecentPanelOpening()
{
std::list<llwchar>& recentlyUsed = LLFloaterEmojiPicker::getRecentlyUsed();
if (recentlyUsed.empty())
{
mEmojiRecentEmptyText->setVisible(true);
mEmojiRecentIconsCtrl->setVisible(false);
}
else
{
LLWString emojis;
for (llwchar emoji : recentlyUsed)
{
emojis += emoji;
}
mEmojiRecentIconsCtrl->setEmojis(emojis);
mEmojiRecentEmptyText->setVisible(false);
mEmojiRecentIconsCtrl->setVisible(true);
mEmojiRecentIconsCtrl->setFocus(true);
}
}
void FSFloaterIM::onRecentEmojiPicked(const LLSD& value)
{
LLSD::String str = value.asString();
if (str.size())
{
LLWString wstr = utf8string_to_wstring(str);
if (wstr.size())
{
llwchar emoji = wstr[0];
onEmojiPicked(emoji);
}
}
}
void FSFloaterIM::onEmojiPickerToggleBtnClicked(FSFloaterIM* self)
{
if (LLFloaterEmojiPicker* picker = LLFloaterEmojiPicker::getInstance())
{

View File

@ -47,10 +47,10 @@ class LLInventoryCategory;
class LLInventoryItem;
class LLLayoutPanel;
class LLLayoutStack;
class LLPanelEmojiComplete;
class LLTextBox;
class LLTextEditor;
typedef boost::signals2::signal<void(const LLUUID& session_id)> floater_showed_signal_t;
/**
@ -239,7 +239,10 @@ private:
bool onChatOptionsVisibleContextMenuItem(const LLSD& userdata);
bool onChatOptionsEnableContextMenuItem(const LLSD& userdata);
static void onEmojiPanelBtnClicked(FSFloaterIM* self);
static void onEmojiRecentPanelToggleBtnClicked(FSFloaterIM* self);
static void onEmojiPickerToggleBtnClicked(FSFloaterIM* self);
void onEmojiRecentPanelOpening();
void onRecentEmojiPicked(const LLSD& value);
void onEmojiPicked(llwchar emoji);
void onEmojiPickerClosed();
@ -256,7 +259,11 @@ private:
LLLayoutStack* mInputPanels;
LLLayoutPanel* mUnreadMessagesNotificationPanel;
LLTextBox* mUnreadMessagesNotificationTextBox;
LLButton* mEmojiButton;
LLButton* mEmojiRecentPanelToggleBtn;
LLButton* mEmojiPickerToggleBtn;
LLLayoutPanel* mEmojiRecentPanel;
LLView* mEmojiRecentEmptyText;
LLPanelEmojiComplete* mEmojiRecentIconsCtrl;
std::string mSavedTitle;
LLUIString mTypingStart;

View File

@ -61,6 +61,7 @@
#include "lllogchat.h"
#include "llmenugl.h"
#include "llmultigesture.h"
#include "llpanelemojicomplete.h"
#include "llresizebar.h"
#include "llresizehandle.h"
#include "llrootview.h"
@ -142,9 +143,22 @@ BOOL FSFloaterNearbyChat::postBuild()
mChatLayoutPanelHeight = mChatLayoutPanel->getRect().getHeight();
mInputEditorPad = mChatLayoutPanelHeight - mInputEditor->getRect().getHeight();
mEmojiButton = getChild<LLButton>("emoji_panel_btn");
mEmojiButton->setLabel(LLUIString(LLWString(1, 128512)));
mEmojiButton->setClickedCallback(boost::bind(&FSFloaterNearbyChat::onEmojiPanelBtnClicked, this));
mEmojiRecentPanelToggleBtn = getChild<LLButton>("emoji_recent_panel_toggle_btn");
mEmojiRecentPanelToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiRecentPanelToggleBtnClicked(this); });
mEmojiRecentPanel = getChild<LLLayoutPanel>("emoji_recent_layout_panel");
mEmojiRecentPanel->setVisible(false);
mEmojiRecentEmptyText = getChildView("emoji_recent_empty_text");
mEmojiRecentEmptyText->setVisible(false);
mEmojiRecentIconsCtrl = getChild<LLPanelEmojiComplete>("emoji_recent_icons_ctrl");
mEmojiRecentIconsCtrl->setCommitCallback([this](LLUICtrl*, const LLSD& value) { onRecentEmojiPicked(value); });
mEmojiRecentIconsCtrl->setVisible(false);
mEmojiPickerToggleBtn = getChild<LLButton>("emoji_picker_toggle_btn");
mEmojiPickerToggleBtn->setLabel(LLUIString(LLWString(1, 128512)));
mEmojiPickerToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerToggleBtnClicked(this); });
getChild<LLButton>("chat_history_btn")->setCommitCallback(boost::bind(&FSFloaterNearbyChat::onHistoryButtonClicked, this));
getChild<LLButton>("chat_search_btn")->setCommitCallback(boost::bind(&FSFloaterNearbyChat::onSearchButtonClicked, this));
@ -766,6 +780,8 @@ void FSFloaterNearbyChat::sendChat( EChatType type )
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
if (!text.empty())
{
FSCommon::updateUsedEmojis(text);
if(type == CHAT_TYPE_OOC)
{
std::string tempText = wstring_to_utf8str( text );
@ -947,7 +963,54 @@ void FSFloaterNearbyChat::handleMinimized(bool minimized)
}
}
void FSFloaterNearbyChat::onEmojiPanelBtnClicked(FSFloaterNearbyChat* self)
void FSFloaterNearbyChat::onEmojiRecentPanelToggleBtnClicked(FSFloaterNearbyChat* self)
{
BOOL show = !self->mEmojiRecentPanel->getVisible();
if (show)
{
self->onEmojiRecentPanelOpening();
}
self->mEmojiRecentPanel->setVisible(show);
self->mEmojiRecentPanelToggleBtn->setImageOverlay(show ? "Arrow_Up" : "Arrow_Down");
}
void FSFloaterNearbyChat::onEmojiRecentPanelOpening()
{
std::list<llwchar>& recentlyUsed = LLFloaterEmojiPicker::getRecentlyUsed();
if (recentlyUsed.empty())
{
mEmojiRecentEmptyText->setVisible(true);
mEmojiRecentIconsCtrl->setVisible(false);
}
else
{
LLWString emojis;
for (llwchar emoji : recentlyUsed)
{
emojis += emoji;
}
mEmojiRecentIconsCtrl->setEmojis(emojis);
mEmojiRecentEmptyText->setVisible(false);
mEmojiRecentIconsCtrl->setVisible(true);
mEmojiRecentIconsCtrl->setFocus(true);
}
}
void FSFloaterNearbyChat::onRecentEmojiPicked(const LLSD& value)
{
LLSD::String str = value.asString();
if (str.size())
{
LLWString wstr = utf8string_to_wstring(str);
if (wstr.size())
{
llwchar emoji = wstr[0];
onEmojiPicked(emoji);
}
}
}
void FSFloaterNearbyChat::onEmojiPickerToggleBtnClicked(FSFloaterNearbyChat* self)
{
if (LLFloaterEmojiPicker* picker = LLFloaterEmojiPicker::getInstance())
{

View File

@ -39,6 +39,7 @@ class LLChatEntry;
class LLComboBox;
class LLLayoutStack;
class LLLayoutPanel;
class LLPanelEmojiComplete;
class LLResizeBar;
class LLTextBox;
@ -120,7 +121,10 @@ private:
bool onChatOptionsVisibleContextMenuItem(const LLSD& userdata);
bool onChatOptionsEnableContextMenuItem(const LLSD& userdata);
static void onEmojiPanelBtnClicked(FSFloaterNearbyChat* self);
static void onEmojiRecentPanelToggleBtnClicked(FSFloaterNearbyChat* self);
static void onEmojiPickerToggleBtnClicked(FSFloaterNearbyChat* self);
void onEmojiRecentPanelOpening();
void onRecentEmojiPicked(const LLSD& value);
void onEmojiPicked(llwchar emoji);
void onEmojiPickerClosed();
@ -129,7 +133,11 @@ private:
LLChatEntry* mInputEditor;
// chat type selector and send chat buttons
LLButton* mEmojiButton;
LLButton* mEmojiRecentPanelToggleBtn;
LLButton* mEmojiPickerToggleBtn;
LLLayoutPanel* mEmojiRecentPanel;
LLView* mEmojiRecentEmptyText;
LLPanelEmojiComplete* mEmojiRecentIconsCtrl;
LLButton* mSendChatButton;
LLComboBox* mChatTypeCombo;

View File

@ -253,6 +253,8 @@ void FSNearbyChat::sendChat(LLWString text, EChatType type)
if (!text.empty())
{
FSCommon::updateUsedEmojis(text);
if (type == CHAT_TYPE_OOC)
{
text = utf8string_to_wstring(gSavedSettings.getString("FSOOCPrefix") + " ") + text + utf8string_to_wstring(" " + gSavedSettings.getString("FSOOCPostfix"));

View File

@ -31,9 +31,9 @@
#include "llbutton.h"
#include "llcombobox.h"
#include "llemojidictionary.h"
#include "llfiltereditor.h"
#include "llfloaterreg.h"
#include "llkeyboard.h"
#include "lllineeditor.h"
#include "llscrollcontainer.h"
#include "llscrollingpanellist.h"
#include "llscrolllistctrl.h"
@ -294,9 +294,9 @@ BOOL LLFloaterEmojiPicker::postBuild()
mGroups = getChild<LLPanel>("Groups");
mBadge = getChild<LLPanel>("Badge");
mFilter = getChild<LLLineEditor>("Filter");
mFilter->setKeystrokeCallback([this](LLLineEditor*, void*) { onSearchKeystroke(); }, NULL);
mFilter->setFont(LLViewerChat::getChatFont());
mFilter = getChild<LLFilterEditor>("Filter");
mFilter->setKeystrokeCallback([this](LLUICtrl*, const LLSD&) { onFilterChanged(); });
mFilter->setTextChangedCallback([this](LLUICtrl*, const LLSD&) { onFilterChanged(); });
mFilter->setText(sFilterPattern);
mEmojiScroll = getChild<LLScrollContainer>("EmojiGridContainer");
@ -588,7 +588,7 @@ void LLFloaterEmojiPicker::onGroupButtonClick(LLUICtrl* ctrl)
}
}
void LLFloaterEmojiPicker::onSearchKeystroke()
void LLFloaterEmojiPicker::onFilterChanged()
{
sFilterPattern = mFilter->getText();
fillEmojis();
@ -669,7 +669,6 @@ void LLFloaterEmojiPicker::onEmojiMouseUp(LLUICtrl* ctrl)
{
if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl))
{
onEmojiUsed(icon->getEmoji());
if (mEmojiPickCallback)
{
mEmojiPickCallback(icon->getEmoji());
@ -723,6 +722,14 @@ void LLFloaterEmojiPicker::closeFloater(bool app_quitting)
}
}
// static
std::list<llwchar>& LLFloaterEmojiPicker::getRecentlyUsed()
{
loadState();
return sRecentlyUsed;
}
// static
void LLFloaterEmojiPicker::onEmojiUsed(llwchar emoji)
{
// Update sRecentlyUsed
@ -762,6 +769,7 @@ void LLFloaterEmojiPicker::onEmojiUsed(llwchar emoji)
sFrequentlyUsed.push_back(std::make_pair(emoji, 1));
}
// static
void LLFloaterEmojiPicker::loadState()
{
if (!sStateFileName.empty())
@ -844,6 +852,7 @@ void LLFloaterEmojiPicker::loadState()
}
}
// static
void LLFloaterEmojiPicker::saveState()
{
if (sStateFileName.empty())

View File

@ -54,13 +54,18 @@ public:
virtual void closeFloater(bool app_quitting = false) override;
static std::list<llwchar>& getRecentlyUsed();
static void onEmojiUsed(llwchar emoji);
static void loadState();
static void saveState();
private:
void fillGroups();
void moveGroups();
void fillEmojis(bool fromResize = false);
void onGroupButtonClick(LLUICtrl* ctrl);
void onSearchKeystroke();
void onFilterChanged();
void onGridMouseEnter();
void onGridMouseLeave();
void onGroupButtonMouseEnter(LLUICtrl* ctrl);
@ -75,13 +80,9 @@ private:
virtual BOOL handleKeyHere(KEY key, MASK mask) override;
void onEmojiUsed(llwchar emoji);
void loadState();
void saveState();
class LLPanel* mGroups { nullptr };
class LLPanel* mBadge { nullptr };
class LLLineEditor* mFilter { nullptr };
class LLFilterEditor* mFilter { nullptr };
class LLScrollContainer* mEmojiScroll { nullptr };
class LLScrollingPanelList* mEmojiGrid { nullptr };
class LLEmojiPreviewPanel* mPreview { nullptr };

View File

@ -601,6 +601,8 @@ void LLFloaterIMNearbyChat::sendChat( EChatType type )
S32 channel = 0;
stripChannelNumber(text, &channel);
updateUsedEmojis(text);
std::string utf8text = wstring_to_utf8str(text);
// Try to trigger a gesture, if not chat to a script.
std::string utf8_revised_text;

View File

@ -254,6 +254,8 @@ void LLFloaterIMSession::sendMsgFromInputEditor()
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
if(!text.empty())
{
updateUsedEmojis(text);
// Truncate and convert to UTF8 for transport
std::string utf8_text = wstring_to_utf8str(text);

View File

@ -35,19 +35,21 @@
#include "llagentcamera.h"
#include "llavataractions.h"
#include "llavatariconctrl.h"
#include "llgroupiconctrl.h"
#include "llchatentry.h"
#include "llchathistory.h"
#include "llchiclet.h"
#include "llchicletbar.h"
#include "lldraghandle.h"
#include "llemojidictionary.h"
#include "llfloaterreg.h"
#include "llfloateremojipicker.h"
#include "llfloaterimsession.h"
#include "llfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container
#include "lllayoutstack.h"
#include "lltoolbarview.h"
#include "llfloaterimnearbychat.h"
#include "llgroupiconctrl.h"
#include "lllayoutstack.h"
#include "llpanelemojicomplete.h"
#include "lltoolbarview.h"
const F32 REFRESH_INTERVAL = 1.0f;
const std::string ICN_GROUP("group_chat_icon");
@ -59,7 +61,7 @@ void cb_group_do_nothing()
}
LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
: LLTransientDockableFloater(NULL, false, session_id),
: super(NULL, false, session_id),
mIsP2PChat(false),
mExpandCollapseBtn(NULL),
mTearOffBtn(NULL),
@ -78,7 +80,7 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
mInputPanels(NULL),
mChatLayoutPanelHeight(0)
{
setAutoFocus(FALSE);
setAutoFocus(FALSE);
mSession = LLIMModel::getInstance()->findIMSession(mSessionID);
mCommitCallbackRegistrar.add("IMSession.Menu.Action",
@ -91,12 +93,12 @@ LLFloaterIMSessionTab::LLFloaterIMSessionTab(const LLSD& session_id)
boost::bind(&LLFloaterIMSessionTab::onIMShowModesMenuItemEnable, this, _2));
// Right click menu handling
mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMSessionTab::checkContextMenuItem, this, _2));
mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2));
mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2));
mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing));
mEnableCallbackRegistrar.add("Avatar.CheckItem", boost::bind(&LLFloaterIMSessionTab::checkContextMenuItem, this, _2));
mEnableCallbackRegistrar.add("Avatar.EnableItem", boost::bind(&LLFloaterIMSessionTab::enableContextMenuItem, this, _2));
mCommitCallbackRegistrar.add("Avatar.DoToSelected", boost::bind(&LLFloaterIMSessionTab::doToSelected, this, _2));
mCommitCallbackRegistrar.add("Group.DoToSelected", boost::bind(&cb_group_do_nothing));
mMinFloaterHeight = getMinHeight();
mMinFloaterHeight = getMinHeight();
}
LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
@ -104,7 +106,7 @@ LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
delete mRefreshTimer;
}
//static
// static
LLFloaterIMSessionTab* LLFloaterIMSessionTab::findConversation(const LLUUID& uuid)
{
LLFloaterIMSessionTab* conv;
@ -121,7 +123,7 @@ LLFloaterIMSessionTab* LLFloaterIMSessionTab::findConversation(const LLUUID& uui
return conv;
};
//static
// static
LLFloaterIMSessionTab* LLFloaterIMSessionTab::getConversation(const LLUUID& uuid)
{
LLFloaterIMSessionTab* conv;
@ -137,14 +139,16 @@ LLFloaterIMSessionTab* LLFloaterIMSessionTab::getConversation(const LLUUID& uuid
}
return conv;
};
// virtual
void LLFloaterIMSessionTab::setVisible(BOOL visible)
{
if(visible && !mHasVisibleBeenInitialized)
if (visible && !mHasVisibleBeenInitialized)
{
mHasVisibleBeenInitialized = true;
if(!gAgentCamera.cameraMouselook())
if (!gAgentCamera.cameraMouselook())
{
LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")->setVisible(true);
}
@ -158,27 +162,26 @@ void LLFloaterIMSessionTab::setVisible(BOOL visible)
mInputButtonPanel->setVisible(isTornOff());
}
LLTransientDockableFloater::setVisible(visible);
super::setVisible(visible);
}
/*virtual*/
// virtual
void LLFloaterIMSessionTab::setFocus(BOOL focus)
{
LLTransientDockableFloater::setFocus(focus);
super::setFocus(focus);
//Redirect focus to input editor
if (focus)
// Redirect focus to input editor
if (focus)
{
updateMessages();
updateMessages();
if (mInputEditor)
{
mInputEditor->setFocus(TRUE);
}
if (mInputEditor)
{
mInputEditor->setFocus(TRUE);
}
}
}
void LLFloaterIMSessionTab::addToHost(const LLUUID& session_id)
{
if ((session_id.notNull() && !gIMMgr->hasSession(session_id))
@ -223,44 +226,58 @@ void LLFloaterIMSessionTab::assignResizeLimits()
{
bool is_participants_pane_collapsed = mParticipantListPanel->isCollapsed();
// disable a layoutstack's functionality when participant list panel is collapsed
// disable a layoutstack's functionality when participant list panel is collapsed
mRightPartPanel->setIgnoreReshape(is_participants_pane_collapsed);
S32 participants_pane_target_width = is_participants_pane_collapsed?
0 : (mParticipantListPanel->getRect().getWidth() + mParticipantListAndHistoryStack->getPanelSpacing());
S32 participants_pane_target_width = is_participants_pane_collapsed?
0 : (mParticipantListPanel->getRect().getWidth() + mParticipantListAndHistoryStack->getPanelSpacing());
S32 new_min_width = participants_pane_target_width + mRightPartPanel->getExpandedMinDim() + mFloaterExtraWidth;
S32 new_min_width = participants_pane_target_width + mRightPartPanel->getExpandedMinDim() + mFloaterExtraWidth;
setResizeLimits(new_min_width, getMinHeight());
this->mParticipantListAndHistoryStack->updateLayout();
}
// virtual
BOOL LLFloaterIMSessionTab::postBuild()
{
BOOL result;
mBodyStack = getChild<LLLayoutStack>("main_stack");
mParticipantListAndHistoryStack = getChild<LLLayoutStack>("im_panels");
mParticipantListAndHistoryStack = getChild<LLLayoutStack>("im_panels");
mCloseBtn = getChild<LLButton>("close_btn");
mCloseBtn->setCommitCallback(boost::bind(&LLFloater::onClickClose, this));
mCloseBtn->setCommitCallback([this](LLUICtrl*, const LLSD&) { onClickClose(this); });
mExpandCollapseBtn = getChild<LLButton>("expand_collapse_btn");
mExpandCollapseBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onSlide, this));
mExpandCollapseBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onSlide(this); });
mExpandCollapseLineBtn = getChild<LLButton>("minz_btn");
mExpandCollapseLineBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onCollapseToLine, this));
mExpandCollapseLineBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onCollapseToLine(this); });
mTearOffBtn = getChild<LLButton>("tear_off_btn");
mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this));
mEmojiBtn = getChild<LLButton>("emoji_panel_btn");
mEmojiBtn->setLabel(LLUIString(LLWString(1, 128512)));
mEmojiBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onEmojiPanelBtnClicked, this));
mEmojiRecentPanelToggleBtn = getChild<LLButton>("emoji_recent_panel_toggle_btn");
mEmojiRecentPanelToggleBtn->setLabel(LLUIString(LLWString(1, 128512)));
mEmojiRecentPanelToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiRecentPanelToggleBtnClicked(this); });
mEmojiRecentPanel = getChild<LLLayoutPanel>("emoji_recent_layout_panel");
mEmojiRecentPanel->setVisible(false);
mEmojiRecentEmptyText = getChildView("emoji_recent_empty_text");
mEmojiRecentEmptyText->setVisible(false);
mEmojiRecentIconsCtrl = getChild<LLPanelEmojiComplete>("emoji_recent_icons_ctrl");
mEmojiRecentIconsCtrl->setCommitCallback([this](LLUICtrl*, const LLSD& value) { onRecentEmojiPicked(value); });
mEmojiRecentIconsCtrl->setVisible(false);
mEmojiPickerToggleBtn = getChild<LLButton>("emoji_picker_toggle_btn");
mEmojiPickerToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerToggleBtnClicked(this); });
mGearBtn = getChild<LLButton>("gear_btn");
mAddBtn = getChild<LLButton>("add_btn");
mAddBtn = getChild<LLButton>("add_btn");
mVoiceButton = getChild<LLButton>("voice_call_btn");
mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel");
@ -314,17 +331,17 @@ BOOL LLFloaterIMSessionTab::postBuild()
// Create the root using an ad-hoc base item
LLConversationItem* base_item = new LLConversationItem(mSessionID, mConversationViewModel);
LLFolderView::Params p(LLUICtrlFactory::getDefaultParams<LLFolderView>());
p.rect = LLRect(0, 0, getRect().getWidth(), 0);
p.parent_panel = mParticipantListPanel;
p.listener = base_item;
p.view_model = &mConversationViewModel;
p.root = NULL;
p.use_ellipses = true;
p.options_menu = "menu_conversation.xml";
p.name = "root";
LLFolderView::Params p(LLUICtrlFactory::getDefaultParams<LLFolderView>());
p.rect = LLRect(0, 0, getRect().getWidth(), 0);
p.parent_panel = mParticipantListPanel;
p.listener = base_item;
p.view_model = &mConversationViewModel;
p.root = NULL;
p.use_ellipses = true;
p.options_menu = "menu_conversation.xml";
p.name = "root";
mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar);
// Attach that root to the scroller
mScroller->addChild(mConversationsRoot);
@ -364,6 +381,7 @@ LLParticipantList* LLFloaterIMSessionTab::getParticipantList()
return dynamic_cast<LLParticipantList*>(LLFloaterIMContainer::getInstance()->getSessionModel(mSessionID));
}
// virtual
void LLFloaterIMSessionTab::draw()
{
if (mRefreshTimer->hasExpired())
@ -388,23 +406,24 @@ void LLFloaterIMSessionTab::draw()
mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL);
}
LLTransientDockableFloater::draw();
super::draw();
}
void LLFloaterIMSessionTab::enableDisableCallBtn()
{
if (LLVoiceClient::instanceExists() && mVoiceButton)
{
mVoiceButton->setEnabled(
mSessionID.notNull()
&& mSession
&& mSession->mSessionInitialized
&& LLVoiceClient::getInstance()->voiceEnabled()
&& LLVoiceClient::getInstance()->isVoiceWorking()
&& mSession->mCallBackEnabled);
}
if (LLVoiceClient::instanceExists() && mVoiceButton)
{
mVoiceButton->setEnabled(
mSessionID.notNull()
&& mSession
&& mSession->mSessionInitialized
&& LLVoiceClient::getInstance()->voiceEnabled()
&& LLVoiceClient::getInstance()->isVoiceWorking()
&& mSession->mCallBackEnabled);
}
}
// virtual
void LLFloaterIMSessionTab::onFocusReceived()
{
setBackgroundOpaque(true);
@ -414,13 +433,14 @@ void LLFloaterIMSessionTab::onFocusReceived()
LLIMModel::instance().sendNoUnreadMessages(mSessionID);
}
LLTransientDockableFloater::onFocusReceived();
super::onFocusReceived();
}
// virtual
void LLFloaterIMSessionTab::onFocusLost()
{
setBackgroundOpaque(false);
LLTransientDockableFloater::onFocusLost();
super::onFocusLost();
}
void LLFloaterIMSessionTab::onInputEditorClicked()
@ -433,7 +453,17 @@ void LLFloaterIMSessionTab::onInputEditorClicked()
gToolBarView->flashCommand(LLCommandId("chat"), false);
}
void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self)
void LLFloaterIMSessionTab::onEmojiRecentPanelToggleBtnClicked(LLFloaterIMSessionTab* self)
{
BOOL show = !self->mEmojiRecentPanel->getVisible();
if (show)
{
self->onEmojiRecentPanelOpening();
}
self->mEmojiRecentPanel->setVisible(show);
}
void LLFloaterIMSessionTab::onEmojiPickerToggleBtnClicked(LLFloaterIMSessionTab* self)
{
if (LLFloaterEmojiPicker* picker = LLFloaterEmojiPicker::getInstance())
{
@ -454,6 +484,43 @@ void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self)
}
}
void LLFloaterIMSessionTab::onEmojiRecentPanelOpening()
{
std::list<llwchar>& recentlyUsed = LLFloaterEmojiPicker::getRecentlyUsed();
if (recentlyUsed.empty())
{
mEmojiRecentEmptyText->setVisible(true);
mEmojiRecentIconsCtrl->setVisible(false);
mEmojiPickerToggleBtn->setFocus(true);
}
else
{
LLWString emojis;
for (llwchar emoji : recentlyUsed)
{
emojis += emoji;
}
mEmojiRecentIconsCtrl->setEmojis(emojis);
mEmojiRecentEmptyText->setVisible(false);
mEmojiRecentIconsCtrl->setVisible(true);
mEmojiRecentIconsCtrl->setFocus(true);
}
}
void LLFloaterIMSessionTab::onRecentEmojiPicked(const LLSD& value)
{
LLSD::String str = value.asString();
if (str.size())
{
LLWString wstr = utf8string_to_wstring(str);
if (wstr.size())
{
llwchar emoji = wstr[0];
onEmojiPicked(emoji);
}
}
}
void LLFloaterIMSessionTab::onEmojiPicked(llwchar emoji)
{
mInputEditor->insertEmoji(emoji);
@ -464,6 +531,12 @@ void LLFloaterIMSessionTab::onEmojiPickerClosed()
mInputEditor->setFocus(TRUE);
}
void LLFloaterIMSessionTab::closeFloater(bool app_quitting)
{
LLFloaterEmojiPicker::saveState();
super::closeFloater(app_quitting);
}
std::string LLFloaterIMSessionTab::appendTime()
{
std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:"
@ -505,6 +578,20 @@ void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD& args)
mChatHistory->appendMessage(chat, chat_args);
}
void LLFloaterIMSessionTab::updateUsedEmojis(LLWString text)
{
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
llassert_always(dictionary);
for (llwchar& c : text)
{
if (dictionary->isEmoji(c))
{
LLFloaterEmojiPicker::onEmojiUsed(c);
}
}
}
static LLTrace::BlockTimerStatHandle FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT("Build Conversation View");
void LLFloaterIMSessionTab::buildConversationViewParticipant()
{
@ -532,10 +619,10 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant()
while (current_participant_model != end_participant_model)
{
LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
if (participant_model)
{
addConversationViewParticipant(participant_model);
}
if (participant_model)
{
addConversationViewParticipant(participant_model);
}
current_participant_model++;
}
}
@ -555,10 +642,10 @@ void LLFloaterIMSessionTab::addConversationViewParticipant(LLConversationItem* p
// If not already present, create the participant view and attach it to the root, otherwise, just refresh it
if (widget)
{
if (update_view)
{
updateConversationViewParticipant(uuid); // overkill?
}
if (update_view)
{
updateConversationViewParticipant(uuid); // overkill?
}
}
else
{
@ -608,11 +695,11 @@ void LLFloaterIMSessionTab::refreshConversation()
{
participants_uuids.push_back(widget_it->first);
}
if (widget_it->second->getViewModelItem())
{
widget_it->second->refresh();
widget_it->second->setVisible(TRUE);
}
if (widget_it->second->getViewModelItem())
{
widget_it->second->refresh();
widget_it->second->setVisible(TRUE);
}
++widget_it;
}
if (is_ad_hoc || mIsP2PChat)
@ -668,7 +755,7 @@ void LLFloaterIMSessionTab::refreshConversation()
// Copied from LLFloaterIMContainer::createConversationViewParticipant(). Refactor opportunity!
LLConversationViewParticipant* LLFloaterIMSessionTab::createConversationViewParticipant(LLConversationItem* item)
{
LLRect panel_rect = mParticipantListPanel->getRect();
LLRect panel_rect = mParticipantListPanel->getRect();
LLConversationViewParticipant::Params params;
params.name = item->getDisplayName();
@ -796,7 +883,7 @@ void LLFloaterIMSessionTab::hideAllStandardButtons()
void LLFloaterIMSessionTab::updateHeaderAndToolbar()
{
// prevent start conversation before its container
LLFloaterIMContainer::getInstance();
LLFloaterIMContainer::getInstance();
bool is_not_torn_off = !checkIfTornOff();
if (is_not_torn_off)
@ -813,12 +900,12 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar()
&& !mIsP2PChat;
mParticipantListAndHistoryStack->collapsePanel(mParticipantListPanel, !is_participant_list_visible);
mParticipantListPanel->setVisible(is_participant_list_visible);
mParticipantListPanel->setVisible(is_participant_list_visible);
// Display collapse image (<<) if the floater is hosted
// or if it is torn off but has an open control panel.
bool is_expanded = is_not_torn_off || is_participant_list_visible;
mExpandCollapseBtn->setImageOverlay(getString(is_expanded ? "collapse_icon" : "expand_icon"));
mExpandCollapseBtn->setToolTip(
is_not_torn_off?
@ -847,10 +934,10 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar()
void LLFloaterIMSessionTab::forceReshape()
{
LLRect floater_rect = getRect();
reshape(llmax(floater_rect.getWidth(), this->getMinWidth()),
llmax(floater_rect.getHeight(), this->getMinHeight()),
true);
LLRect floater_rect = getRect();
reshape(llmax(floater_rect.getWidth(), this->getMinWidth()),
llmax(floater_rect.getHeight(), this->getMinHeight()),
true);
}
@ -876,7 +963,7 @@ void LLFloaterIMSessionTab::processChatHistoryStyleUpdate(bool clean_messages/*
LLFloaterIMNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLFloaterIMNearbyChat>("nearby_chat");
if (nearby_chat)
{
nearby_chat->reloadMessages(clean_messages);
nearby_chat->reloadMessages(clean_messages);
}
}
@ -922,15 +1009,15 @@ void LLFloaterIMSessionTab::onSlide(LLFloaterIMSessionTab* self)
{
if (!self->mIsP2PChat)
{
// The state must toggle the collapsed state of the panel
should_be_expanded = self->mParticipantListPanel->isCollapsed();
// The state must toggle the collapsed state of the panel
should_be_expanded = self->mParticipantListPanel->isCollapsed();
// Update the expand/collapse flag of the participant list panel and save it
gSavedSettings.setBOOL("IMShowControlPanel", should_be_expanded);
self->mIsParticipantListExpanded = should_be_expanded;
// Refresh for immediate feedback
self->refreshConversation();
gSavedSettings.setBOOL("IMShowControlPanel", should_be_expanded);
self->mIsParticipantListExpanded = should_be_expanded;
// Refresh for immediate feedback
self->refreshConversation();
}
}
@ -967,12 +1054,12 @@ void LLFloaterIMSessionTab::reshapeFloater(bool collapse)
+ mChatLayoutPanel->getRect().getHeight() - mChatLayoutPanelHeight + 2;
floater_rect.mTop -= height;
setResizeLimits(getMinWidth(), floater_rect.getHeight());
setResizeLimits(getMinWidth(), floater_rect.getHeight());
}
else
{
floater_rect.mTop = floater_rect.mBottom + mFloaterHeight;
setResizeLimits(getMinWidth(), mMinFloaterHeight);
setResizeLimits(getMinWidth(), mMinFloaterHeight);
}
enableResizeCtrls(true, true, !collapse);
@ -997,7 +1084,7 @@ void LLFloaterIMSessionTab::restoreFloater()
setShape(floater_rect, true);
mBodyStack->updateLayout();
mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon"));
setResizeLimits(getMinWidth(), mMinFloaterHeight);
setResizeLimits(getMinWidth(), mMinFloaterHeight);
setMessagePaneExpanded(true);
saveCollapsedState();
mInputEditor->enableSingleLineMode(false);
@ -1023,8 +1110,8 @@ void LLFloaterIMSessionTab::onTearOffClicked()
{
restoreFloater();
setFollows(isTornOff()? FOLLOWS_ALL : FOLLOWS_NONE);
mSaveRect = isTornOff();
initRectControl();
mSaveRect = isTornOff();
initRectControl();
LLFloater::onClickTearOff(this);
LLFloaterIMContainer* container = LLFloaterReg::findTypedInstance<LLFloaterIMContainer>("im_container");
@ -1114,8 +1201,8 @@ bool LLFloaterIMSessionTab::checkIfTornOff()
void LLFloaterIMSessionTab::doToSelected(const LLSD& userdata)
{
// Get the list of selected items in the tab
std::string command = userdata.asString();
uuid_vec_t selected_uuids;
std::string command = userdata.asString();
uuid_vec_t selected_uuids;
getSelectedUUIDs(selected_uuids);
// Perform the command (IM, profile, etc...) on the list using the general conversation container method
@ -1127,8 +1214,8 @@ void LLFloaterIMSessionTab::doToSelected(const LLSD& userdata)
bool LLFloaterIMSessionTab::enableContextMenuItem(const LLSD& userdata)
{
// Get the list of selected items in the tab
std::string command = userdata.asString();
uuid_vec_t selected_uuids;
std::string command = userdata.asString();
uuid_vec_t selected_uuids;
getSelectedUUIDs(selected_uuids);
// Perform the item enable test on the list using the general conversation container method
@ -1139,8 +1226,8 @@ bool LLFloaterIMSessionTab::enableContextMenuItem(const LLSD& userdata)
bool LLFloaterIMSessionTab::checkContextMenuItem(const LLSD& userdata)
{
// Get the list of selected items in the tab
std::string command = userdata.asString();
uuid_vec_t selected_uuids;
std::string command = userdata.asString();
uuid_vec_t selected_uuids;
getSelectedUUIDs(selected_uuids);
// Perform the item check on the list using the general conversation container method
@ -1150,19 +1237,19 @@ bool LLFloaterIMSessionTab::checkContextMenuItem(const LLSD& userdata)
void LLFloaterIMSessionTab::getSelectedUUIDs(uuid_vec_t& selected_uuids)
{
const std::set<LLFolderViewItem*> selected_items = mConversationsRoot->getSelectionList();
const std::set<LLFolderViewItem*> selected_items = mConversationsRoot->getSelectionList();
std::set<LLFolderViewItem*>::const_iterator it = selected_items.begin();
const std::set<LLFolderViewItem*>::const_iterator it_end = selected_items.end();
std::set<LLFolderViewItem*>::const_iterator it = selected_items.begin();
const std::set<LLFolderViewItem*>::const_iterator it_end = selected_items.end();
for (; it != it_end; ++it)
{
LLConversationItem* conversation_item = static_cast<LLConversationItem *>((*it)->getViewModelItem());
if (conversation_item)
{
selected_uuids.push_back(conversation_item->getUUID());
}
}
for (; it != it_end; ++it)
{
LLConversationItem* conversation_item = static_cast<LLConversationItem *>((*it)->getViewModelItem());
if (conversation_item)
{
selected_uuids.push_back(conversation_item->getUUID());
}
}
}
LLConversationItem* LLFloaterIMSessionTab::getCurSelectedViewModelItem()
@ -1170,8 +1257,8 @@ LLConversationItem* LLFloaterIMSessionTab::getCurSelectedViewModelItem()
LLConversationItem *conversationItem = NULL;
if(mConversationsRoot &&
mConversationsRoot->getCurSelectedItem() &&
mConversationsRoot->getCurSelectedItem()->getViewModelItem())
mConversationsRoot->getCurSelectedItem() &&
mConversationsRoot->getCurSelectedItem()->getViewModelItem())
{
conversationItem = static_cast<LLConversationItem *>(mConversationsRoot->getCurSelectedItem()->getViewModelItem()) ;
}

View File

@ -43,10 +43,12 @@
class LLPanelChatControlPanel;
class LLChatEntry;
class LLChatHistory;
class LLPanelEmojiComplete;
class LLFloaterIMSessionTab
: public LLTransientDockableFloater
{
using super = LLTransientDockableFloater;
public:
LOG_CLASS(LLFloaterIMSessionTab);
@ -70,9 +72,8 @@ public:
bool isHostAttached() {return mIsHostAttached;}
void setHostAttached(bool is_attached) {mIsHostAttached = is_attached;}
static LLFloaterIMSessionTab* findConversation(const LLUUID& uuid);
static LLFloaterIMSessionTab* getConversation(const LLUUID& uuid);
static LLFloaterIMSessionTab* findConversation(const LLUUID& uuid);
static LLFloaterIMSessionTab* getConversation(const LLUUID& uuid);
bool isNearbyChat() {return mIsNearbyChat;}
@ -82,6 +83,7 @@ public:
/*virtual*/ void draw();
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ void setFocus(BOOL focus);
/*virtual*/ void closeFloater(bool app_quitting = false);
// Handle the left hand participant list widgets
void addConversationViewParticipant(LLConversationItem* item, bool update_view = true);
@ -138,8 +140,8 @@ protected:
virtual void enableDisableCallBtn();
// process focus events to set a currently active session
/* virtual */ void onFocusLost();
/* virtual */ void onFocusReceived();
/* virtual */ void onFocusLost();
// prepare chat's params and out one message to chatHistory
void appendMessage(const LLChat& chat, const LLSD& args = LLSD());
@ -147,6 +149,8 @@ protected:
std::string appendTime();
void assignResizeLimits();
void updateUsedEmojis(LLWString text);
S32 mFloaterExtraWidth;
bool mIsNearbyChat;
@ -154,8 +158,7 @@ protected:
bool mMessagePaneExpanded;
bool mIsParticipantListExpanded;
S32 mMinFloaterHeight;
S32 mMinFloaterHeight;
LLIMModel::LLIMSession* mSession;
@ -170,33 +173,37 @@ protected:
LLLayoutPanel* mContentPanel;
LLLayoutPanel* mToolbarPanel;
LLLayoutPanel* mInputButtonPanel;
LLLayoutPanel* mEmojiRecentPanel;
LLView* mEmojiRecentEmptyText;
LLPanelEmojiComplete* mEmojiRecentIconsCtrl;
LLParticipantList* getParticipantList();
conversations_widgets_map mConversationsWidgets;
LLConversationViewModel mConversationViewModel;
LLFolderView* mConversationsRoot;
LLScrollContainer* mScroller;
LLChatHistory* mChatHistory;
LLChatHistory* mChatHistory;
LLChatEntry* mInputEditor;
LLLayoutPanel * mChatLayoutPanel;
LLLayoutStack * mInputPanels;
LLLayoutPanel* mChatLayoutPanel;
LLLayoutStack* mInputPanels;
LLButton* mExpandCollapseLineBtn;
LLButton* mExpandCollapseBtn;
LLButton* mTearOffBtn;
LLButton* mEmojiBtn;
LLButton* mEmojiRecentPanelToggleBtn;
LLButton* mEmojiPickerToggleBtn;
LLButton* mCloseBtn;
LLButton* mGearBtn;
LLButton* mAddBtn;
LLButton* mVoiceButton;
LLButton* mVoiceButton;
private:
// Handling selection and contextual menu
void doToSelected(const LLSD& userdata);
bool enableContextMenuItem(const LLSD& userdata);
bool checkContextMenuItem(const LLSD& userdata);
void doToSelected(const LLSD& userdata);
bool enableContextMenuItem(const LLSD& userdata);
bool checkContextMenuItem(const LLSD& userdata);
void getSelectedUUIDs(uuid_vec_t& selected_uuids);
void getSelectedUUIDs(uuid_vec_t& selected_uuids);
/// Refreshes the floater at a constant rate.
virtual void refresh() = 0;
@ -210,13 +217,16 @@ private:
void onInputEditorClicked();
static void onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self);
static void onEmojiRecentPanelToggleBtnClicked(LLFloaterIMSessionTab* self);
static void onEmojiPickerToggleBtnClicked(LLFloaterIMSessionTab* self);
void onEmojiRecentPanelOpening();
void onRecentEmojiPicked(const LLSD& value);
void onEmojiPicked(llwchar emoji);
void onEmojiPickerClosed();
bool checkIfTornOff();
bool mIsHostAttached;
bool mHasVisibleBeenInitialized;
bool mIsHostAttached;
bool mHasVisibleBeenInitialized;
LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.

View File

@ -41,6 +41,7 @@ static LLDefaultChildRegistry::Register<LLPanelEmojiComplete> r("emoji_complete"
LLPanelEmojiComplete::Params::Params()
: autosize("autosize")
, noscroll("noscroll")
, max_emoji("max_emoji")
, padding("padding")
, selected_image("selected_image")
@ -50,6 +51,7 @@ LLPanelEmojiComplete::Params::Params()
LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p)
: LLUICtrl(p)
, mAutoSize(p.autosize)
, mNoScroll(p.noscroll)
, mMaxVisible(p.max_emoji)
, mPadding(p.padding)
, mSelectedImage(p.selected_image)
@ -152,7 +154,7 @@ BOOL LLPanelEmojiComplete::handleMouseUp(S32 x, S32 y, MASK mask)
void LLPanelEmojiComplete::onCommit()
{
if (npos != mCurSelected)
if (mCurSelected < mEmojis.size())
{
LLWString wstr;
wstr.push_back(mEmojis.at(mCurSelected));
@ -167,6 +169,14 @@ void LLPanelEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_paren
updateConstraints();
}
void LLPanelEmojiComplete::setEmojis(const LLWString& emojis)
{
mEmojis = emojis;
mCurSelected = 0;
onEmojisChanged();
}
void LLPanelEmojiComplete::setEmojiHint(const std::string& hint)
{
llwchar curEmoji = (mCurSelected < mEmojis.size()) ? mEmojis.at(mCurSelected) : 0;
@ -175,6 +185,11 @@ void LLPanelEmojiComplete::setEmojiHint(const std::string& hint)
size_t curEmojiIdx = (curEmoji) ? mEmojis.find(curEmoji) : std::string::npos;
mCurSelected = (std::string::npos != curEmojiIdx) ? curEmojiIdx : 0;
onEmojisChanged();
}
void LLPanelEmojiComplete::onEmojisChanged()
{
if (mAutoSize)
{
mVisibleEmojis = (U16)std::min(mEmojis.size(), mMaxVisible);
@ -233,9 +248,13 @@ void LLPanelEmojiComplete::updateConstraints()
void LLPanelEmojiComplete::updateScrollPos()
{
const size_t cntEmoji = mEmojis.size();
if (0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected)
if (mNoScroll || 0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected)
{
mScrollPos = 0;
if (mCurSelected >= mVisibleEmojis)
{
mCurSelected = mVisibleEmojis ? mVisibleEmojis - 1 : 0;
}
}
else if (cntEmoji - 1 == mCurSelected)
{
@ -273,11 +292,11 @@ BOOL LLFloaterEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_pare
handled = true;
break;
}
}
if (handled)
return TRUE;
return LLFloater::handleKey(key, mask, called_from_parent);
}

View File

@ -40,6 +40,7 @@ public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<bool> autosize;
Optional<bool> noscroll;
Optional<S32> max_emoji,
padding;
@ -50,6 +51,7 @@ public:
protected:
LLPanelEmojiComplete(const LLPanelEmojiComplete::Params&);
public:
virtual ~LLPanelEmojiComplete();
@ -62,9 +64,13 @@ public:
void reshape(S32 width, S32 height, BOOL called_from_parent) override;
public:
const LLWString& getEmojis() const { return mEmojis; }
size_t getEmojiCount() const { return mEmojis.size(); }
void setEmojiHint(const std::string& hint);
void setEmojis(const LLWString& emojis);
void setEmojiHint(const std::string& hint);
protected:
void LLPanelEmojiComplete::onEmojisChanged();
size_t posToIndex(S32 x, S32 y) const;
void select(size_t emoji_idx);
void selectNext();
@ -76,13 +82,14 @@ protected:
protected:
static constexpr auto npos = std::numeric_limits<size_t>::max();
bool mAutoSize = false;
const bool mAutoSize = false;
const bool mNoScroll = false;
const LLFontGL* mFont;
U16 mEmojiWidth = 0;
size_t mMaxVisible = 0;
S32 mPadding = 8;
const size_t mMaxVisible = 0;
const S32 mPadding = 8;
LLRect mRenderRect;
LLUIImagePtr mSelectedImage;
const LLUIImagePtr mSelectedImage;
LLWString mEmojis;
size_t mVisibleEmojis = 0;

View File

@ -66,13 +66,19 @@
<layout_panel name="chat_layout_panel">
<layout_stack name="input_panels">
<layout_panel name="emoji_button_layout_panel">
<button name="emoji_panel_btn" tool_tip="Emoji-Auswahl öffnen/schliessen"/>
<button name="emoji_picker_toggle_btn" tool_tip="Emoji-Auswahl öffnen/schliessen"/>
<button name="emoji_recent_panel_toggle_btn" tool_tip="Zuletzt verwendete Emoji-Auswahl öffnen/schliessen"/>
</layout_panel>
<layout_panel name="input_button_layout_panel">
<button name="send_chat" label="Senden"/>
</layout_panel>
</layout_stack>
</layout_panel>
<layout_panel name="emoji_recent_layout_panel">
<text name="emoji_recent_empty_text">
Zuletzt verwendete Emojis erscheinen hier
</text>
</layout_panel>
</layout_stack>
</layout_panel>
</layout_stack>

View File

@ -31,7 +31,8 @@
<chat_editor name="chat_box"/>
</layout_panel>
<layout_panel name="emoji_button_layout_panel">
<button name="emoji_panel_btn" tool_tip="Emoji-Auswahl öffnen/schliessen"/>
<button name="emoji_picker_toggle_btn" tool_tip="Emoji-Auswahl öffnen/schliessen"/>
<button name="emoji_recent_panel_toggle_btn" tool_tip="Zuletzt verwendete Emoji-Auswahl öffnen/schliessen"/>
</layout_panel>
<layout_panel name="input_button_layout_panel">
<spinner name="ChatChannel" tool_tip="Kanal, an den der Chat gesendet werden soll. Kann unter Einstellungen -> Chat -> Firestorm -> Kanalauswahl in Eingabezeile anzeigen aktiviert werden." label_width="35"/>
@ -46,6 +47,11 @@
</layout_panel>
</layout_stack>
</layout_panel>
<layout_panel name="emoji_recent_layout_panel">
<text name="emoji_recent_empty_text">
Zuletzt verwendete Emojis erscheinen hier
</text>
</layout_panel>
</layout_stack>
</layout_panel>
</layout_stack>

View File

@ -12,19 +12,14 @@
width="250">
<floater.string name="title_for_recently_used" value="Recently used"/>
<floater.string name="title_for_frequently_used" value="Frequently used"/>
<line_editor
<filter_editor
name="Filter"
label="Start typing to filter"
layout="bottomleft"
follows="bottom|left|right"
text_tentative_color="TextFgTentativeColor"
show_label_focused="true"
max_length_bytes="63"
text_pad_right="5"
text_pad_left="5"
bottom="5"
left="10"
height="29"
height="23"
width="230" />
<scroll_container
name="EmojiGridContainer"

View File

@ -655,7 +655,7 @@
auto_resize="false"
user_resize="false"
name="emoji_button_layout_panel"
width="25"
width="35"
top="0"
bottom="-1">
<button
@ -667,10 +667,25 @@
image_hover_unselected="Toolbar_Middle_Over"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
right="-1"
name="emoji_panel_btn"
right="-11"
name="emoji_picker_toggle_btn"
tool_tip="Show/hide emoji panel"
width="24"/>
<button
follows="right|bottom"
bottom="23"
height="22"
use_font_color="true"
font="EmojiLarge"
image_hover_unselected="Toolbar_Middle_Over"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
image_overlay="Arrow_Down"
right="-1"
name="emoji_recent_panel_toggle_btn"
tool_tip="Shows/hides recent emojis"
left_pad="0"
width="10"/>
</layout_panel>
<layout_panel
visibility_control="FSShowIMSendButton"
@ -693,6 +708,33 @@
</layout_panel>
</layout_stack>
</layout_panel>
<layout_panel
name="emoji_recent_layout_panel"
height="28"
auto_resize="false">
<text
name="emoji_recent_empty_text"
follows="top|left|right"
layout="topleft"
auto_resize="false"
h_pad="20"
v_pad="5"
top="0"
left="5"
right="-1"
height="25"
>Recently used emojis will appear here</text>
<emoji_complete
name="emoji_recent_icons_ctrl"
follows="top|left|right"
layout="topleft"
noscroll="true"
max_emoji="20"
top="0"
left="5"
right="-1"
height="25"/>
</layout_panel>
</layout_stack>
</layout_panel>
</layout_stack>

View File

@ -276,7 +276,7 @@
auto_resize="false"
user_resize="false"
name="emoji_button_layout_panel"
width="25">
width="35">
<button
follows="right|bottom"
bottom="-1"
@ -286,10 +286,25 @@
image_hover_unselected="Toolbar_Middle_Over"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
right="-1"
name="emoji_panel_btn"
right="-11"
name="emoji_picker_toggle_btn"
tool_tip="Show/hide emoji panel"
width="24"/>
<button
follows="right|bottom"
bottom="-1"
height="22"
use_font_color="true"
font="EmojiLarge"
image_hover_unselected="Toolbar_Middle_Over"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
image_overlay="Arrow_Down"
right="-1"
name="emoji_recent_panel_toggle_btn"
tool_tip="Shows/hides recent emojis"
left_pad="0"
width="10"/>
</layout_panel>
<layout_panel
visibility_control="FSShowChatChannel"
@ -384,6 +399,33 @@
</layout_panel>
</layout_stack>
</layout_panel>
<layout_panel
name="emoji_recent_layout_panel"
height="28"
auto_resize="false">
<text
name="emoji_recent_empty_text"
follows="top|left|right"
layout="topleft"
auto_resize="false"
h_pad="20"
v_pad="5"
top="0"
left="5"
right="-1"
height="25"
>Recently used emojis will appear here</text>
<emoji_complete
name="emoji_recent_icons_ctrl"
follows="top|left|right"
layout="topleft"
noscroll="true"
max_emoji="20"
top="0"
left="5"
right="-1"
height="25"/>
</layout_panel>
</layout_stack>
</layout_panel>
</layout_stack>

View File

@ -291,6 +291,7 @@
height="20"
is_expandable="true"
text_tentative_color="TextFgTentativeColor"
bg_writeable_color="ScriptBackground"
name="chat_editor"
max_length="1023"
spellcheck="true"
@ -300,8 +301,8 @@
right="-30"
wrap="true" />
<button
name="emoji_panel_btn"
tool_tip="Shows/hides emoji picker"
name="emoji_recent_panel_toggle_btn"
tool_tip="Shows/hides recent emojis"
follows="right|bottom"
use_font_color="true"
font="EmojiLarge"
@ -332,6 +333,43 @@
</layout_panel>
</layout_stack>
</layout_panel>
<layout_panel
name="emoji_recent_layout_panel"
height="35"
auto_resize="false">
<text
name="emoji_recent_empty_text"
follows="top|left|right"
layout="topleft"
auto_resize="false"
h_pad="20"
v_pad="10"
top="0"
left="5"
right="-60"
height="30"
>Recently used emojis will appear here</text>
<emoji_complete
name="emoji_recent_icons_ctrl"
follows="top|left|right"
layout="topleft"
noscroll="true"
max_emoji="20"
top="0"
left="5"
right="-60"
height="30"/>
<button
name="emoji_picker_toggle_btn"
label="More"
tool_tip="Shows/hides emoji picker"
follows="right|bottom"
layout="topleft"
bottom="-5"
right="-5"
height="30"
width="60"/>
</layout_panel>
</layout_stack>
</view>
</floater>

View File

@ -57,6 +57,12 @@
#if 0
#ifndef LL_WINDOWS
typedef struct {
void *re_pcre;
size_t re_nsub;
size_t re_erroffset;
} regex_t;
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#endif