Add mini emoji (auto-)complete helper
parent
8694f055b6
commit
d95571cf7c
|
|
@ -441,6 +441,7 @@ set(viewer_SOURCE_FILES
|
|||
llpaneleditsky.cpp
|
||||
llpaneleditwater.cpp
|
||||
llpaneleditwearable.cpp
|
||||
llpanelemojicomplete.cpp
|
||||
llpanelenvironment.cpp
|
||||
llpanelexperiencelisteditor.cpp
|
||||
llpanelexperiencelog.cpp
|
||||
|
|
@ -1072,6 +1073,7 @@ set(viewer_HEADER_FILES
|
|||
llpaneleditsky.h
|
||||
llpaneleditwater.h
|
||||
llpaneleditwearable.h
|
||||
llpanelemojicomplete.h
|
||||
llpanelenvironment.h
|
||||
llpanelexperiencelisteditor.h
|
||||
llpanelexperiencelog.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
* @file llpanelemojicomplete.h
|
||||
* @brief Header file for LLPanelEmojiComplete
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=lgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llemojidictionary.h"
|
||||
#include "llpanelemojicomplete.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
constexpr U32 MIN_MOUSE_MOVE_DELTA = 4;
|
||||
|
||||
// ============================================================================
|
||||
// LLPanelEmojiComplete
|
||||
//
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLPanelEmojiComplete> r("emoji_complete");
|
||||
|
||||
LLPanelEmojiComplete::Params::Params()
|
||||
: selected_image("selected_image")
|
||||
{
|
||||
}
|
||||
|
||||
LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p)
|
||||
: LLUICtrl(p)
|
||||
, mSelectedImage(p.selected_image)
|
||||
{
|
||||
setFont(p.font);
|
||||
}
|
||||
|
||||
LLPanelEmojiComplete::~LLPanelEmojiComplete()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::draw()
|
||||
{
|
||||
if (!mEmojis.empty())
|
||||
{
|
||||
const S32 centerY = mRenderRect.getCenterY();
|
||||
const size_t firstVisibleIdx = mScrollPos, lastVisibleIdx = llmin(mScrollPos + mVisibleEmojis, mEmojis.size()) - 1;
|
||||
|
||||
if (mCurSelected >= firstVisibleIdx && mCurSelected <= lastVisibleIdx)
|
||||
{
|
||||
const S32 emoji_left = mRenderRect.mLeft + (mCurSelected - firstVisibleIdx) * mEmojiWidth;
|
||||
const S32 emoji_height = mFont->getLineHeight() + mPadding;
|
||||
mSelectedImage->draw(emoji_left, centerY - emoji_height / 2, mEmojiWidth, emoji_height);
|
||||
}
|
||||
|
||||
U32 left = mRenderRect.mLeft + mPadding;
|
||||
for (U32 curIdx = firstVisibleIdx; curIdx <= lastVisibleIdx; curIdx++)
|
||||
{
|
||||
mFont->render(
|
||||
mEmojis, curIdx,
|
||||
left, centerY,
|
||||
LLColor4::white, LLFontGL::LEFT, LLFontGL::VCENTER, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW_SOFT,
|
||||
1, S32_MAX, nullptr, false, true);
|
||||
left += mEmojiWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLPanelEmojiComplete::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLVector2 curHover(x, y);
|
||||
if ((mLastHover - curHover).lengthSquared() > MIN_MOUSE_MOVE_DELTA)
|
||||
{
|
||||
mCurSelected = posToIndex(x, y);
|
||||
mLastHover = curHover;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLPanelEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
if (MASK_NONE == mask)
|
||||
{
|
||||
bool handled = false;
|
||||
switch (key)
|
||||
{
|
||||
case KEY_LEFT:
|
||||
case KEY_UP:
|
||||
selectPrevious();
|
||||
handled = true;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case KEY_DOWN:
|
||||
selectNext();
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
LLUICtrl::reshape(width, height, called_from_parent);
|
||||
updateConstraints();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::setEmojiHint(const std::string& hint)
|
||||
{
|
||||
mEmojis = LLEmojiDictionary::instance().findMatchingEmojis(hint);
|
||||
mScrollPos = llmin(mScrollPos, mEmojis.size());
|
||||
updateConstraints();
|
||||
}
|
||||
|
||||
size_t LLPanelEmojiComplete::posToIndex(S32 x, S32 y) const
|
||||
{
|
||||
if (mRenderRect.pointInRect(x, y))
|
||||
{
|
||||
return llmin((size_t)x / mEmojiWidth, mEmojis.size() - 1);
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::select(size_t emoji_idx)
|
||||
{
|
||||
mCurSelected = llclamp<size_t>(emoji_idx, 0, mEmojis.size());
|
||||
updateScrollPos();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::selectNext()
|
||||
{
|
||||
select(mCurSelected + 1 < mEmojis.size() ? mCurSelected + 1 : 0);
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::selectPrevious()
|
||||
{
|
||||
select(mCurSelected - 1 >= 0 ? mCurSelected - 1 : mEmojis.size() - 1);
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::setFont(const LLFontGL* fontp)
|
||||
{
|
||||
mFont = fontp;
|
||||
updateConstraints();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::updateConstraints()
|
||||
{
|
||||
const S32 ctrlWidth = getLocalRect().getWidth();
|
||||
|
||||
mEmojiWidth = mFont->getWidthF32(u8"\U0001F431") + mPadding * 2;
|
||||
mVisibleEmojis = ctrlWidth / mEmojiWidth;
|
||||
mRenderRect = getLocalRect().stretch((ctrlWidth - mVisibleEmojis * mEmojiWidth) / -2, 0);
|
||||
|
||||
updateScrollPos();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::updateScrollPos()
|
||||
{
|
||||
const size_t cntEmoji = mEmojis.size();
|
||||
if (0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected)
|
||||
{
|
||||
mScrollPos = 0;
|
||||
}
|
||||
else if (cntEmoji - 1 == mCurSelected)
|
||||
{
|
||||
mScrollPos = mCurSelected - mVisibleEmojis + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mScrollPos = mCurSelected - ((float)mCurSelected / (cntEmoji - 2) * (mVisibleEmojis - 2));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLFloaterEmojiComplete
|
||||
//
|
||||
|
||||
LLFloaterEmojiComplete::LLFloaterEmojiComplete(const LLSD& sdKey)
|
||||
: LLFloater(sdKey)
|
||||
{
|
||||
// This floater should hover on top of our dependent (with the dependent having the focus)
|
||||
setFocusStealsFrontmost(false);
|
||||
setAutoFocus(false);
|
||||
setBackgroundVisible(false);
|
||||
}
|
||||
|
||||
void LLFloaterEmojiComplete::onOpen(const LLSD& key)
|
||||
{
|
||||
findChild<LLPanelEmojiComplete>("emoji_complete_ctrl")->setEmojiHint(key["hint"].asString());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* @file llpanelemojicomplete.h
|
||||
* @brief Header file for LLPanelEmojiComplete
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "lluictrl.h"
|
||||
|
||||
// ============================================================================
|
||||
// LLPanelEmojiComplete
|
||||
//
|
||||
|
||||
class LLPanelEmojiComplete : public LLUICtrl
|
||||
{
|
||||
friend class LLUICtrlFactory;
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
|
||||
{
|
||||
Optional<LLUIImage*> selected_image;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
protected:
|
||||
LLPanelEmojiComplete(const LLPanelEmojiComplete::Params&);
|
||||
public:
|
||||
virtual ~LLPanelEmojiComplete();
|
||||
|
||||
void draw() override;
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask) override;
|
||||
BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override;
|
||||
void reshape(S32 width, S32 height, BOOL called_from_parent) override;
|
||||
|
||||
public:
|
||||
void setEmojiHint(const std::string& hint);
|
||||
protected:
|
||||
size_t posToIndex(S32 x, S32 y) const;
|
||||
void select(size_t emoji_idx);
|
||||
void selectNext();
|
||||
void selectPrevious();
|
||||
void setFont(const LLFontGL* fontp);
|
||||
void updateConstraints();
|
||||
void updateScrollPos();
|
||||
|
||||
protected:
|
||||
static constexpr auto npos = std::numeric_limits<size_t>::max();
|
||||
|
||||
const LLFontGL* mFont;
|
||||
U16 mEmojiWidth = 0;
|
||||
LLUIImagePtr mSelectedImage;
|
||||
|
||||
LLWString mEmojis;
|
||||
U16 mVisibleEmojis = 0;
|
||||
size_t mFirstVisible = 0;
|
||||
size_t mScrollPos = 0;
|
||||
size_t mCurSelected = 0;
|
||||
LLVector2 mLastHover;
|
||||
|
||||
S32 mPadding = 8;
|
||||
LLRect mRenderRect;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLFloaterEmojiComplete
|
||||
//
|
||||
|
||||
class LLFloaterEmojiComplete : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLFloaterEmojiComplete(const LLSD& sdKey);
|
||||
|
||||
public:
|
||||
void onOpen(const LLSD& key) override;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -155,6 +155,7 @@
|
|||
#include "llfloaterimnearbychat.h"
|
||||
#include "llpanelblockedlist.h"
|
||||
#include "llpanelclassified.h"
|
||||
#include "llpanelemojicomplete.h"
|
||||
#include "llpreviewanim.h"
|
||||
#include "llpreviewgesture.h"
|
||||
#include "llpreviewnotecard.h"
|
||||
|
|
@ -229,6 +230,7 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>);
|
||||
LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>);
|
||||
|
||||
LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", &LLFloaterReg::build<LLFloaterEmojiComplete>);
|
||||
LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>);
|
||||
|
||||
LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
can_close="false"
|
||||
can_dock="false"
|
||||
can_drag_on_left="false"
|
||||
can_minimize="false"
|
||||
can_resize="false"
|
||||
can_tear_off="false"
|
||||
header_height="0"
|
||||
layout="topleft"
|
||||
legacy_header_height="0"
|
||||
height="40"
|
||||
single_instance="true"
|
||||
width="240"
|
||||
>
|
||||
<emoji_complete
|
||||
height="30"
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
top="5"
|
||||
width="230"
|
||||
name="emoji_complete_ctrl"
|
||||
>
|
||||
</emoji_complete>
|
||||
</floater>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<emoji_complete
|
||||
font="EmojiHuge"
|
||||
hover_image="ListItem_Over"
|
||||
selected_image="ListItem_Select"
|
||||
>
|
||||
</emoji_complete>
|
||||
Loading…
Reference in New Issue