Merge branch 'DRTVWR-489' of https://github.com/secondlife/viewer
# Conflicts: # indra/newview/skins/default/xui/en/floater_emoji_picker.xmlmaster
commit
c2484ffb36
|
|
@ -0,0 +1,6 @@
|
|||
@ECHO OFF
|
||||
REM call c:\python27\autobuild11\scripts\activate.bat
|
||||
autobuild --version
|
||||
autobuild configure -c ReleaseFS -v -- --chan private
|
||||
REM autobuild build --no-configure -c ReleaseFS
|
||||
pause
|
||||
|
|
@ -366,6 +366,7 @@ public:
|
|||
static void replaceNonstandardASCII( string_type& string, T replacement );
|
||||
static void replaceChar( string_type& string, T target, T replacement );
|
||||
static void replaceString( string_type& string, string_type target, string_type replacement );
|
||||
static string_type capitalize(const string_type& str);
|
||||
static void capitalize(string_type& str);
|
||||
|
||||
static BOOL containsNonprintable(const string_type& string);
|
||||
|
|
@ -1610,6 +1611,15 @@ void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spa
|
|||
str = out_str;
|
||||
}
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
std::basic_string<T> LLStringUtilBase<T>::capitalize(const string_type& str)
|
||||
{
|
||||
string_type result(str);
|
||||
capitalize(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void LLStringUtilBase<T>::capitalize(string_type& str)
|
||||
|
|
|
|||
|
|
@ -558,6 +558,8 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type
|
|||
|
||||
// Fallback fonts with a functor have precedence over everything else
|
||||
fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin();
|
||||
/* This leads to a bug SL-19831 "Check marks in the menu are less visible."
|
||||
** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render"
|
||||
for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback)
|
||||
{
|
||||
if (it_fallback->second(wch))
|
||||
|
|
@ -569,6 +571,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Initialize char to glyph map
|
||||
glyph_index = FT_Get_Char_Index(mFTFace, wch);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,12 @@
|
|||
// Constants
|
||||
//
|
||||
|
||||
constexpr char SKINNED_EMOJI_FILENAME[] = "emoji_characters.xml";
|
||||
static const std::string SKINNED_EMOJI_FILENAME("emoji_characters.xml");
|
||||
static const std::string SKINNED_CATEGORY_FILENAME("emoji_categories.xml");
|
||||
static const std::string COMMON_GROUP_FILENAME("emoji_groups.xml");
|
||||
static const std::string GROUP_NAME_ALL("all");
|
||||
static const std::string GROUP_NAME_OTHERS("others");
|
||||
static const std::string GROUP_NAME_SKIP("skip");
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
|
|
@ -50,82 +55,68 @@ std::list<T> llsd_array_to_list(const LLSD& sd, std::function<void(T&)> mutator
|
|||
template<>
|
||||
std::list<std::string> llsd_array_to_list(const LLSD& sd, std::function<void(std::string&)> mutator)
|
||||
{
|
||||
std::list<std::string> result;
|
||||
for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it)
|
||||
{
|
||||
const LLSD& entry = *it;
|
||||
if (!entry.isString())
|
||||
continue;
|
||||
std::list<std::string> result;
|
||||
for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it)
|
||||
{
|
||||
const LLSD& entry = *it;
|
||||
if (!entry.isString())
|
||||
continue;
|
||||
|
||||
result.push_back(entry.asStringRef());
|
||||
if (mutator)
|
||||
{
|
||||
mutator(result.back());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LLEmojiDescriptor::LLEmojiDescriptor(const LLSD& descriptor_sd)
|
||||
{
|
||||
Name = descriptor_sd["Name"].asStringRef();
|
||||
|
||||
const LLWString emoji_string = utf8str_to_wstring(descriptor_sd["Character"].asString());
|
||||
Character = (1 == emoji_string.size()) ? emoji_string[0] : L'\0'; // We don't currently support character composition
|
||||
|
||||
auto toLower = [](std::string& str) { LLStringUtil::toLower(str); };
|
||||
ShortCodes = llsd_array_to_list<std::string>(descriptor_sd["ShortCodes"], toLower);
|
||||
Categories = llsd_array_to_list<std::string>(descriptor_sd["Categories"], toLower);
|
||||
|
||||
if (Name.empty())
|
||||
{
|
||||
Name = ShortCodes.front();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLEmojiDescriptor::isValid() const
|
||||
{
|
||||
return
|
||||
Character &&
|
||||
!ShortCodes.empty() &&
|
||||
!Categories.empty();
|
||||
result.push_back(entry.asStringRef());
|
||||
if (mutator)
|
||||
{
|
||||
mutator(result.back());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct emoji_filter_base
|
||||
{
|
||||
emoji_filter_base(const std::string& needle)
|
||||
{
|
||||
// Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category
|
||||
mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle;
|
||||
LLStringUtil::toLower(mNeedle);
|
||||
}
|
||||
emoji_filter_base(const std::string& needle)
|
||||
{
|
||||
// Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category
|
||||
mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle;
|
||||
LLStringUtil::toLower(mNeedle);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string mNeedle;
|
||||
std::string mNeedle;
|
||||
};
|
||||
|
||||
struct emoji_filter_shortcode_or_category_contains : public emoji_filter_base
|
||||
{
|
||||
emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {}
|
||||
emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {}
|
||||
|
||||
bool operator()(const LLEmojiDescriptor& descr) const
|
||||
{
|
||||
for (const auto& short_code : descr.ShortCodes)
|
||||
{
|
||||
if (boost::icontains(short_code, mNeedle))
|
||||
return true;
|
||||
}
|
||||
bool operator()(const LLEmojiDescriptor& descr) const
|
||||
{
|
||||
for (const auto& short_code : descr.ShortCodes)
|
||||
{
|
||||
if (boost::icontains(short_code, mNeedle))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& category : descr.Categories)
|
||||
{
|
||||
if (boost::icontains(category, mNeedle))
|
||||
return true;
|
||||
}
|
||||
if (boost::icontains(descr.Category, mNeedle))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
std::string LLEmojiDescriptor::getShortCodes() const
|
||||
{
|
||||
std::string result;
|
||||
for (const std::string& shortCode : ShortCodes)
|
||||
{
|
||||
if (!result.empty())
|
||||
{
|
||||
result += ", ";
|
||||
}
|
||||
result += shortCode;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiDictionary class
|
||||
//
|
||||
|
|
@ -137,91 +128,278 @@ LLEmojiDictionary::LLEmojiDictionary()
|
|||
// static
|
||||
void LLEmojiDictionary::initClass()
|
||||
{
|
||||
LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton();
|
||||
LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton();
|
||||
|
||||
LLSD data;
|
||||
|
||||
auto filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN);
|
||||
if (filenames.empty())
|
||||
{
|
||||
LL_WARNS() << "Emoji file characters not found" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
const std::string filename = filenames.back();
|
||||
llifstream file(filename.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL;
|
||||
LLSDSerialize::fromXML(data, file);
|
||||
}
|
||||
|
||||
if (data.isUndefined())
|
||||
{
|
||||
LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLSD::array_const_iterator descriptor_it = data.beginArray(), descriptor_end = data.endArray(); descriptor_it != descriptor_end; ++descriptor_it)
|
||||
{
|
||||
LLEmojiDescriptor descriptor(*descriptor_it);
|
||||
if (!descriptor.isValid())
|
||||
{
|
||||
LL_WARNS() << "Skipping invalid emoji descriptor " << descriptor.Character << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
pThis->addEmoji(std::move(descriptor));
|
||||
}
|
||||
pThis->loadTranslations();
|
||||
pThis->loadGroups();
|
||||
pThis->loadEmojis();
|
||||
}
|
||||
|
||||
LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const
|
||||
{
|
||||
LLWString result;
|
||||
boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)),
|
||||
std::back_inserter(result), [](const auto& descr) { return descr.Character; });
|
||||
return result;
|
||||
LLWString result;
|
||||
boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)),
|
||||
std::back_inserter(result), [](const auto& descr) { return descr.Character; });
|
||||
return result;
|
||||
}
|
||||
|
||||
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const
|
||||
{
|
||||
const auto it = mEmoji2Descr.find(emoji);
|
||||
return (mEmoji2Descr.end() != it) ? it->second : nullptr;
|
||||
const auto it = mEmoji2Descr.find(emoji);
|
||||
return (mEmoji2Descr.end() != it) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const
|
||||
{
|
||||
const auto it = mShortCode2Descr.find(short_code);
|
||||
return (mShortCode2Descr.end() != it) ? it->second : nullptr;
|
||||
const auto it = mShortCode2Descr.find(short_code);
|
||||
return (mShortCode2Descr.end() != it) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const
|
||||
{
|
||||
const auto it = mEmoji2Descr.find(ch);
|
||||
return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null;
|
||||
const auto it = mEmoji2Descr.find(ch);
|
||||
return (mEmoji2Descr.end() != it) ? it->second->ShortCodes.front() : LLStringUtil::null;
|
||||
}
|
||||
|
||||
bool LLEmojiDictionary::isEmoji(llwchar ch) const
|
||||
{
|
||||
// Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6
|
||||
if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000))
|
||||
{
|
||||
return mEmoji2Descr.find(ch) != mEmoji2Descr.end();
|
||||
}
|
||||
// Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6
|
||||
if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000))
|
||||
{
|
||||
return mEmoji2Descr.find(ch) != mEmoji2Descr.end();
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr)
|
||||
void LLEmojiDictionary::loadTranslations()
|
||||
{
|
||||
mEmojis.push_back(descr);
|
||||
mEmoji2Descr.insert(std::make_pair(descr.Character, &mEmojis.back()));
|
||||
for (const std::string& shortCode : descr.ShortCodes)
|
||||
{
|
||||
mShortCode2Descr.insert(std::make_pair(shortCode, &mEmojis.back()));
|
||||
}
|
||||
for (const std::string& category : descr.Categories)
|
||||
{
|
||||
mCategory2Descrs[category].push_back(&mEmojis.back());
|
||||
}
|
||||
std::vector<std::string> filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_CATEGORY_FILENAME, LLDir::CURRENT_SKIN);
|
||||
if (filenames.empty())
|
||||
{
|
||||
LL_WARNS() << "Emoji file categories not found" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string filename = filenames.back();
|
||||
llifstream file(filename.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS() << "Emoji file categories failed to open" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS() << "Loading emoji categories file at " << filename << LL_ENDL;
|
||||
|
||||
LLSD data;
|
||||
LLSDSerialize::fromXML(data, file);
|
||||
if (data.isUndefined())
|
||||
{
|
||||
LL_WARNS() << "Emoji file categories missing or ill-formed" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Register translations for all categories
|
||||
for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it)
|
||||
{
|
||||
const LLSD& sd = *it;
|
||||
const std::string& name = sd["Name"].asStringRef();
|
||||
const std::string& category = sd["Category"].asStringRef();
|
||||
if (!name.empty() && !category.empty())
|
||||
{
|
||||
mTranslations[name] = category;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Skipping invalid emoji category '" << name << "' => '" << category << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::loadGroups()
|
||||
{
|
||||
const std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, COMMON_GROUP_FILENAME);
|
||||
llifstream file(filename.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS() << "Emoji file groups failed to open" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS() << "Loading emoji groups file at " << filename << LL_ENDL;
|
||||
|
||||
LLSD data;
|
||||
LLSDSerialize::fromXML(data, file);
|
||||
if (data.isUndefined())
|
||||
{
|
||||
LL_WARNS() << "Emoji file groups missing or ill-formed" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
mGroups.clear();
|
||||
// Add group "all"
|
||||
mGroups.emplace_back();
|
||||
// https://www.compart.com/en/unicode/U+1F50D
|
||||
mGroups.front().Character = 0x1F50D;
|
||||
// https://www.compart.com/en/unicode/U+1F302
|
||||
llwchar iconOthers = 0x1F302;
|
||||
|
||||
// Register all groups
|
||||
for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it)
|
||||
{
|
||||
const LLSD& sd = *it;
|
||||
const std::string& name = sd["Name"].asStringRef();
|
||||
if (name == GROUP_NAME_ALL)
|
||||
{
|
||||
mGroups.front().Character = loadIcon(sd);
|
||||
}
|
||||
else if (name == GROUP_NAME_OTHERS)
|
||||
{
|
||||
iconOthers = loadIcon(sd);
|
||||
}
|
||||
else if (name == GROUP_NAME_SKIP)
|
||||
{
|
||||
mSkipCategories = loadCategories(sd);
|
||||
translateCategories(mSkipCategories);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new group
|
||||
mGroups.emplace_back();
|
||||
LLEmojiGroup& group = mGroups.back();
|
||||
group.Character = loadIcon(sd);
|
||||
group.Categories = loadCategories(sd);
|
||||
translateCategories(group.Categories);
|
||||
|
||||
for (const std::string& category : group.Categories)
|
||||
{
|
||||
mCategory2Group.insert(std::make_pair(category, &group));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add group "others"
|
||||
mGroups.emplace_back();
|
||||
mGroups.back().Character = iconOthers;
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::loadEmojis()
|
||||
{
|
||||
std::vector<std::string> filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN);
|
||||
if (filenames.empty())
|
||||
{
|
||||
LL_WARNS() << "Emoji file characters not found" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string filename = filenames.back();
|
||||
llifstream file(filename.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS() << "Emoji file characters failed to open" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL;
|
||||
|
||||
LLSD data;
|
||||
LLSDSerialize::fromXML(data, file);
|
||||
if (data.isUndefined())
|
||||
{
|
||||
LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it)
|
||||
{
|
||||
const LLSD& sd = *it;
|
||||
|
||||
llwchar icon = loadIcon(sd);
|
||||
if (!icon)
|
||||
{
|
||||
LL_WARNS() << "Skipping invalid emoji descriptor (no icon)" << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::list<std::string> categories = loadCategories(sd);
|
||||
if (categories.empty())
|
||||
{
|
||||
LL_WARNS() << "Skipping invalid emoji descriptor (no categories)" << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string category = categories.front();
|
||||
|
||||
if (std::find(mSkipCategories.begin(), mSkipCategories.end(), category) != mSkipCategories.end())
|
||||
{
|
||||
// This category is listed for skip
|
||||
continue;
|
||||
}
|
||||
|
||||
std::list<std::string> shortCodes = loadShortCodes(sd);
|
||||
if (shortCodes.empty())
|
||||
{
|
||||
LL_WARNS() << "Skipping invalid emoji descriptor (no shortCodes)" << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mCategory2Group.find(category) == mCategory2Group.end())
|
||||
{
|
||||
// Add unknown category to "others" group
|
||||
mGroups.back().Categories.push_back(category);
|
||||
mCategory2Group.insert(std::make_pair(category, &mGroups.back()));
|
||||
}
|
||||
|
||||
mEmojis.emplace_back();
|
||||
LLEmojiDescriptor& emoji = mEmojis.back();
|
||||
emoji.Character = icon;
|
||||
emoji.Category = category;
|
||||
emoji.ShortCodes = std::move(shortCodes);
|
||||
|
||||
mEmoji2Descr.insert(std::make_pair(icon, &emoji));
|
||||
mCategory2Descrs[category].push_back(&emoji);
|
||||
for (const std::string& shortCode : emoji.ShortCodes)
|
||||
{
|
||||
mShortCode2Descr.insert(std::make_pair(shortCode, &emoji));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llwchar LLEmojiDictionary::loadIcon(const LLSD& sd)
|
||||
{
|
||||
// We don't currently support character composition
|
||||
const LLWString icon = utf8str_to_wstring(sd["Character"].asString());
|
||||
return (1 == icon.size()) ? icon[0] : L'\0';
|
||||
}
|
||||
|
||||
static inline std::list<std::string> loadStrings(const LLSD& sd, const std::string key)
|
||||
{
|
||||
auto toLower = [](std::string& str) { LLStringUtil::toLower(str); };
|
||||
return llsd_array_to_list<std::string>(sd[key], toLower);
|
||||
}
|
||||
|
||||
std::list<std::string> LLEmojiDictionary::loadCategories(const LLSD& sd)
|
||||
{
|
||||
static const std::string categoriesKey("Categories");
|
||||
return loadStrings(sd, categoriesKey);
|
||||
}
|
||||
|
||||
std::list<std::string> LLEmojiDictionary::loadShortCodes(const LLSD& sd)
|
||||
{
|
||||
static const std::string shortCodesKey("ShortCodes");
|
||||
return loadStrings(sd, shortCodesKey);
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::translateCategories(std::list<std::string>& categories)
|
||||
{
|
||||
for (std::string& category : categories)
|
||||
{
|
||||
auto it = mTranslations.find(category);
|
||||
if (it != mTranslations.end())
|
||||
{
|
||||
category = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -36,14 +36,20 @@
|
|||
|
||||
struct LLEmojiDescriptor
|
||||
{
|
||||
LLEmojiDescriptor(const LLSD& descriptor_sd);
|
||||
llwchar Character;
|
||||
std::string Category;
|
||||
std::list<std::string> ShortCodes;
|
||||
std::string getShortCodes() const;
|
||||
};
|
||||
|
||||
bool isValid() const;
|
||||
// ============================================================================
|
||||
// LLEmojiGroup class
|
||||
//
|
||||
|
||||
std::string Name;
|
||||
llwchar Character;
|
||||
std::list<std::string> ShortCodes;
|
||||
std::list<std::string> Categories;
|
||||
struct LLEmojiGroup
|
||||
{
|
||||
llwchar Character;
|
||||
std::list<std::string> Categories;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -52,36 +58,48 @@ struct LLEmojiDescriptor
|
|||
|
||||
class LLEmojiDictionary : public LLParamSingleton<LLEmojiDictionary>, public LLInitClass<LLEmojiDictionary>
|
||||
{
|
||||
LLSINGLETON(LLEmojiDictionary);
|
||||
~LLEmojiDictionary() override {};
|
||||
LLSINGLETON(LLEmojiDictionary);
|
||||
~LLEmojiDictionary() override {};
|
||||
|
||||
public:
|
||||
typedef std::map<llwchar, const LLEmojiDescriptor*> emoji2descr_map_t;
|
||||
typedef emoji2descr_map_t::value_type emoji2descr_item_t;
|
||||
typedef std::map<std::string, const LLEmojiDescriptor*> code2descr_map_t;
|
||||
typedef code2descr_map_t::value_type code2descr_item_t;
|
||||
typedef std::map<std::string, std::vector<const LLEmojiDescriptor*>> cat2descrs_map_t;
|
||||
typedef cat2descrs_map_t::value_type cat2descrs_item_t;
|
||||
typedef std::map<std::string, std::string> cat2cat_map_t;
|
||||
typedef std::map<std::string, const LLEmojiGroup*> cat2group_map_t;
|
||||
typedef std::map<llwchar, const LLEmojiDescriptor*> emoji2descr_map_t;
|
||||
typedef std::map<std::string, const LLEmojiDescriptor*> code2descr_map_t;
|
||||
typedef std::map<std::string, std::vector<const LLEmojiDescriptor*>> cat2descrs_map_t;
|
||||
|
||||
static void initClass();
|
||||
LLWString findMatchingEmojis(const std::string& needle) const;
|
||||
const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const;
|
||||
const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const;
|
||||
std::string getNameFromEmoji(llwchar ch) const;
|
||||
bool isEmoji(llwchar ch) const;
|
||||
static void initClass();
|
||||
LLWString findMatchingEmojis(const std::string& needle) const;
|
||||
const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const;
|
||||
const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const;
|
||||
std::string getNameFromEmoji(llwchar ch) const;
|
||||
bool isEmoji(llwchar ch) const;
|
||||
|
||||
const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; }
|
||||
const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; }
|
||||
const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; }
|
||||
const std::vector<LLEmojiGroup>& getGroups() const { return mGroups; }
|
||||
const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; }
|
||||
const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; }
|
||||
const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; }
|
||||
|
||||
private:
|
||||
void addEmoji(LLEmojiDescriptor&& descr);
|
||||
void loadTranslations();
|
||||
void loadGroups();
|
||||
void loadEmojis();
|
||||
|
||||
static llwchar loadIcon(const LLSD& sd);
|
||||
static std::list<std::string> loadCategories(const LLSD& sd);
|
||||
static std::list<std::string> loadShortCodes(const LLSD& sd);
|
||||
void translateCategories(std::list<std::string>& categories);
|
||||
|
||||
private:
|
||||
std::list<LLEmojiDescriptor> mEmojis;
|
||||
emoji2descr_map_t mEmoji2Descr;
|
||||
code2descr_map_t mShortCode2Descr;
|
||||
cat2descrs_map_t mCategory2Descrs;
|
||||
std::vector<LLEmojiGroup> mGroups;
|
||||
std::list<LLEmojiDescriptor> mEmojis;
|
||||
std::list<std::string> mSkipCategories;
|
||||
|
||||
cat2cat_map_t mTranslations;
|
||||
cat2group_map_t mCategory2Group;
|
||||
emoji2descr_map_t mEmoji2Descr;
|
||||
cat2descrs_map_t mCategory2Descrs;
|
||||
code2descr_map_t mShortCode2Descr;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -37,53 +37,44 @@ static LLDefaultChildRegistry::Register<LLScrollingPanelList> r("scrolling_panel
|
|||
|
||||
// This could probably be integrated with LLScrollContainer -SJB
|
||||
|
||||
LLScrollingPanelList::Params::Params()
|
||||
: is_horizontal("is_horizontal")
|
||||
, padding("padding")
|
||||
, spacing("spacing")
|
||||
{
|
||||
}
|
||||
|
||||
LLScrollingPanelList::LLScrollingPanelList(const Params& p)
|
||||
: LLUICtrl(p)
|
||||
, mIsHorizontal(p.is_horizontal)
|
||||
, mPadding(p.padding.isProvided() ? p.padding : DEFAULT_PADDING)
|
||||
, mSpacing(p.spacing.isProvided() ? p.spacing : DEFAULT_SPACING)
|
||||
{
|
||||
}
|
||||
|
||||
void LLScrollingPanelList::clearPanels()
|
||||
{
|
||||
deleteAllChildren();
|
||||
mPanelList.clear();
|
||||
|
||||
LLRect rc = getRect();
|
||||
rc.setLeftTopAndSize(rc.mLeft, rc.mTop, 1, 1);
|
||||
setRect(rc);
|
||||
|
||||
notifySizeChanged(rc.getHeight());
|
||||
rearrange();
|
||||
}
|
||||
|
||||
S32 LLScrollingPanelList::addPanel( LLScrollingPanel* panel )
|
||||
S32 LLScrollingPanelList::addPanel(LLScrollingPanel* panel, bool back)
|
||||
{
|
||||
addChildInBack( panel );
|
||||
mPanelList.push_front( panel );
|
||||
|
||||
// Resize this view
|
||||
S32 total_height = 0;
|
||||
S32 max_width = 0;
|
||||
S32 cur_gap = 0;
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
iter != mPanelList.end(); ++iter)
|
||||
if (back)
|
||||
{
|
||||
LLScrollingPanel *childp = *iter;
|
||||
total_height += childp->getRect().getHeight() + cur_gap;
|
||||
max_width = llmax( max_width, childp->getRect().getWidth() );
|
||||
cur_gap = GAP_BETWEEN_PANELS;
|
||||
addChild(panel);
|
||||
mPanelList.push_back(panel);
|
||||
}
|
||||
LLRect rc = getRect();
|
||||
rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height);
|
||||
setRect(rc);
|
||||
|
||||
notifySizeChanged(rc.getHeight());
|
||||
|
||||
// Reposition each of the child views
|
||||
S32 cur_y = total_height;
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
iter != mPanelList.end(); ++iter)
|
||||
else
|
||||
{
|
||||
LLScrollingPanel *childp = *iter;
|
||||
cur_y -= childp->getRect().getHeight();
|
||||
childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom);
|
||||
cur_y -= GAP_BETWEEN_PANELS;
|
||||
addChildInBack(panel);
|
||||
mPanelList.push_front(panel);
|
||||
}
|
||||
|
||||
return total_height;
|
||||
rearrange();
|
||||
|
||||
return mIsHorizontal ? getRect().getWidth() : getRect().getHeight();
|
||||
}
|
||||
|
||||
void LLScrollingPanelList::removePanel(LLScrollingPanel* panel)
|
||||
|
|
@ -100,7 +91,7 @@ void LLScrollingPanelList::removePanel(LLScrollingPanel* panel)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(iter != mPanelList.end())
|
||||
if (iter != mPanelList.end())
|
||||
{
|
||||
removePanel(index);
|
||||
}
|
||||
|
|
@ -120,36 +111,7 @@ void LLScrollingPanelList::removePanel( U32 panel_index )
|
|||
mPanelList.erase( mPanelList.begin() + panel_index );
|
||||
}
|
||||
|
||||
const S32 GAP_BETWEEN_PANELS = 6;
|
||||
|
||||
// Resize this view
|
||||
S32 total_height = 0;
|
||||
S32 max_width = 0;
|
||||
S32 cur_gap = 0;
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
iter != mPanelList.end(); ++iter)
|
||||
{
|
||||
LLScrollingPanel *childp = *iter;
|
||||
total_height += childp->getRect().getHeight() + cur_gap;
|
||||
max_width = llmax( max_width, childp->getRect().getWidth() );
|
||||
cur_gap = GAP_BETWEEN_PANELS;
|
||||
}
|
||||
LLRect rc = getRect();
|
||||
rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height);
|
||||
setRect(rc);
|
||||
|
||||
notifySizeChanged(rc.getHeight());
|
||||
|
||||
// Reposition each of the child views
|
||||
S32 cur_y = total_height;
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
iter != mPanelList.end(); ++iter)
|
||||
{
|
||||
LLScrollingPanel *childp = *iter;
|
||||
cur_y -= childp->getRect().getHeight();
|
||||
childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom);
|
||||
cur_y -= GAP_BETWEEN_PANELS;
|
||||
}
|
||||
rearrange();
|
||||
}
|
||||
|
||||
void LLScrollingPanelList::updatePanels(BOOL allow_modify)
|
||||
|
|
@ -162,20 +124,91 @@ void LLScrollingPanelList::updatePanels(BOOL allow_modify)
|
|||
}
|
||||
}
|
||||
|
||||
void LLScrollingPanelList::rearrange()
|
||||
{
|
||||
// Resize this view
|
||||
S32 new_width, new_height;
|
||||
if (!mPanelList.empty())
|
||||
{
|
||||
new_width = new_height = mPadding * 2;
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
iter != mPanelList.end(); ++iter)
|
||||
{
|
||||
LLScrollingPanel* childp = *iter;
|
||||
const LLRect& rect = childp->getRect();
|
||||
if (mIsHorizontal)
|
||||
{
|
||||
new_width += rect.getWidth() + mSpacing;
|
||||
new_height = llmax(new_height, rect.getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
new_height += rect.getHeight() + mSpacing;
|
||||
new_width = llmax(new_width, rect.getWidth());
|
||||
}
|
||||
}
|
||||
|
||||
if (mIsHorizontal)
|
||||
{
|
||||
new_width -= mSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_height -= mSpacing;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_width = new_height = 1;
|
||||
}
|
||||
|
||||
LLRect rc = getRect();
|
||||
if (mIsHorizontal || !followsRight())
|
||||
{
|
||||
rc.mRight = rc.mLeft + new_width;
|
||||
}
|
||||
if (!mIsHorizontal || !followsBottom())
|
||||
{
|
||||
rc.mBottom = rc.mTop - new_height;
|
||||
}
|
||||
|
||||
if (rc.mRight != getRect().mRight || rc.mBottom != getRect().mBottom)
|
||||
{
|
||||
setRect(rc);
|
||||
notifySizeChanged();
|
||||
}
|
||||
|
||||
// Reposition each of the child views
|
||||
S32 pos = mIsHorizontal ? mPadding : rc.getHeight() - mPadding;
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
iter != mPanelList.end(); ++iter)
|
||||
{
|
||||
LLScrollingPanel* childp = *iter;
|
||||
const LLRect& rect = childp->getRect();
|
||||
if (mIsHorizontal)
|
||||
{
|
||||
childp->translate(pos - rect.mLeft, rc.getHeight() - mPadding - rect.mTop);
|
||||
pos += rect.getWidth() + mSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
childp->translate(mPadding - rect.mLeft, pos - rect.mTop);
|
||||
pos -= rect.getHeight() + mSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLScrollingPanelList::updatePanelVisiblilty()
|
||||
{
|
||||
// Determine visibility of children.
|
||||
S32 BORDER_WIDTH = 2; // HACK
|
||||
|
||||
LLRect parent_local_rect = getParent()->getRect();
|
||||
parent_local_rect.stretch( -BORDER_WIDTH );
|
||||
|
||||
LLRect parent_screen_rect;
|
||||
getParent()->localPointToScreen(
|
||||
BORDER_WIDTH, 0,
|
||||
getParent()->localPointToScreen(
|
||||
mPadding, mPadding,
|
||||
&parent_screen_rect.mLeft, &parent_screen_rect.mBottom );
|
||||
getParent()->localPointToScreen(
|
||||
parent_local_rect.getWidth() - BORDER_WIDTH, parent_local_rect.getHeight() - BORDER_WIDTH,
|
||||
getParent()->localPointToScreen(
|
||||
getParent()->getRect().getWidth() - mPadding,
|
||||
getParent()->getRect().getHeight() - mPadding,
|
||||
&parent_screen_rect.mRight, &parent_screen_rect.mTop );
|
||||
|
||||
for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();
|
||||
|
|
@ -207,11 +240,12 @@ void LLScrollingPanelList::draw()
|
|||
LLUICtrl::draw();
|
||||
}
|
||||
|
||||
void LLScrollingPanelList::notifySizeChanged(S32 height)
|
||||
void LLScrollingPanelList::notifySizeChanged()
|
||||
{
|
||||
LLSD info;
|
||||
info["action"] = "size_changes";
|
||||
info["height"] = height;
|
||||
info["height"] = getRect().getHeight();
|
||||
info["width"] = getRect().getWidth();
|
||||
notifyParent(info);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,12 +51,18 @@ class LLScrollingPanelList : public LLUICtrl
|
|||
{
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
|
||||
{};
|
||||
LLScrollingPanelList(const Params& p)
|
||||
: LLUICtrl(p)
|
||||
{}
|
||||
{
|
||||
Optional<bool> is_horizontal;
|
||||
Optional<S32> padding;
|
||||
Optional<S32> spacing;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
LLScrollingPanelList(const Params& p);
|
||||
|
||||
static const S32 GAP_BETWEEN_PANELS = 6;
|
||||
static const S32 DEFAULT_SPACING = 6;
|
||||
static const S32 DEFAULT_PADDING = 2;
|
||||
|
||||
typedef std::deque<LLScrollingPanel*> panel_list_t;
|
||||
|
||||
|
|
@ -65,11 +71,18 @@ public:
|
|||
virtual void draw();
|
||||
|
||||
void clearPanels();
|
||||
S32 addPanel( LLScrollingPanel* panel );
|
||||
void removePanel( LLScrollingPanel* panel );
|
||||
void removePanel( U32 panel_index );
|
||||
S32 addPanel(LLScrollingPanel* panel, bool back = false);
|
||||
void removePanel(LLScrollingPanel* panel);
|
||||
void removePanel(U32 panel_index);
|
||||
void updatePanels(BOOL allow_modify);
|
||||
const panel_list_t& getPanelList() { return mPanelList; }
|
||||
void rearrange();
|
||||
|
||||
const panel_list_t& getPanelList() const { return mPanelList; }
|
||||
bool getIsHorizontal() const { return mIsHorizontal; }
|
||||
void setPadding(S32 padding) { mPadding = padding; rearrange(); }
|
||||
void setSpacing(S32 spacing) { mSpacing = spacing; rearrange(); }
|
||||
S32 getPadding() const { return mPadding; }
|
||||
S32 getSpacing() const { return mSpacing; }
|
||||
|
||||
private:
|
||||
void updatePanelVisiblilty();
|
||||
|
|
@ -77,7 +90,11 @@ private:
|
|||
/**
|
||||
* Notify parent about size change, makes sense when used inside accordion
|
||||
*/
|
||||
void notifySizeChanged(S32 height);
|
||||
void notifySizeChanged();
|
||||
|
||||
bool mIsHorizontal;
|
||||
S32 mPadding;
|
||||
S32 mSpacing;
|
||||
|
||||
panel_list_t mPanelList;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>all</string>
|
||||
<key>Character</key>
|
||||
<string>🔍</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>😀</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>smileys and emotion</string>
|
||||
<string>people and body</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>🥬</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>animals and nature</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>🍔</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>food and drink</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>🛩</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>travel and places</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>🏈</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>activities</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>💡</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>objects</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Character</key>
|
||||
<string>⚠</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>symbols</string>
|
||||
</array>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>others</string>
|
||||
<key>Character</key>
|
||||
<string>🌂</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>skip</string>
|
||||
<key>Categories</key>
|
||||
<array>
|
||||
<string>components</string>
|
||||
</array>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -33,49 +33,71 @@ struct LLEmojiDescriptor;
|
|||
|
||||
class LLFloaterEmojiPicker : public LLFloater
|
||||
{
|
||||
using super = LLFloater;
|
||||
|
||||
public:
|
||||
// The callback function will be called with an emoji char.
|
||||
typedef boost::function<void (llwchar)> pick_callback_t;
|
||||
typedef boost::function<void ()> close_callback_t;
|
||||
// The callback function will be called with an emoji char.
|
||||
typedef boost::function<void (llwchar)> pick_callback_t;
|
||||
typedef boost::function<void ()> close_callback_t;
|
||||
|
||||
// Call this to select an emoji.
|
||||
static LLFloaterEmojiPicker* getInstance();
|
||||
static LLFloaterEmojiPicker* showInstance(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
|
||||
// Call this to select an emoji.
|
||||
static LLFloaterEmojiPicker* getInstance();
|
||||
static LLFloaterEmojiPicker* showInstance(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
|
||||
|
||||
LLFloaterEmojiPicker(const LLSD& key);
|
||||
virtual ~LLFloaterEmojiPicker();
|
||||
LLFloaterEmojiPicker(const LLSD& key);
|
||||
virtual ~LLFloaterEmojiPicker();
|
||||
|
||||
virtual BOOL postBuild();
|
||||
virtual BOOL postBuild() override;
|
||||
virtual void dirtyRect() override;
|
||||
|
||||
void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
|
||||
void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr);
|
||||
|
||||
virtual void closeFloater(bool app_quitting = false);
|
||||
virtual void closeFloater(bool app_quitting = false) override;
|
||||
|
||||
private:
|
||||
void fillEmojis();
|
||||
bool matchesCategory(const LLEmojiDescriptor* descr);
|
||||
bool matchesPattern(const LLEmojiDescriptor* descr);
|
||||
void fillGroups();
|
||||
void moveGroups();
|
||||
void fillEmojis(bool fromResize = false);
|
||||
|
||||
void onCategoryCommit();
|
||||
void onSearchKeystroke();
|
||||
void onPreviewEmojiClick();
|
||||
void onEmojiSelect();
|
||||
void onEmojiEmpty();
|
||||
void onEmojiPick();
|
||||
bool matchesPattern(const LLEmojiDescriptor* descr);
|
||||
|
||||
virtual BOOL handleKeyHere(KEY key, MASK mask);
|
||||
void onGroupButtonClick(LLUICtrl* ctrl);
|
||||
void onSearchKeystroke();
|
||||
void onPreviewEmojiClick();
|
||||
void onGridMouseEnter();
|
||||
void onGridMouseLeave();
|
||||
void onGroupButtonMouseEnter(LLUICtrl* ctrl);
|
||||
void onGroupButtonMouseLeave(LLUICtrl* ctrl);
|
||||
void onEmojiMouseEnter(LLUICtrl* ctrl);
|
||||
void onEmojiMouseLeave(LLUICtrl* ctrl);
|
||||
void onEmojiMouseClick(LLUICtrl* ctrl, MASK mask);
|
||||
|
||||
class LLComboBox* mCategory { nullptr };
|
||||
class LLLineEditor* mSearch { nullptr };
|
||||
class LLScrollListCtrl* mEmojis { nullptr };
|
||||
class LLButton* mPreviewEmoji { nullptr };
|
||||
void selectGridIcon(LLUICtrl* ctrl);
|
||||
void unselectGridIcon(LLUICtrl* ctrl);
|
||||
|
||||
pick_callback_t mEmojiPickCallback;
|
||||
close_callback_t mFloaterCloseCallback;
|
||||
virtual BOOL handleKeyHere(KEY key, MASK mask) override;
|
||||
|
||||
static std::string mSelectedCategory;
|
||||
static std::string mSearchPattern;
|
||||
static int mSelectedEmojiIndex;
|
||||
void onEmojiUsed(llwchar emoji);
|
||||
void loadState();
|
||||
void saveState();
|
||||
|
||||
class LLPanel* mGroups { nullptr };
|
||||
class LLPanel* mBadge { nullptr };
|
||||
class LLLineEditor* mSearch { nullptr };
|
||||
class LLScrollContainer* mEmojiScroll { nullptr };
|
||||
class LLScrollingPanelList* mEmojiGrid { nullptr };
|
||||
class LLButton* mPreviewEmoji { nullptr };
|
||||
class LLTextBox* mDescription { nullptr };
|
||||
|
||||
pick_callback_t mEmojiPickCallback;
|
||||
close_callback_t mFloaterCloseCallback;
|
||||
|
||||
std::vector<class LLButton*> mGroupButtons;
|
||||
|
||||
S32 mRecentBadgeWidth { 0 };
|
||||
S32 mRecentGridWidth { 0 };
|
||||
S32 mRecentMaxIcons { 0 };
|
||||
LLUICtrl* mHoveredIcon { nullptr };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>smileys and følelser</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>mennesker and krop</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>komponenter</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>dyr and natur</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>mad and drikke</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>rejser and steder</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>oplevelser</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>objekter</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>symboler</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>Smileys and Emotionen</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>Menschen and Körper</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>Komponenten</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>Tiere and Natur</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>Essen and Trinken</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>Reisen and Orte</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>Aktivitäten</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>Gegenstände</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>Symbole</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater name="emojipicker" title="Emoji auswählen">
|
||||
<floater.string name="title_for_recently_used" value="Zuletzt verwendet"/>
|
||||
<floater.string name="title_for_frequently_used" value="Häufig verwendet"/>
|
||||
<line_editor name="Search" label="Nach Emoji suchen"/>
|
||||
<scroll_list name="Emojis">
|
||||
<columns label="@" name="look" />
|
||||
<columns label="Name" name="name" />
|
||||
</scroll_list>
|
||||
<combo_box name="Category" label="Kategorie auswählen"/>
|
||||
</floater>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>smileys and emotion</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>people and body</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>components</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>animals and nature</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>food and drink</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>travel and places</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>activities</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>objects</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>symbols</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
<scrolling_panel_list
|
||||
follows="left|right"
|
||||
layout="topleft"
|
||||
left="1"
|
||||
left="1"
|
||||
name="chiclet_row_panel_list"
|
||||
width="318"/>
|
||||
</scroll_container>
|
||||
|
|
|
|||
|
|
@ -7,59 +7,77 @@
|
|||
legacy_header_height="0"
|
||||
can_resize="true"
|
||||
layout="topleft"
|
||||
min_width="250"
|
||||
height="400"
|
||||
width="200">
|
||||
width="250">
|
||||
<floater.string name="title_for_recently_used" value="Recently used"/>
|
||||
<floater.string name="title_for_frequently_used" value="Frequently used"/>
|
||||
<line_editor
|
||||
name="Search"
|
||||
label="Type to search an emoji"
|
||||
label="Type to search"
|
||||
layout="bottomleft"
|
||||
follows="bottom|left|right"
|
||||
text_tentative_color="TextFgTentativeColor"
|
||||
max_length_bytes="63"
|
||||
bottom="5"
|
||||
left="39"
|
||||
bottom="5"
|
||||
left="34"
|
||||
height="29"
|
||||
width="158" />
|
||||
width="212" />
|
||||
<text
|
||||
name="Description"
|
||||
layout="bottomleft"
|
||||
follows="bottom|left|right"
|
||||
font="SansSerifMedium"
|
||||
bottom="5"
|
||||
left="42"
|
||||
height="29"
|
||||
width="200" />
|
||||
<button
|
||||
name="PreviewEmoji"
|
||||
name="PreviewEmoji"
|
||||
layout="bottomleft"
|
||||
follows="bottom|left"
|
||||
font="EmojiHuge"
|
||||
use_font_color="true"
|
||||
bottom="5"
|
||||
left="5"
|
||||
height="29"
|
||||
width="29" />
|
||||
<scroll_list
|
||||
name="Emojis"
|
||||
font="EmojiHuge"
|
||||
use_font_color="true"
|
||||
bottom="5"
|
||||
left="2"
|
||||
height="29"
|
||||
width="29" />
|
||||
<scroll_container
|
||||
name="EmojiGridContainer"
|
||||
layout="topleft"
|
||||
follows="all"
|
||||
sort_column="0"
|
||||
max_chars="63"
|
||||
commit_on_selection_change="true"
|
||||
draw_heading="true"
|
||||
heading_height="25"
|
||||
left="5"
|
||||
row_padding="0"
|
||||
top="25"
|
||||
height="338"
|
||||
width="192">
|
||||
<columns
|
||||
label="@"
|
||||
name="look"
|
||||
width="30" />
|
||||
<columns
|
||||
label="Name"
|
||||
name="name" />
|
||||
</scroll_list>
|
||||
<combo_box
|
||||
name="Category"
|
||||
label="Choose a category"
|
||||
top="25"
|
||||
left="0"
|
||||
height="339"
|
||||
width="250">
|
||||
<scrolling_panel_list
|
||||
name="EmojiGrid"
|
||||
layout="topleft"
|
||||
follows="top|left|right"
|
||||
padding="4"
|
||||
spacing="0"
|
||||
top="0"
|
||||
left="0"
|
||||
width="250"/>
|
||||
</scroll_container>
|
||||
<panel
|
||||
name="Groups"
|
||||
layout="topleft"
|
||||
follows="top|left|right"
|
||||
allow_text_entry="true"
|
||||
top="0"
|
||||
left="5"
|
||||
top="0"
|
||||
left="0"
|
||||
height="25"
|
||||
width="192" />
|
||||
width="250">
|
||||
<panel
|
||||
name="Badge"
|
||||
layout="bottomleft"
|
||||
follows="bottom|left"
|
||||
background_visible="true"
|
||||
background_opaque="true"
|
||||
bg_opaque_color="FrogGreen"
|
||||
bottom="0"
|
||||
height="2"
|
||||
width="20"
|
||||
/>
|
||||
</panel>
|
||||
</floater>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>emoticonos y emoción</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>personas y cuerpo</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>componentes</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>animales y la naturaleza</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>comida y bebida</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>viajes y lugares</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>actividades</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>objetos</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>símbolos</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>smileys et émotion</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>les gens et le corps</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>composants</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>animaux et la nature</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>nourriture et boissons</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>voyages et lieux</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>activités</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>objets</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>symboles</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>smileys and emozione</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>persone e corpo</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>componenti</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>animali and natura</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>cibo e bevande</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>viaggi and luoghi</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>attività</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>oggetti</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>simboli</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>スマイリーと感情</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>人体</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>コンポーネント</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>動物自然</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>飲み物・食べ物</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>旅行・場所</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>有効化</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>オブジェクト</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>シンボル</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>buźki and emocje</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>ludzie and ciało</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>składniki</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>zwierzęta and przyroda</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>jedzenie i picie</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>podróże and miejsca</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>aktywność</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>objekt</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>symbole</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>sorrisos e emoção</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>pessoas e corpo</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>componentes</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>animais e natureza</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>comida e bebida</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>viagens e lugares</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>atividades</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>objetos</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>símbolos</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>смайлики и люди</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>тело людей</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>компонент</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>животные и природа</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>еда и напитки</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>путешествия и местности</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>варианты досуга</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>предметы</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>символы</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" ?>
|
||||
<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd">
|
||||
<array>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>smileys and emotion</string>
|
||||
<key>Category</key>
|
||||
<string>笑脸</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>people and body</string>
|
||||
<key>Category</key>
|
||||
<string>人体</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>components</string>
|
||||
<key>Category</key>
|
||||
<string>组件</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>animals and nature</string>
|
||||
<key>Category</key>
|
||||
<string>野生动物</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>food and drink</string>
|
||||
<key>Category</key>
|
||||
<string>食物飲料</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>travel and places</string>
|
||||
<key>Category</key>
|
||||
<string>旅遊地點</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>activities</string>
|
||||
<key>Category</key>
|
||||
<string>个人活动</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>objects</string>
|
||||
<key>Category</key>
|
||||
<string>物件</string>
|
||||
</map>
|
||||
<map>
|
||||
<key>Name</key>
|
||||
<string>symbols</string>
|
||||
<key>Category</key>
|
||||
<string>人的符号</string>
|
||||
</map>
|
||||
</array>
|
||||
</llsd>
|
||||
Loading…
Reference in New Issue