Add mini emoji (auto-)complete helper

meow-7.2.2
Kitty Barnett 2022-10-23 16:10:06 +02:00
parent 8694f055b6
commit d95571cf7c
6 changed files with 346 additions and 0 deletions

View File

@ -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

View File

@ -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());
}
// ============================================================================

View File

@ -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;
};
// ============================================================================

View File

@ -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>);

View File

@ -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>

View File

@ -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>