Merge branch 'main' into marchcat/x-merge
# Conflicts: # indra/llcommon/llstring.cpp # indra/llcommon/llstring.hmaster
commit
b68a05e7c3
|
|
@ -1,18 +1,18 @@
|
|||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- ignore-for-release
|
||||
authors:
|
||||
- dependabot
|
||||
categories:
|
||||
- title: Breaking Changes 🛠
|
||||
labels:
|
||||
- semver-major
|
||||
- breaking-change
|
||||
- title: New Features 🎉
|
||||
labels:
|
||||
- semver-minor
|
||||
- enhancement
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- '*'
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- ignore-for-release
|
||||
authors:
|
||||
- dependabot
|
||||
categories:
|
||||
- title: Breaking Changes 🛠
|
||||
labels:
|
||||
- semver-major
|
||||
- breaking-change
|
||||
- title: New Features 🎉
|
||||
labels:
|
||||
- semver-minor
|
||||
- enhancement
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- '*'
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ indra/newview/dbghelp.dll
|
|||
indra/newview/filters.xml
|
||||
indra/newview/fmod.dll
|
||||
indra/newview/fmod.log
|
||||
indra/newview/fonts
|
||||
indra/newview/mozilla-theme
|
||||
indra/newview/mozilla-universal-darwin.tgz
|
||||
indra/newview/pilot.txt
|
||||
|
|
@ -68,6 +69,7 @@ indra/newview/teleport_history.txt
|
|||
indra/newview/typed_locations.txt
|
||||
indra/newview/vivox-runtime
|
||||
indra/newview/skins/default/html/common/equirectangular/js
|
||||
emoji_characters.xml
|
||||
indra/server-linux-*
|
||||
indra/temp
|
||||
indra/test/linden_file.dat
|
||||
|
|
|
|||
374
autobuild.xml
374
autobuild.xml
|
|
@ -104,37 +104,25 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>59c1827cab82516504a2eb31e0aa7e38035b5085</string>
|
||||
<string>8539775e0a0783bd252bc548b20b3472a8254c31</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-boost/releases/download/v1.81-90bb2df/boost-1.81-darwin64-90bb2df.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-boost/releases/download/v1.81-09d25a7/boost-1.81-darwin64-09d25a7.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>038853b97307a9b65de20c4c50098023</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9675/45694/boost-1.65.1-linux64-509640.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>26214a33c568929ffeeb3463ce183f2888ce4fe4</string>
|
||||
<string>d40c86fbcb6ce064d546165cbabbf035ea80e07b</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-boost/releases/download/v1.81-90bb2df/boost-1.81-windows64-90bb2df.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-boost/releases/download/v1.81-09d25a7/boost-1.81-windows64-09d25a7.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
|
|
@ -147,7 +135,7 @@
|
|||
<key>copyright</key>
|
||||
<string>(see individual source files)</string>
|
||||
<key>version</key>
|
||||
<string>1.81</string>
|
||||
<string>1.81-09d25a7</string>
|
||||
<key>name</key>
|
||||
<string>boost</string>
|
||||
<key>description</key>
|
||||
|
|
@ -208,37 +196,25 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7f447d30d7add80270a55cf3c53000392821a1cb</string>
|
||||
<string>b1bb8a9c8d458d8842d79f9633fb61df12f1b0ad</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.d1ef72a/colladadom-2.3.d1ef72a-darwin64-d1ef72a.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.ab0c124/colladadom-2.3.ab0c124-darwin64-ab0c124.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c90613240ba3e3a171d3379275ae4ee3</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9695/45732/colladadom-2.3.509683-linux64-509683.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b32294a2f31f5b4ca49928e66832aad1bb4a88ac</string>
|
||||
<string>0df4c05d4efa3019afa4cbf09599df60b586fc5c</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.d1ef72a/colladadom-2.3.d1ef72a-windows64-d1ef72a.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-colladadom/releases/download/v2.3.ab0c124/colladadom-2.3.ab0c124-windows64-ab0c124.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
|
|
@ -251,7 +227,7 @@
|
|||
<key>copyright</key>
|
||||
<string>Copyright 2006 Sony Computer Entertainment Inc.</string>
|
||||
<key>version</key>
|
||||
<string>2.3.d1ef72a</string>
|
||||
<string>2.3.ab0c124</string>
|
||||
<key>name</key>
|
||||
<string>colladadom</string>
|
||||
</map>
|
||||
|
|
@ -477,6 +453,50 @@
|
|||
<key>description</key>
|
||||
<string>A headless browser SDK that uses the Chromium Embedded Framework (CEF). It is designed to make it easier to write applications that render modern web content directly to a memory buffer, inject synthesized mouse and keyboard events as well as interact with web based features like JavaScript or cookies.</string>
|
||||
</map>
|
||||
<key>emoji_shortcodes</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://github.com/secondlife/3p-emoji-shortcodes</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2017-2019 Miles Johnson.</string>
|
||||
<key>description</key>
|
||||
<string>Emoji shortcodes</string>
|
||||
<key>license</key>
|
||||
<string>MIT</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/emojibase-license.txt</string>
|
||||
<key>name</key>
|
||||
<string>emoji_shortcodes</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7ac35da9b1b5c9a05954edeef3fe8e54</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113242/980233/emoji_shortcodes-6.1.0.579438-darwin64-579438.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>087ce7e6d93dcd88b477b10d8e1ab259</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113243/980244/emoji_shortcodes-6.1.0.579438-windows64-579438.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>6.1.0.579438</string>
|
||||
</map>
|
||||
<key>expat</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -635,6 +655,16 @@
|
|||
</map>
|
||||
<key>freetype</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.</string>
|
||||
<key>description</key>
|
||||
<string>Font rendering library</string>
|
||||
<key>license</key>
|
||||
<string>FreeType</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/freetype.txt</string>
|
||||
<key>name</key>
|
||||
<string>freetype</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
|
|
@ -642,11 +672,11 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>912d122aae996483ba814fe8e569394ddca0d42e</string>
|
||||
<string>d90a5c2fb4a729eeff3965ea6dd0a35cf146d379</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-darwin64-4f739fa.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v.2.12.1.557becd/freetype-2.12.1.557becd-darwin64-557becd.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -656,42 +686,46 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>14f57822f0cedef957a50a03a7b5372075cf8e1c</string>
|
||||
<string>4a999279562e8f3e4ba02d3e78a844ddf6fe18f1</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-linux64-4f739fa.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v.2.12.1.557becd/freetype-2.12.1.557becd-linux64-557becd.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>4fecff41a38d67d6b1c97c7c73980667b6a8a1bd</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v.2.12.1.557becd/freetype-2.12.1.557becd-windows-557becd.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>d175b39257b691a957724e655c6cffe0b5a7b104</string>
|
||||
<string>1837fdfd44204c78e79134944f824b0211817883</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v2.4.4.4f739fa/freetype-2.4.4.4f739fa-windows64-4f739fa.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-freetype/releases/download/v.2.12.1.557becd/freetype-2.12.1.557becd-windows64-557becd.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>license</key>
|
||||
<string>FreeType</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/freetype.txt</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.</string>
|
||||
<key>version</key>
|
||||
<string>2.4.4.4f739fa</string>
|
||||
<key>name</key>
|
||||
<string>freetype</string>
|
||||
<key>description</key>
|
||||
<string>Font rendering library</string>
|
||||
<string>2.12.1.557becd</string>
|
||||
</map>
|
||||
<key>glext</key>
|
||||
<map>
|
||||
|
|
@ -766,37 +800,25 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c016d7333a3ded88c060119b4e3a5847015a8711</string>
|
||||
<string>dce3174b12136746f5f910e311e895c1b47bf8fb</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.77bba00/googlemock-1.7.0.77bba00-darwin64-77bba00.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.2b109d4/googlemock-1.7.0.2b109d4-darwin64-2b109d4.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>ff459b58695c76838782847a0b792104</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/9697/45717/googlemock-1.7.0.509686-linux64-509686.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>df51dff9a820fc96c18c2bc00b64467e541633a5</string>
|
||||
<string>265813f84b04c3b03f3d7d33e149b3d5e3cf31db</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.77bba00/googlemock-1.7.0.77bba00-windows64-77bba00.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-googlemock/releases/download/v1.7.0.2b109d4/googlemock-1.7.0.2b109d4-windows64-2b109d4.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
|
|
@ -809,7 +831,7 @@
|
|||
<key>copyright</key>
|
||||
<string>Copyright 2008, Google Inc.</string>
|
||||
<key>version</key>
|
||||
<string>1.7.0.77bba00</string>
|
||||
<string>1.7.0.2b109d4</string>
|
||||
<key>name</key>
|
||||
<string>googlemock</string>
|
||||
<key>description</key>
|
||||
|
|
@ -933,6 +955,54 @@
|
|||
<key>description</key>
|
||||
<string>Havok source code for libs and demos</string>
|
||||
</map>
|
||||
<key>icu4c</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-icu4c</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org></string>
|
||||
<key>description</key>
|
||||
<string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string>
|
||||
<key>license</key>
|
||||
<string>ICU, permissive non-copyleft free software license</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/icu.txt</string>
|
||||
<key>name</key>
|
||||
<string>icu4c</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>47bc32b991385f1a6530e4c6179b07f64ca6edc7</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-darwin64-7d08d82.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b7db881dac80302e4d9010af34c0bf6ca9897df9</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-7d08d82/icu4c-4.8.1-windows64-7d08d82.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>4.8.1-7d08d82</string>
|
||||
</map>
|
||||
<key>jpegencoderbasic</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -1850,6 +1920,62 @@
|
|||
<key>description</key>
|
||||
<string>minizip-ng is a zip manipulation library. Based on work of Gilles Vollant.</string>
|
||||
</map>
|
||||
<key>nanosvg</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-nanosvg</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2013-14 Mikko Mononen</string>
|
||||
<key>description</key>
|
||||
<string>NanoSVG is a simple single-header-file SVG parser and rasterizer</string>
|
||||
<key>license</key>
|
||||
<string>Zlib</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/nanosvg.txt</string>
|
||||
<key>name</key>
|
||||
<string>nanosvg</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>32ead724319c2ea6f65fc5be0e3157cc</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/115452/994130/nanosvg-2022.09.27-darwin64-580364.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>84698f044598ff79e255965f3d1c3e80</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/115397/993664/nanosvg-2022.09.27-linux-580337.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>ee61ff8b866be04c325f1fe2db516d71</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/115454/994144/nanosvg-2022.09.27-windows64-580364.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>2022.09.27</string>
|
||||
</map>
|
||||
<key>nghttp2</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -2554,6 +2680,48 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>description</key>
|
||||
<string>uriparser is a strictly RFC 3986 compliant URI parsing and handling library written in C. uriparser is cross-platform, fast, supports Unicode and is licensed under the New BSD license.</string>
|
||||
</map>
|
||||
<key>viewer-fonts</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2016-2022 Brad Erickson CC-BY-4.0/MIT, Copyright 2016-2022 Twitter, Inc. CC-BY-4.0, Copyright 2013 Joe Loughry and Terence Eden MIT</string>
|
||||
<key>description</key>
|
||||
<string>Viewer fonts</string>
|
||||
<key>license</key>
|
||||
<string>Various open source</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/fonts.txt</string>
|
||||
<key>name</key>
|
||||
<string>viewer-fonts</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6041bbd4001e3951f96ac3456c7906da</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113314/980656/viewer_fonts-1.579464-darwin64-579464.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>1745ba6eec0108250446fe01d4aa065c</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/113307/980631/viewer_fonts-1.579464-windows64-579464.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.579464</string>
|
||||
</map>
|
||||
<key>viewer-manager</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -2933,7 +3101,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE</string>
|
||||
<string>-DROOT_PROJECT_NAME:STRING=SecondLife</string>
|
||||
<string>-DINSTALL_PROPRIETARY=TRUE</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -2953,11 +3121,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE</string>
|
||||
<string>-DROOT_PROJECT_NAME:STRING=SecondLife</string>
|
||||
<string>-DINSTALL_PROPRIETARY=FALSE</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>../indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>RelWithDebInfoOS</string>
|
||||
|
|
@ -2974,7 +3142,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE</string>
|
||||
<string>-DROOT_PROJECT_NAME:STRING=SecondLife</string>
|
||||
<string>-DINSTALL_PROPRIETARY=TRUE</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -2994,11 +3162,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE</string>
|
||||
<string>-DROOT_PROJECT_NAME:STRING=SecondLife</string>
|
||||
<string>-DINSTALL_PROPRIETARY=FALSE</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>../indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>ReleaseOS</string>
|
||||
|
|
@ -3019,11 +3187,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>-G</string>
|
||||
<string>Xcode</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>../indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3036,7 +3204,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>default</key>
|
||||
<string>True</string>
|
||||
|
|
@ -3051,7 +3219,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>-G</string>
|
||||
<string>Xcode</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3064,7 +3232,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>RelWithDebInfoOS</string>
|
||||
|
|
@ -3077,11 +3245,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>-G</string>
|
||||
<string>Xcode</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>../indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3094,7 +3262,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>Release</string>
|
||||
|
|
@ -3107,7 +3275,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>-G</string>
|
||||
<string>Xcode</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3120,7 +3288,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-project</string>
|
||||
<string>SecondLife.xcodeproj</string>
|
||||
<string>-parallelizeTargets</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>ReleaseOS</string>
|
||||
|
|
@ -3144,11 +3312,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-G</string>
|
||||
<string>Ninja</string>
|
||||
<string>-DLL_TESTS=Off</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>../indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3169,7 +3337,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-G</string>
|
||||
<string>Ninja</string>
|
||||
<string>-DLL_TESTS=Off</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3207,11 +3375,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN}</string>
|
||||
<string>-A</string>
|
||||
<string>${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>..\indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3221,11 +3389,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>/build</string>
|
||||
<string>RelWithDebInfo|${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>SecondLife.sln</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>default</key>
|
||||
<string>True</string>
|
||||
|
|
@ -3245,11 +3413,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-DINSTALL_PROPRIETARY=FALSE</string>
|
||||
<string>-DUSE_KDU=FALSE</string>
|
||||
<string>-DUSE_OPENAL:BOOL=ON</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>..\indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3263,11 +3431,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>/p:useenv=true</string>
|
||||
<string>/verbosity:minimal</string>
|
||||
<string>/p:VCBuildAdditionalOptions= /incremental</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>SecondLife.sln</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>RelWithDebInfoOS</string>
|
||||
|
|
@ -3282,11 +3450,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN}</string>
|
||||
<string>-A</string>
|
||||
<string>${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>..\indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3296,11 +3464,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>/build</string>
|
||||
<string>Release|${AUTOBUILD_WIN_VSPLATFORM|NOTWIN}</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>SecondLife.sln</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>Release</string>
|
||||
|
|
@ -3319,11 +3487,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>-DINSTALL_PROPRIETARY=FALSE</string>
|
||||
<string>-DUSE_KDU=FALSE</string>
|
||||
<string>-DUSE_OPENAL:BOOL=ON</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>..\indra</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3337,11 +3505,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>/p:useenv=true</string>
|
||||
<string>/verbosity:minimal</string>
|
||||
<string>/p:VCBuildAdditionalOptions= /incremental</string>
|
||||
</array>
|
||||
</array>
|
||||
<key>arguments</key>
|
||||
<array>
|
||||
<string>SecondLife.sln</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>ReleaseOS</string>
|
||||
|
|
|
|||
|
|
@ -239,6 +239,8 @@ Ansariel Hiller
|
|||
SL-15398
|
||||
SL-18432
|
||||
SL-19140
|
||||
SL-19575
|
||||
SL-19623
|
||||
SL-4126
|
||||
SL-20224
|
||||
SL-20524
|
||||
|
|
@ -900,6 +902,7 @@ Kitty Barnett
|
|||
STORM-2149
|
||||
MAINT-7581
|
||||
MAINT-7081
|
||||
DRTVWR-489 (Internal JIRA that tracks Kitty's sizeable, epic contribution: support for Emoji characters in the Viewer [April 2023])
|
||||
SL-18988
|
||||
Kolor Fall
|
||||
Komiko Okamoto
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ set(cmake_SOURCE_FILES
|
|||
GoogleMock.cmake
|
||||
Havok.cmake
|
||||
Hunspell.cmake
|
||||
ICU4C.cmake
|
||||
JsonCpp.cmake
|
||||
LLAddBuildTest.cmake
|
||||
LLAppearance.cmake
|
||||
|
|
@ -64,7 +65,7 @@ set(cmake_SOURCE_FILES
|
|||
VisualLeakDetector.cmake
|
||||
LibVLCPlugin.cmake
|
||||
XmlRpcEpi.cmake
|
||||
xxHash.cmake
|
||||
xxHash.cmake
|
||||
ZLIBNG.cmake
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,15 @@ if(WINDOWS)
|
|||
uriparser.dll
|
||||
)
|
||||
|
||||
# ICU4C (same filenames for 32 and 64 bit builds)
|
||||
set(release_files ${release_files} icudt48.dll)
|
||||
set(release_files ${release_files} icuin48.dll)
|
||||
set(release_files ${release_files} icuio48.dll)
|
||||
set(release_files ${release_files} icule48.dll)
|
||||
set(release_files ${release_files} iculx48.dll)
|
||||
set(release_files ${release_files} icutu48.dll)
|
||||
set(release_files ${release_files} icuuc48.dll)
|
||||
|
||||
# OpenSSL
|
||||
if(ADDRESS_SIZE EQUAL 64)
|
||||
set(release_files ${release_files} libcrypto-1_1-x64.dll)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
include_guard()
|
||||
|
||||
add_library( ll::icu4c INTERFACE IMPORTED )
|
||||
|
||||
|
||||
use_system_binary(icu4c)
|
||||
use_prebuilt_binary(icu4c)
|
||||
if (WINDOWS)
|
||||
target_link_libraries( ll::icu4c INTERFACE icuuc)
|
||||
elseif(DARWIN)
|
||||
target_link_libraries( ll::icu4c INTERFACE icuuc)
|
||||
#elseif(LINUX)
|
||||
## target_link_libraries( ll::icu4c INTERFACE )
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid platform")
|
||||
endif()
|
||||
|
||||
target_include_directories( ll::icu4c SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/unicode )
|
||||
|
||||
use_prebuilt_binary(dictionaries)
|
||||
|
|
@ -18,3 +18,6 @@ endif()
|
|||
|
||||
use_prebuilt_binary(slvoice)
|
||||
|
||||
use_prebuilt_binary(nanosvg)
|
||||
use_prebuilt_binary(viewer-fonts)
|
||||
use_prebuilt_binary(emoji_shortcodes)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class LLWearableType : public LLParamSingleton<LLWearableType>
|
|||
{
|
||||
LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);
|
||||
~LLWearableType();
|
||||
void initSingleton();
|
||||
void initSingleton() override;
|
||||
public:
|
||||
enum EType
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
project(llcommon)
|
||||
|
||||
include(00-Common)
|
||||
include(ICU4C)
|
||||
include(LLCommon)
|
||||
include(bugsplat)
|
||||
include(Linking)
|
||||
|
|
@ -282,6 +283,7 @@ target_link_libraries(
|
|||
ll::uriparser
|
||||
ll::oslibraries
|
||||
ll::tracy
|
||||
ll::icu4c
|
||||
)
|
||||
|
||||
target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
|
|||
LLSINGLETON(LLCoros);
|
||||
~LLCoros();
|
||||
|
||||
void cleanupSingleton();
|
||||
void cleanupSingleton() override;
|
||||
public:
|
||||
/// The viewer's use of the term "coroutine" became deeply embedded before
|
||||
/// the industry term "fiber" emerged to distinguish userland threads from
|
||||
|
|
|
|||
|
|
@ -802,7 +802,7 @@ public:
|
|||
private: \
|
||||
/* implement LLSingleton pure virtual method whose sole purpose */ \
|
||||
/* is to remind people to use this macro */ \
|
||||
virtual void you_must_use_LLSINGLETON_macro() {} \
|
||||
virtual void you_must_use_LLSINGLETON_macro() override {} \
|
||||
friend class LLSingleton<DERIVED_CLASS>; \
|
||||
DERIVED_CLASS(__VA_ARGS__)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "llerror.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llsd.h"
|
||||
#include <unicode/uchar.h>
|
||||
#include <vector>
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
|
@ -338,8 +339,6 @@ S32 wchar_utf8_length(const llwchar wc)
|
|||
{
|
||||
if (wc < 0x80)
|
||||
{
|
||||
// This case will also catch negative values which are
|
||||
// technically invalid.
|
||||
return 1;
|
||||
}
|
||||
else if (wc < 0x800)
|
||||
|
|
@ -364,6 +363,30 @@ S32 wchar_utf8_length(const llwchar wc)
|
|||
}
|
||||
}
|
||||
|
||||
std::string wchar_utf8_preview(const llwchar wc)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::uppercase << (U32)wc;
|
||||
|
||||
U8 out_bytes[8];
|
||||
U32 size = (U32)wchar_to_utf8chars(wc, (char*)out_bytes);
|
||||
|
||||
if (size > 1)
|
||||
{
|
||||
oss << " [";
|
||||
for (U32 i = 0; i < size; ++i)
|
||||
{
|
||||
if (i)
|
||||
{
|
||||
oss << ", ";
|
||||
}
|
||||
oss << (int)out_bytes[i];
|
||||
}
|
||||
oss << "]";
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
S32 wstring_utf8_length(const LLWString& wstr)
|
||||
{
|
||||
|
|
@ -622,6 +645,119 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
|
|||
return out;
|
||||
}
|
||||
|
||||
llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset, size_t length)
|
||||
{
|
||||
switch (length)
|
||||
{
|
||||
case 2:
|
||||
return ((utf8str[offset] & 0x1F) << 6) +
|
||||
(utf8str[offset + 1] & 0x3F);
|
||||
case 3:
|
||||
return ((utf8str[offset] & 0x0F) << 12) +
|
||||
((utf8str[offset + 1] & 0x3F) << 6) +
|
||||
(utf8str[offset + 2] & 0x3F);
|
||||
case 4:
|
||||
return ((utf8str[offset] & 0x07) << 18) +
|
||||
((utf8str[offset + 1] & 0x3F) << 12) +
|
||||
((utf8str[offset + 2] & 0x3F) << 6) +
|
||||
(utf8str[offset + 3] & 0x3F);
|
||||
case 5:
|
||||
return ((utf8str[offset] & 0x03) << 24) +
|
||||
((utf8str[offset + 1] & 0x3F) << 18) +
|
||||
((utf8str[offset + 2] & 0x3F) << 12) +
|
||||
((utf8str[offset + 3] & 0x3F) << 6) +
|
||||
(utf8str[offset + 4] & 0x3F);
|
||||
case 6:
|
||||
return ((utf8str[offset] & 0x01) << 30) +
|
||||
((utf8str[offset + 1] & 0x3F) << 24) +
|
||||
((utf8str[offset + 2] & 0x3F) << 18) +
|
||||
((utf8str[offset + 3] & 0x3F) << 12) +
|
||||
((utf8str[offset + 4] & 0x3F) << 6) +
|
||||
(utf8str[offset + 5] & 0x3F);
|
||||
case 7:
|
||||
return ((utf8str[offset + 1] & 0x03) << 30) +
|
||||
((utf8str[offset + 2] & 0x3F) << 24) +
|
||||
((utf8str[offset + 3] & 0x3F) << 18) +
|
||||
((utf8str[offset + 4] & 0x3F) << 12) +
|
||||
((utf8str[offset + 5] & 0x3F) << 6) +
|
||||
(utf8str[offset + 6] & 0x3F);
|
||||
}
|
||||
return LL_UNKNOWN_CHAR;
|
||||
}
|
||||
|
||||
std::string utf8str_showBytesUTF8(const std::string& utf8str)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
bool in_sequence = false;
|
||||
size_t sequence_size = 0;
|
||||
size_t byte_index = 0;
|
||||
size_t source_length = utf8str.size();
|
||||
|
||||
auto open_sequence = [&]()
|
||||
{
|
||||
if (!result.empty() && result.back() != '\n')
|
||||
result += '\n'; // Use LF as a separator before new UTF-8 sequence
|
||||
result += '[';
|
||||
in_sequence = true;
|
||||
};
|
||||
|
||||
auto close_sequence = [&]()
|
||||
{
|
||||
llwchar unicode = utf8str_to_wchar(utf8str, byte_index - sequence_size, sequence_size);
|
||||
if (unicode != LL_UNKNOWN_CHAR)
|
||||
{
|
||||
result += llformat("+%04X", unicode);
|
||||
}
|
||||
result += ']';
|
||||
in_sequence = false;
|
||||
sequence_size = 0;
|
||||
};
|
||||
|
||||
while (byte_index < source_length)
|
||||
{
|
||||
U8 byte = utf8str[byte_index];
|
||||
if (byte >= 0x80) // Part of an UTF-8 sequence
|
||||
{
|
||||
if (!in_sequence) // Start new UTF-8 sequence
|
||||
{
|
||||
open_sequence();
|
||||
}
|
||||
else if (byte >= 0xC0) // Start another UTF-8 sequence
|
||||
{
|
||||
close_sequence();
|
||||
open_sequence();
|
||||
}
|
||||
else // Continue the same UTF-8 sequence
|
||||
{
|
||||
result += '.';
|
||||
}
|
||||
result += llformat("%02X", byte); // The byte is represented in hexadecimal form
|
||||
++sequence_size;
|
||||
}
|
||||
else // ASCII symbol is represented as a character
|
||||
{
|
||||
if (in_sequence) // End of UTF-8 sequence
|
||||
{
|
||||
close_sequence();
|
||||
if (byte != '\n')
|
||||
{
|
||||
result += '\n'; // Use LF as a separator between UTF-8 and ASCII
|
||||
}
|
||||
}
|
||||
result += byte;
|
||||
}
|
||||
++byte_index;
|
||||
}
|
||||
|
||||
if (in_sequence) // End of UTF-8 sequence
|
||||
{
|
||||
close_sequence();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Search for any emoji symbol, return true if found
|
||||
bool wstring_has_emoji(const LLWString& wstr)
|
||||
{
|
||||
|
|
@ -874,61 +1010,35 @@ std::string LLStringOps::sPM;
|
|||
// static
|
||||
bool LLStringOps::isEmoji(llwchar wch)
|
||||
{
|
||||
// Most of the following symbols are not actually emoticons, but rather small pictures
|
||||
|
||||
// 0x1F000 .. 0x1F02F - mahjong tiles
|
||||
// https://symbl.cc/en/unicode/table/#mahjong-tiles
|
||||
|
||||
// 0x1F030 .. 0x1F09F - domino tiles
|
||||
// https://symbl.cc/en/unicode/table/#domino-tiles
|
||||
|
||||
// 0x1F0A0 .. 0x1F0FF - playing cards
|
||||
// https://symbl.cc/en/unicode/table/#playing-cards
|
||||
|
||||
// 0x1F100 .. 0x1F1FF - enclosed alphanumeric supplement
|
||||
// https://symbl.cc/en/unicode/table/#enclosed-alphanumeric-supplement
|
||||
|
||||
// 0x1F200 .. 0x1F2FF - enclosed ideographic supplement
|
||||
// https://symbl.cc/en/unicode/table/#enclosed-ideographic-supplement
|
||||
|
||||
// 0x1F300 .. 0x1F5FF - miscellaneous symbols and pictographs
|
||||
// https://symbl.cc/en/unicode/table/#miscellaneous-symbols-and-pictographs
|
||||
|
||||
// 0x1F600 .. 0x1F64F - emoticons
|
||||
// https://symbl.cc/en/unicode/table/#emoticons
|
||||
|
||||
// 0x1F650 .. 0x1F67F - ornamental dingbats
|
||||
// https://symbl.cc/en/unicode/table/#ornamental-dingbats
|
||||
|
||||
// 0x1F680 .. 0x1F6FF - transport and map symbols
|
||||
// https://symbl.cc/en/unicode/table/#transport-and-map-symbols
|
||||
|
||||
// 0x1F700 .. 0x1F77F - alchemical symbols
|
||||
// https://symbl.cc/en/unicode/table/#alchemical-symbols
|
||||
|
||||
// 0x1F780 .. 0x1F7FF - geometric shapes extended
|
||||
// https://symbl.cc/en/unicode/table/#geometric-shapes-extended
|
||||
|
||||
// 0x1F800 .. 0x1F8FF - supplemental arrows c
|
||||
// https://symbl.cc/en/unicode/table/#supplemental-arrows-c
|
||||
|
||||
// 0x1F900 .. 0x1F9FF - supplemental symbols and pictographs
|
||||
// https://symbl.cc/en/unicode/table/#supplemental-symbols-and-pictographs
|
||||
|
||||
// 0x1FA00 .. 0x1FA6F - chess symbols
|
||||
// https://symbl.cc/en/unicode/table/#chess-symbols
|
||||
|
||||
// 0x1FA70 .. 0x1FAFF - symbols and pictographs extended a
|
||||
// https://symbl.cc/en/unicode/table/#symbols-and-pictographs-extended-a
|
||||
|
||||
// 0x1FB00 .. 0x1FBFF - symbols for legacy computing
|
||||
// https://symbl.cc/en/unicode/table/#symbols-for-legacy-computing
|
||||
|
||||
// 0x1FC00 .. 0x1FFFF - undefined block 44
|
||||
// These symbols aren't defined yet
|
||||
// https://symbl.cc/en/unicode/table/#undefined-block-44
|
||||
|
||||
return wch >= 0x1F000 && wch < 0x1FC00;
|
||||
int ublock = ublock_getCode(wch);
|
||||
switch (ublock)
|
||||
{
|
||||
case UBLOCK_GENERAL_PUNCTUATION:
|
||||
case UBLOCK_LETTERLIKE_SYMBOLS:
|
||||
case UBLOCK_ARROWS:
|
||||
case UBLOCK_MISCELLANEOUS_TECHNICAL:
|
||||
case UBLOCK_ENCLOSED_ALPHANUMERICS:
|
||||
case UBLOCK_GEOMETRIC_SHAPES:
|
||||
case UBLOCK_MISCELLANEOUS_SYMBOLS:
|
||||
case UBLOCK_DINGBATS:
|
||||
case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
|
||||
case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
|
||||
case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS:
|
||||
case UBLOCK_EMOTICONS:
|
||||
case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS:
|
||||
#if U_ICU_VERSION_MAJOR_NUM > 56
|
||||
// Boost uses ICU so we can't update it independently
|
||||
case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS:
|
||||
#endif // U_ICU_VERSION_MAJOR_NUM > 56
|
||||
return true;
|
||||
default:
|
||||
#if U_ICU_VERSION_MAJOR_NUM > 56
|
||||
return false;
|
||||
#else
|
||||
// See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs
|
||||
return wch >= 0x1F900 && wch <= 0x1F9FF;
|
||||
#endif // U_ICU_VERSION_MAJOR_NUM > 56
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -357,6 +357,8 @@ 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);
|
||||
static void stripNonprintable(string_type& string);
|
||||
|
|
@ -680,6 +682,8 @@ LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr);
|
|||
// Length in bytes of this wide char in a UTF8 string
|
||||
LL_COMMON_API S32 wchar_utf8_length(const llwchar wc);
|
||||
|
||||
LL_COMMON_API std::string wchar_utf8_preview(const llwchar wc);
|
||||
|
||||
LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str);
|
||||
|
||||
// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
|
||||
|
|
@ -739,6 +743,10 @@ LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str);
|
|||
|
||||
LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
|
||||
|
||||
LL_COMMON_API llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset, size_t length);
|
||||
|
||||
LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str);
|
||||
|
||||
LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr);
|
||||
|
||||
LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr);
|
||||
|
|
@ -1600,6 +1608,29 @@ 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)
|
||||
{
|
||||
if (str.size())
|
||||
{
|
||||
auto last = str[0] = toupper(str[0]);
|
||||
for (U32 i = 1; i < str.size(); ++i)
|
||||
{
|
||||
last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ public: \
|
|||
DEP_INIT /* dependency in initSingleton */ \
|
||||
} sDepFlag; \
|
||||
\
|
||||
void initSingleton(); \
|
||||
void cleanupSingleton(); \
|
||||
void initSingleton() override; \
|
||||
void cleanupSingleton() override; \
|
||||
}; \
|
||||
\
|
||||
CLS::dep_flag CLS::sDepFlag = DEP_NONE
|
||||
|
|
@ -300,7 +300,7 @@ namespace tut
|
|||
{
|
||||
LLSINGLETON_EMPTY_CTOR(CircularPInit);
|
||||
public:
|
||||
virtual void initSingleton()
|
||||
virtual void initSingleton() override
|
||||
{
|
||||
// never mind indirection, just go straight for the circularity
|
||||
CircularPInit *pt = getInstance();
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,
|
|||
{
|
||||
LLSINGLETON(LLFolderDictionary);
|
||||
protected:
|
||||
virtual LLFolderType::EType notFound() const
|
||||
virtual LLFolderType::EType notFound() const override
|
||||
{
|
||||
return LLFolderType::FT_NONE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class LLSettingsDictionary : public LLSingleton<LLSettingsDictionary>,
|
|||
{
|
||||
LLSINGLETON(LLSettingsDictionary);
|
||||
|
||||
void initSingleton();
|
||||
void initSingleton() override;
|
||||
};
|
||||
|
||||
LLSettingsDictionary::LLSettingsDictionary()
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public:
|
|||
private:
|
||||
virtual ~LLExperienceCache();
|
||||
|
||||
virtual void initSingleton();
|
||||
virtual void initSingleton() override;
|
||||
|
||||
typedef boost::function<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLCore::HttpRequest::ptr_t, std::string)> permissionInvoker_fn;
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ class LLProxy: public LLSingleton<LLProxy>
|
|||
LLSINGLETON(LLProxy);
|
||||
LOG_CLASS(LLProxy);
|
||||
|
||||
/*virtual*/ void initSingleton();
|
||||
/*virtual*/ void initSingleton() override;
|
||||
|
||||
public:
|
||||
// Static check for enabled status for UDP packets. Call from main thread only.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ set(llrender_SOURCE_FILES
|
|||
llcubemaparray.cpp
|
||||
llfontbitmapcache.cpp
|
||||
llfontfreetype.cpp
|
||||
llfontfreetypesvg.cpp
|
||||
llfontgl.cpp
|
||||
llfontregistry.cpp
|
||||
llgl.cpp
|
||||
|
|
@ -43,6 +44,7 @@ set(llrender_HEADER_FILES
|
|||
llcubemaparray.h
|
||||
llfontgl.h
|
||||
llfontfreetype.h
|
||||
llfontfreetypesvg.h
|
||||
llfontbitmapcache.h
|
||||
llfontregistry.h
|
||||
llgl.h
|
||||
|
|
|
|||
|
|
@ -30,14 +30,7 @@
|
|||
#include "llfontbitmapcache.h"
|
||||
|
||||
LLFontBitmapCache::LLFontBitmapCache()
|
||||
: mNumComponents(0),
|
||||
mBitmapWidth(0),
|
||||
mBitmapHeight(0),
|
||||
mBitmapNum(-1),
|
||||
mMaxCharWidth(0),
|
||||
mMaxCharHeight(0),
|
||||
mCurrentOffsetX(1),
|
||||
mCurrentOffsetY(1)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -45,121 +38,149 @@ LLFontBitmapCache::~LLFontBitmapCache()
|
|||
{
|
||||
}
|
||||
|
||||
void LLFontBitmapCache::init(S32 num_components,
|
||||
S32 max_char_width,
|
||||
void LLFontBitmapCache::init(S32 max_char_width,
|
||||
S32 max_char_height)
|
||||
{
|
||||
reset();
|
||||
|
||||
mNumComponents = num_components;
|
||||
mMaxCharWidth = max_char_width;
|
||||
mMaxCharHeight = max_char_height;
|
||||
}
|
||||
|
||||
LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const
|
||||
{
|
||||
if (bitmap_num >= mImageRawVec.size())
|
||||
return NULL;
|
||||
|
||||
return mImageRawVec[bitmap_num];
|
||||
}
|
||||
|
||||
LLImageGL *LLFontBitmapCache::getImageGL(U32 bitmap_num) const
|
||||
{
|
||||
if (bitmap_num >= mImageGLVec.size())
|
||||
return NULL;
|
||||
|
||||
return mImageGLVec[bitmap_num];
|
||||
}
|
||||
|
||||
|
||||
BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitmap_num)
|
||||
{
|
||||
if ((mBitmapNum<0) || (mCurrentOffsetX + width + 1) > mBitmapWidth)
|
||||
S32 image_width = mMaxCharWidth * 20;
|
||||
S32 pow_iw = 2;
|
||||
while (pow_iw < image_width)
|
||||
{
|
||||
if ((mBitmapNum<0) || (mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight)
|
||||
pow_iw <<= 1;
|
||||
}
|
||||
image_width = pow_iw;
|
||||
image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
|
||||
|
||||
mBitmapWidth = image_width;
|
||||
mBitmapHeight = image_width;
|
||||
}
|
||||
|
||||
LLImageRaw *LLFontBitmapCache::getImageRaw(EFontGlyphType bitmap_type, U32 bitmap_num) const
|
||||
{
|
||||
const U32 bitmap_idx = static_cast<U32>(bitmap_type);
|
||||
if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageRawVec[bitmap_idx].size())
|
||||
return nullptr;
|
||||
|
||||
return mImageRawVec[bitmap_idx][bitmap_num];
|
||||
}
|
||||
|
||||
LLImageGL *LLFontBitmapCache::getImageGL(EFontGlyphType bitmap_type, U32 bitmap_num) const
|
||||
{
|
||||
const U32 bitmap_idx = static_cast<U32>(bitmap_type);
|
||||
if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageGLVec[bitmap_idx].size())
|
||||
return nullptr;
|
||||
|
||||
return mImageGLVec[bitmap_idx][bitmap_num];
|
||||
}
|
||||
|
||||
|
||||
BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyphType bitmap_type, U32& bitmap_num)
|
||||
{
|
||||
if (bitmap_type >= EFontGlyphType::Count)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const U32 bitmap_idx = static_cast<U32>(bitmap_type);
|
||||
if (mImageRawVec[bitmap_idx].empty() || (mCurrentOffsetX[bitmap_idx] + width + 1) > mBitmapWidth)
|
||||
{
|
||||
if ((mImageRawVec[bitmap_idx].empty()) || (mCurrentOffsetY[bitmap_idx] + 2*mMaxCharHeight + 2) > mBitmapHeight)
|
||||
{
|
||||
// We're out of space in the current image, or no image
|
||||
// has been allocated yet. Make a new one.
|
||||
|
||||
mImageRawVec.push_back(new LLImageRaw);
|
||||
mBitmapNum = mImageRawVec.size()-1;
|
||||
LLImageRaw *image_raw = getImageRaw(mBitmapNum);
|
||||
|
||||
S32 image_width = mMaxCharWidth * 20;
|
||||
S32 pow_iw = 2;
|
||||
while (pow_iw < image_width)
|
||||
{
|
||||
pow_iw *= 2;
|
||||
}
|
||||
image_width = pow_iw;
|
||||
image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
|
||||
S32 image_height = image_width;
|
||||
|
||||
mBitmapWidth = image_width;
|
||||
mBitmapHeight = image_height;
|
||||
|
||||
S32 num_components = getNumComponents(bitmap_type);
|
||||
mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components));
|
||||
bitmap_num = mImageRawVec[bitmap_idx].size() - 1;
|
||||
|
||||
LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num);
|
||||
if (EFontGlyphType::Grayscale == bitmap_type)
|
||||
{
|
||||
image_raw->clear(255, 0);
|
||||
}
|
||||
|
||||
// Make corresponding GL image.
|
||||
mImageGLVec.push_back(new LLImageGL(FALSE));
|
||||
LLImageGL *image_gl = getImageGL(mBitmapNum);
|
||||
|
||||
S32 image_width = mMaxCharWidth * 20;
|
||||
S32 pow_iw = 2;
|
||||
while (pow_iw < image_width)
|
||||
{
|
||||
pow_iw *= 2;
|
||||
}
|
||||
image_width = pow_iw;
|
||||
image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
|
||||
S32 image_height = image_width;
|
||||
|
||||
image_raw->resize(image_width, image_height, mNumComponents);
|
||||
|
||||
mBitmapWidth = image_width;
|
||||
mBitmapHeight = image_height;
|
||||
|
||||
switch (mNumComponents)
|
||||
{
|
||||
case 1:
|
||||
image_raw->clear();
|
||||
break;
|
||||
case 2:
|
||||
image_raw->clear(255, 0);
|
||||
break;
|
||||
}
|
||||
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false));
|
||||
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
|
||||
|
||||
// Start at beginning of the new image.
|
||||
mCurrentOffsetX = 1;
|
||||
mCurrentOffsetY = 1;
|
||||
mCurrentOffsetX[bitmap_idx] = 1;
|
||||
mCurrentOffsetY[bitmap_idx] = 1;
|
||||
|
||||
// Attach corresponding GL texture.
|
||||
image_gl->createGLTexture(0, image_raw);
|
||||
// Attach corresponding GL texture. (*TODO: is this needed?)
|
||||
gGL.getTexUnit(0)->bind(image_gl);
|
||||
image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move to next row in current image.
|
||||
mCurrentOffsetX = 1;
|
||||
mCurrentOffsetY += mMaxCharHeight + 1;
|
||||
mCurrentOffsetX[bitmap_idx] = 1;
|
||||
mCurrentOffsetY[bitmap_idx] += mMaxCharHeight + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pos_x = mCurrentOffsetX;
|
||||
pos_y = mCurrentOffsetY;
|
||||
bitmap_num = mBitmapNum;
|
||||
pos_x = mCurrentOffsetX[bitmap_idx];
|
||||
pos_y = mCurrentOffsetY[bitmap_idx];
|
||||
bitmap_num = getNumBitmaps(bitmap_type) - 1;
|
||||
|
||||
mCurrentOffsetX += width + 1;
|
||||
mCurrentOffsetX[bitmap_idx] += width + 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFontBitmapCache::destroyGL()
|
||||
{
|
||||
for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin();
|
||||
it != mImageGLVec.end(); ++it)
|
||||
for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++)
|
||||
{
|
||||
(*it)->destroyGLTexture();
|
||||
for (LLImageGL* image_gl : mImageGLVec[idx])
|
||||
{
|
||||
image_gl->destroyGLTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontBitmapCache::reset()
|
||||
{
|
||||
mImageRawVec.clear();
|
||||
|
||||
mImageGLVec.clear();
|
||||
for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++)
|
||||
{
|
||||
mImageRawVec[idx].clear();
|
||||
mImageGLVec[idx].clear();
|
||||
mCurrentOffsetX[idx] = 1;
|
||||
mCurrentOffsetY[idx] = 1;
|
||||
}
|
||||
|
||||
mBitmapWidth = 0;
|
||||
mBitmapHeight = 0;
|
||||
mBitmapNum = -1;
|
||||
mCurrentOffsetX = 1;
|
||||
mCurrentOffsetY = 1;
|
||||
}
|
||||
|
||||
//static
|
||||
U32 LLFontBitmapCache::getNumComponents(EFontGlyphType bitmap_type)
|
||||
{
|
||||
switch (bitmap_type)
|
||||
{
|
||||
case EFontGlyphType::Grayscale:
|
||||
return 2;
|
||||
case EFontGlyphType::Color:
|
||||
return 4;
|
||||
default:
|
||||
llassert(false);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@
|
|||
#include <vector>
|
||||
#include "lltrace.h"
|
||||
|
||||
enum class EFontGlyphType : U32
|
||||
{
|
||||
Grayscale = 0,
|
||||
Color,
|
||||
Count,
|
||||
Unspecified,
|
||||
};
|
||||
|
||||
// Maintain a collection of bitmaps containing rendered glyphs.
|
||||
// Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL.
|
||||
class LLFontBitmapCache
|
||||
|
|
@ -39,35 +47,35 @@ public:
|
|||
~LLFontBitmapCache();
|
||||
|
||||
// Need to call this once, before caching any glyphs.
|
||||
void init(S32 num_components,
|
||||
S32 max_char_width,
|
||||
void init(S32 max_char_width,
|
||||
S32 max_char_height);
|
||||
|
||||
void reset();
|
||||
|
||||
BOOL nextOpenPos(S32 width, S32 &posX, S32 &posY, S32 &bitmapNum);
|
||||
BOOL nextOpenPos(S32 width, S32& posX, S32& posY, EFontGlyphType bitmapType, U32& bitmapNum);
|
||||
|
||||
void destroyGL();
|
||||
|
||||
LLImageRaw *getImageRaw(U32 bitmapNum = 0) const;
|
||||
LLImageGL *getImageGL(U32 bitmapNum = 0) const;
|
||||
|
||||
LLImageRaw* getImageRaw(EFontGlyphType bitmapType, U32 bitmapNum) const;
|
||||
LLImageGL* getImageGL(EFontGlyphType bitmapType, U32 bitmapNum) const;
|
||||
|
||||
S32 getMaxCharWidth() const { return mMaxCharWidth; }
|
||||
S32 getNumComponents() const { return mNumComponents; }
|
||||
U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? mImageRawVec[static_cast<U32>(bitmapType)].size() : 0; }
|
||||
S32 getBitmapWidth() const { return mBitmapWidth; }
|
||||
S32 getBitmapHeight() const { return mBitmapHeight; }
|
||||
|
||||
protected:
|
||||
static U32 getNumComponents(EFontGlyphType bitmap_type);
|
||||
|
||||
private:
|
||||
S32 mNumComponents;
|
||||
S32 mBitmapWidth;
|
||||
S32 mBitmapHeight;
|
||||
S32 mBitmapNum;
|
||||
S32 mMaxCharWidth;
|
||||
S32 mMaxCharHeight;
|
||||
S32 mCurrentOffsetX;
|
||||
S32 mCurrentOffsetY;
|
||||
std::vector<LLPointer<LLImageRaw> > mImageRawVec;
|
||||
std::vector<LLPointer<LLImageGL> > mImageGLVec;
|
||||
S32 mBitmapWidth = 0;
|
||||
S32 mBitmapHeight = 0;
|
||||
S32 mCurrentOffsetX[static_cast<U32>(EFontGlyphType::Count)] = { 1 };
|
||||
S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 };
|
||||
S32 mMaxCharWidth = 0;
|
||||
S32 mMaxCharHeight = 0;
|
||||
std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)];
|
||||
std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)];
|
||||
};
|
||||
|
||||
#endif //LL_LLFONTBITMAPCACHE_H
|
||||
|
|
|
|||
|
|
@ -34,14 +34,17 @@
|
|||
#ifdef LL_WINDOWS
|
||||
#include <freetype2\freetype\ftsystem.h>
|
||||
#endif
|
||||
#include "llfontfreetypesvg.h"
|
||||
|
||||
// For some reason, this won't work if it's not wrapped in the ifdef
|
||||
#ifdef FT_FREETYPE_H
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
|
||||
#include "lldir.h"
|
||||
#include "llerror.h"
|
||||
#include "llimage.h"
|
||||
#include "llimagepng.h"
|
||||
//#include "llimagej2c.h"
|
||||
#include "llmath.h" // Linden math
|
||||
#include "llstring.h"
|
||||
|
|
@ -49,6 +52,8 @@
|
|||
#include "llfontbitmapcache.h"
|
||||
#include "llgl.h"
|
||||
|
||||
#define ENABLE_OT_SVG_SUPPORT
|
||||
|
||||
FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
|
||||
|
||||
LLFontManager *gFontManagerp = NULL;
|
||||
|
|
@ -81,6 +86,16 @@ LLFontManager::LLFontManager()
|
|||
LL_ERRS() << "Freetype initialization failure!" << LL_ENDL;
|
||||
FT_Done_FreeType(gFTLibrary);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OT_SVG_SUPPORT
|
||||
SVG_RendererHooks hooks = {
|
||||
LLFontFreeTypeSvgRenderer::OnInit,
|
||||
LLFontFreeTypeSvgRenderer::OnFree,
|
||||
LLFontFreeTypeSvgRenderer::OnRender,
|
||||
LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot,
|
||||
};
|
||||
FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks);
|
||||
#endif
|
||||
}
|
||||
|
||||
LLFontManager::~LLFontManager()
|
||||
|
|
@ -89,8 +104,9 @@ LLFontManager::~LLFontManager()
|
|||
}
|
||||
|
||||
|
||||
LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
|
||||
LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type)
|
||||
: mGlyphIndex(index),
|
||||
mGlyphType(glyph_type),
|
||||
mWidth(0), // In pixels
|
||||
mHeight(0), // In pixels
|
||||
mXAdvance(0.f), // In pixels
|
||||
|
|
@ -99,10 +115,25 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
|
|||
mYBitmapOffset(0), // Offset to the origin in the bitmap
|
||||
mXBearing(0), // Distance from baseline to left in pixels
|
||||
mYBearing(0), // Distance from baseline to top in pixels
|
||||
mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph
|
||||
mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph
|
||||
{
|
||||
}
|
||||
|
||||
LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi)
|
||||
: mGlyphIndex(fgi.mGlyphIndex)
|
||||
, mGlyphType(fgi.mGlyphType)
|
||||
, mWidth(fgi.mWidth)
|
||||
, mHeight(fgi.mHeight)
|
||||
, mXAdvance(fgi.mXAdvance)
|
||||
, mYAdvance(fgi.mYAdvance)
|
||||
, mXBitmapOffset(fgi.mXBitmapOffset)
|
||||
, mYBitmapOffset(fgi.mYBitmapOffset)
|
||||
, mXBearing(fgi.mXBearing)
|
||||
, mYBearing(fgi.mYBearing)
|
||||
{
|
||||
mBitmapEntry = fgi.mBitmapEntry;
|
||||
}
|
||||
|
||||
LLFontFreetype::LLFontFreetype()
|
||||
: mFontBitmapCachep(new LLFontBitmapCache),
|
||||
mAscender(0.f),
|
||||
|
|
@ -156,7 +187,7 @@ void ft_close_cb(FT_Stream stream) {
|
|||
}
|
||||
#endif
|
||||
|
||||
BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
|
||||
BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n)
|
||||
{
|
||||
// Don't leak face objects. This is also needed to deal with
|
||||
// changed font file names.
|
||||
|
|
@ -220,7 +251,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
|
|||
S32 max_char_width = ll_round(0.5f + (x_max - x_min));
|
||||
S32 max_char_height = ll_round(0.5f + (y_max - y_min));
|
||||
|
||||
mFontBitmapCachep->init(components, max_char_width, max_char_height);
|
||||
mFontBitmapCachep->init(max_char_width, max_char_height);
|
||||
|
||||
if (!mFTFace->charmap)
|
||||
{
|
||||
|
|
@ -231,7 +262,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
|
|||
if (!mIsFallback)
|
||||
{
|
||||
// Add the default glyph
|
||||
addGlyphFromFont(this, 0, 0);
|
||||
addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);
|
||||
}
|
||||
|
||||
mName = filename;
|
||||
|
|
@ -323,14 +354,11 @@ void LLFontFreetype::clearFontStreams()
|
|||
}
|
||||
#endif
|
||||
|
||||
void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
|
||||
void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor)
|
||||
{
|
||||
mFallbackFonts = font;
|
||||
}
|
||||
|
||||
const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const
|
||||
{
|
||||
return mFallbackFonts;
|
||||
// Insert functor fallbacks before generic fallbacks
|
||||
mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(),
|
||||
std::make_pair(fallback_font, functor));
|
||||
}
|
||||
|
||||
F32 LLFontFreetype::getLineHeight() const
|
||||
|
|
@ -354,7 +382,7 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const
|
|||
return 0.0;
|
||||
|
||||
// Return existing info only if it is current
|
||||
LLFontGlyphInfo* gi = getGlyphInfo(wch);
|
||||
LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
if (gi)
|
||||
{
|
||||
return gi->mXAdvance;
|
||||
|
|
@ -386,10 +414,10 @@ F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
|
|||
return 0.0;
|
||||
|
||||
//llassert(!mIsFallback);
|
||||
LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);;
|
||||
LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);;
|
||||
U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
|
||||
// Kern this puppy.
|
||||
LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right);
|
||||
LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified);
|
||||
U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
|
||||
|
||||
FT_Vector delta;
|
||||
|
|
@ -420,60 +448,94 @@ BOOL LLFontFreetype::hasGlyph(llwchar wch) const
|
|||
return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end());
|
||||
}
|
||||
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const
|
||||
{
|
||||
if (mFTFace == NULL)
|
||||
return FALSE;
|
||||
|
||||
llassert(!mIsFallback);
|
||||
llassert(glyph_type < EFontGlyphType::Count);
|
||||
//LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL;
|
||||
|
||||
FT_UInt glyph_index;
|
||||
|
||||
// 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))
|
||||
{
|
||||
glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
|
||||
if (glyph_index)
|
||||
{
|
||||
return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Initialize char to glyph map
|
||||
glyph_index = FT_Get_Char_Index(mFTFace, wch);
|
||||
if (glyph_index == 0)
|
||||
{
|
||||
//LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL;
|
||||
font_vector_t::const_iterator iter;
|
||||
for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++)
|
||||
for (; it_fallback != mFallbackFonts.cend(); ++it_fallback)
|
||||
{
|
||||
glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
|
||||
glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
|
||||
if (glyph_index)
|
||||
{
|
||||
return addGlyphFromFont(*iter, wch, glyph_index);
|
||||
return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
|
||||
if (iter == mCharGlyphInfoMap.end())
|
||||
std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch);
|
||||
char_glyph_info_map_t::iterator iter =
|
||||
std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; });
|
||||
if (iter == range_it.second)
|
||||
{
|
||||
return addGlyphFromFont(this, wch, glyph_index);
|
||||
return addGlyphFromFont(this, wch, glyph_index, glyph_type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType requested_glyph_type) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (mFTFace == NULL)
|
||||
return NULL;
|
||||
|
||||
llassert(!mIsFallback);
|
||||
fontp->renderGlyph(glyph_index);
|
||||
fontp->renderGlyph(requested_glyph_type, glyph_index);
|
||||
|
||||
EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified;
|
||||
switch (fontp->mFTFace->glyph->bitmap.pixel_mode)
|
||||
{
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
bitmap_glyph_type = EFontGlyphType::Grayscale;
|
||||
break;
|
||||
case FT_PIXEL_MODE_BGRA:
|
||||
bitmap_glyph_type = EFontGlyphType::Color;
|
||||
break;
|
||||
default:
|
||||
llassert_always(true);
|
||||
break;
|
||||
}
|
||||
S32 width = fontp->mFTFace->glyph->bitmap.width;
|
||||
S32 height = fontp->mFTFace->glyph->bitmap.rows;
|
||||
|
||||
S32 pos_x, pos_y;
|
||||
S32 bitmap_num;
|
||||
mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num);
|
||||
U32 bitmap_num;
|
||||
mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num);
|
||||
mAddGlyphCount++;
|
||||
|
||||
LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
|
||||
LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type);
|
||||
gi->mXBitmapOffset = pos_x;
|
||||
gi->mYBitmapOffset = pos_y;
|
||||
gi->mBitmapNum = bitmap_num;
|
||||
gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num);
|
||||
gi->mWidth = width;
|
||||
gi->mHeight = height;
|
||||
gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
|
||||
|
|
@ -484,8 +546,12 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
|
|||
|
||||
insertGlyphInfo(wch, gi);
|
||||
|
||||
llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
|
||||
|| fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
if (requested_glyph_type != bitmap_glyph_type)
|
||||
{
|
||||
LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi);
|
||||
gi_temp->mGlyphType = bitmap_glyph_type;
|
||||
insertGlyphInfo(wch, gi_temp);
|
||||
}
|
||||
|
||||
if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
|
||||
|| fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
|
||||
|
|
@ -520,78 +586,95 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
|
|||
buffer_row_stride = width;
|
||||
}
|
||||
|
||||
switch (mFontBitmapCachep->getNumComponents())
|
||||
{
|
||||
case 1:
|
||||
mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x,
|
||||
pos_y,
|
||||
width,
|
||||
height,
|
||||
buffer_data,
|
||||
buffer_row_stride,
|
||||
TRUE);
|
||||
break;
|
||||
case 2:
|
||||
setSubImageLuminanceAlpha(pos_x,
|
||||
pos_y,
|
||||
bitmap_num,
|
||||
width,
|
||||
height,
|
||||
buffer_data,
|
||||
buffer_row_stride);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setSubImageLuminanceAlpha(pos_x,
|
||||
pos_y,
|
||||
bitmap_num,
|
||||
width,
|
||||
height,
|
||||
buffer_data,
|
||||
buffer_row_stride);
|
||||
|
||||
if (tmp_graydata)
|
||||
delete[] tmp_graydata;
|
||||
}
|
||||
else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
|
||||
{
|
||||
setSubImageBGRA(pos_x,
|
||||
pos_y,
|
||||
bitmap_num,
|
||||
fontp->mFTFace->glyph->bitmap.width,
|
||||
fontp->mFTFace->glyph->bitmap.rows,
|
||||
fontp->mFTFace->glyph->bitmap.buffer,
|
||||
llabs(fontp->mFTFace->glyph->bitmap.pitch));
|
||||
} else {
|
||||
// we don't know how to handle this pixel format from FreeType;
|
||||
// omit it from the font-image.
|
||||
llassert(false);
|
||||
}
|
||||
|
||||
LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
|
||||
LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num);
|
||||
image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const
|
||||
LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const
|
||||
{
|
||||
char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
|
||||
if (iter != mCharGlyphInfoMap.end())
|
||||
std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch);
|
||||
|
||||
char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type)
|
||||
? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; })
|
||||
: range_it.first;
|
||||
if (iter != range_it.second)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this glyph doesn't yet exist, so render it and return the result
|
||||
return addGlyph(wch);
|
||||
return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
|
||||
{
|
||||
char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
|
||||
if (iter != mCharGlyphInfoMap.end())
|
||||
llassert(gi->mGlyphType < EFontGlyphType::Count);
|
||||
std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch);
|
||||
|
||||
char_glyph_info_map_t::iterator iter =
|
||||
std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; });
|
||||
if (iter != range_it.second)
|
||||
{
|
||||
delete iter->second;
|
||||
iter->second = gi;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCharGlyphInfoMap[wch] = gi;
|
||||
mCharGlyphInfoMap.insert(std::make_pair(wch, gi));
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontFreetype::renderGlyph(U32 glyph_index) const
|
||||
void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const
|
||||
{
|
||||
if (mFTFace == NULL)
|
||||
return;
|
||||
|
||||
llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) );
|
||||
FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT;
|
||||
if (EFontGlyphType::Color == bitmap_type)
|
||||
{
|
||||
// We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode
|
||||
load_flags |= FT_LOAD_COLOR;
|
||||
}
|
||||
|
||||
FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags);
|
||||
if (FT_Err_Ok != error)
|
||||
{
|
||||
std::string message = llformat(
|
||||
"Error %d (%s) loading glyph %u: bitmap_type=%u, load_flags=%d",
|
||||
error, FT_Error_String(error), glyph_index, bitmap_type, load_flags);
|
||||
LL_WARNS_ONCE() << message << LL_ENDL;
|
||||
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
|
||||
llassert_always_msg(FT_Err_Ok == error, message.c_str());
|
||||
}
|
||||
|
||||
llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) );
|
||||
|
||||
|
|
@ -601,7 +684,7 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const
|
|||
void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
|
||||
{
|
||||
resetBitmapCache();
|
||||
loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback);
|
||||
loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0);
|
||||
if (!mIsFallback)
|
||||
{
|
||||
// This is the head of the list - need to rebuild ourself and all fallbacks.
|
||||
|
|
@ -611,11 +694,9 @@ void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
|
|||
}
|
||||
else
|
||||
{
|
||||
for(font_vector_t::iterator it = mFallbackFonts.begin();
|
||||
it != mFallbackFonts.end();
|
||||
++it)
|
||||
for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it)
|
||||
{
|
||||
(*it)->reset(vert_dpi, horz_dpi);
|
||||
it->first->reset(vert_dpi, horz_dpi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -637,7 +718,7 @@ void LLFontFreetype::resetBitmapCache()
|
|||
if(!mIsFallback)
|
||||
{
|
||||
// Add the empty glyph
|
||||
addGlyphFromFont(this, 0, 0);
|
||||
addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -651,6 +732,34 @@ const std::string &LLFontFreetype::getName() const
|
|||
return mName;
|
||||
}
|
||||
|
||||
static void dumpFontBitmap(const LLImageRaw* image_raw, const std::string& file_name)
|
||||
{
|
||||
LLPointer<LLImagePNG> tmpImage = new LLImagePNG();
|
||||
if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) )
|
||||
{
|
||||
LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontFreetype::dumpFontBitmaps() const
|
||||
{
|
||||
// Dump all the regular bitmaps (if any)
|
||||
for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++)
|
||||
{
|
||||
dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx));
|
||||
}
|
||||
|
||||
// Dump all the color bitmaps (if any)
|
||||
for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++)
|
||||
{
|
||||
dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx));
|
||||
}
|
||||
}
|
||||
|
||||
const LLFontBitmapCache* LLFontFreetype::getFontBitmapCache() const
|
||||
{
|
||||
return mFontBitmapCachep;
|
||||
|
|
@ -666,17 +775,46 @@ U8 LLFontFreetype::getStyle() const
|
|||
return mStyle;
|
||||
}
|
||||
|
||||
bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const
|
||||
{
|
||||
LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num);
|
||||
llassert(!mIsFallback);
|
||||
llassert(image_raw && (image_raw->getComponents() == 4));
|
||||
|
||||
// NOTE: inspired by LLImageRaw::setSubImage()
|
||||
U32* image_data = (U32*)image_raw->getData();
|
||||
if (!image_data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (U32 idxRow = 0; idxRow < height; idxRow++)
|
||||
{
|
||||
const U32 nSrcRow = height - 1 - idxRow;
|
||||
const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents();
|
||||
const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x;
|
||||
|
||||
for (U32 idxCol = 0; idxCol < width; idxCol++)
|
||||
{
|
||||
U32 nTemp = nSrcOffset + idxCol * 4;
|
||||
image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const
|
||||
{
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num);
|
||||
|
||||
llassert(!mIsFallback);
|
||||
llassert(image_raw && (image_raw->getComponents() == 2));
|
||||
|
||||
|
||||
U8 *target = image_raw->getData();
|
||||
llassert(target);
|
||||
|
||||
if (!data)
|
||||
if (!data || !target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,11 @@ private:
|
|||
|
||||
struct LLFontGlyphInfo
|
||||
{
|
||||
LLFontGlyphInfo(U32 index);
|
||||
LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type);
|
||||
LLFontGlyphInfo(const LLFontGlyphInfo& fgi);
|
||||
|
||||
U32 mGlyphIndex;
|
||||
EFontGlyphType mGlyphType;
|
||||
|
||||
// Metrics
|
||||
S32 mWidth; // In pixels
|
||||
|
|
@ -71,7 +73,7 @@ struct LLFontGlyphInfo
|
|||
S32 mYBitmapOffset; // Offset to the origin in the bitmap
|
||||
S32 mXBearing; // Distance from baseline to left in pixels
|
||||
S32 mYBearing; // Distance from baseline to top in pixels
|
||||
S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph
|
||||
std::pair<EFontGlyphType, S32> mBitmapEntry; // Which bitmap in the bitmap cache contains this glyph
|
||||
};
|
||||
|
||||
extern LLFontManager *gFontManagerp;
|
||||
|
|
@ -84,7 +86,7 @@ public:
|
|||
|
||||
// is_fallback should be true for fallback fonts that aren't used
|
||||
// to render directly (Unicode backup, primarily)
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n = 0);
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n);
|
||||
|
||||
S32 getNumFaces(const std::string& filename);
|
||||
|
||||
|
|
@ -93,10 +95,8 @@ public:
|
|||
void clearFontStreams();
|
||||
#endif
|
||||
|
||||
typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;
|
||||
|
||||
void setFallbackFonts(const font_vector_t &font);
|
||||
const font_vector_t &getFallbackFonts() const;
|
||||
typedef std::function<bool(llwchar)> char_functor_t;
|
||||
void addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor = nullptr);
|
||||
|
||||
// Global font metrics - in units of pixels
|
||||
F32 getLineHeight() const;
|
||||
|
|
@ -135,7 +135,7 @@ public:
|
|||
F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters
|
||||
F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters
|
||||
|
||||
LLFontGlyphInfo* getGlyphInfo(llwchar wch) const;
|
||||
LLFontGlyphInfo* getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const;
|
||||
|
||||
void reset(F32 vert_dpi, F32 horz_dpi);
|
||||
|
||||
|
|
@ -143,6 +143,7 @@ public:
|
|||
|
||||
const std::string& getName() const;
|
||||
|
||||
void dumpFontBitmaps() const;
|
||||
const LLFontBitmapCache* getFontBitmapCache() const;
|
||||
|
||||
void setStyle(U8 style);
|
||||
|
|
@ -151,10 +152,11 @@ public:
|
|||
private:
|
||||
void resetBitmapCache();
|
||||
void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const;
|
||||
bool setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const;
|
||||
BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character
|
||||
LLFontGlyphInfo* addGlyph(llwchar wch) const; // Add a new character to the font if necessary
|
||||
LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
|
||||
void renderGlyph(U32 glyph_index) const;
|
||||
LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary
|
||||
LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
|
||||
void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const;
|
||||
void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
|
||||
|
||||
std::string mName;
|
||||
|
|
@ -174,9 +176,12 @@ private:
|
|||
#endif
|
||||
|
||||
BOOL mIsFallback;
|
||||
font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
|
||||
typedef std::pair<LLPointer<LLFontFreetype>, char_functor_t> fallback_font_t;
|
||||
typedef std::vector<fallback_font_t> fallback_font_vector_t;
|
||||
fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
|
||||
|
||||
typedef boost::unordered_map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
|
||||
// *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique)
|
||||
typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
|
||||
mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
|
||||
|
||||
mutable LLFontBitmapCache* mFontBitmapCachep;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
/**
|
||||
* @file llfontfreetypesvg.cpp
|
||||
* @brief Freetype font library SVG glyph rendering
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, 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 "linden_common.h"
|
||||
|
||||
#include "llfontfreetypesvg.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4702)
|
||||
#endif
|
||||
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include <nanosvg/nanosvg.h>
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include <nanosvg/nanosvgrast.h>
|
||||
|
||||
#if LL_WINDOWS
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
struct LLSvgRenderData
|
||||
{
|
||||
FT_UInt GlyphIndex = 0;
|
||||
FT_Error Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time
|
||||
// (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170)
|
||||
NSVGimage* pNSvgImage = nullptr;
|
||||
float Scale = 0.f;
|
||||
};
|
||||
|
||||
// static
|
||||
FT_Error LLFontFreeTypeSvgRenderer::OnInit(FT_Pointer* state)
|
||||
{
|
||||
// The SVG driver hook state is shared across all callback invocations; since our state is lightweight
|
||||
// we store it in the glyph instead.
|
||||
*state = nullptr;
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontFreeTypeSvgRenderer::OnFree(FT_Pointer* state)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontFreeTypeSvgRenderer::OnDataFinalizer(void* objectp)
|
||||
{
|
||||
FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp);
|
||||
|
||||
LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
|
||||
glyph_slot->generic.data = nullptr;
|
||||
glyph_slot->generic.finalizer = nullptr;
|
||||
delete(pData);
|
||||
}
|
||||
|
||||
//static
|
||||
FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer*)
|
||||
{
|
||||
FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other);
|
||||
|
||||
llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex);
|
||||
if (!glyph_slot->generic.data)
|
||||
{
|
||||
glyph_slot->generic.data = new LLSvgRenderData();
|
||||
glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer;
|
||||
}
|
||||
LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
|
||||
if (!cache)
|
||||
{
|
||||
datap->GlyphIndex = glyph_slot->glyph_index;
|
||||
datap->Error = FT_Err_Ok;
|
||||
}
|
||||
|
||||
// NOTE: nsvgParse modifies the input string so we need a temporary copy
|
||||
llassert(!datap->pNSvgImage || cache);
|
||||
if (!datap->pNSvgImage)
|
||||
{
|
||||
char* document_buffer = new char[document->svg_document_length + 1];
|
||||
memcpy(document_buffer, document->svg_document, document->svg_document_length);
|
||||
document_buffer[document->svg_document_length] = '\0';
|
||||
|
||||
datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.);
|
||||
|
||||
delete[] document_buffer;
|
||||
}
|
||||
|
||||
if (!datap->pNSvgImage)
|
||||
{
|
||||
datap->Error = FT_Err_Invalid_SVG_Document;
|
||||
return FT_Err_Invalid_SVG_Document;
|
||||
}
|
||||
|
||||
// We don't (currently) support transformations so test for an identity rotation matrix + zero translation
|
||||
if (document->transform.xx != 1 << 16 || document->transform.yx != 0 ||
|
||||
document->transform.xy != 0 || document->transform.yy != 1 << 16 ||
|
||||
document->delta.x > 0 || document->delta.y > 0)
|
||||
{
|
||||
datap->Error = FT_Err_Unimplemented_Feature;
|
||||
return FT_Err_Unimplemented_Feature;
|
||||
}
|
||||
|
||||
float svg_width = datap->pNSvgImage->width;
|
||||
float svg_height = datap->pNSvgImage->height;
|
||||
if (svg_width == 0.f || svg_height == 0.f)
|
||||
{
|
||||
svg_width = document->units_per_EM;
|
||||
svg_height = document->units_per_EM;
|
||||
}
|
||||
|
||||
float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width);
|
||||
float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height);
|
||||
float svg_scale = llmin(svg_x_scale, svg_y_scale);
|
||||
datap->Scale = svg_scale;
|
||||
|
||||
glyph_slot->bitmap.width = floorf(svg_width) * svg_scale;
|
||||
glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale;
|
||||
glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2;
|
||||
glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f;
|
||||
glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4;
|
||||
glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
|
||||
/* Copied as-is from fcft (MIT license) */
|
||||
|
||||
// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
|
||||
float horiBearingX = 0.;
|
||||
float horiBearingY = -glyph_slot->bitmap_top;
|
||||
|
||||
// XXX parentheses correct?
|
||||
float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2;
|
||||
float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2;
|
||||
|
||||
// Do conversion in two steps to avoid 'bad function cast' warning
|
||||
glyph_slot->metrics.width = glyph_slot->bitmap.width * 64;
|
||||
glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64;
|
||||
glyph_slot->metrics.horiBearingX = horiBearingX * 64;
|
||||
glyph_slot->metrics.horiBearingY = horiBearingY * 64;
|
||||
glyph_slot->metrics.vertBearingX = vertBearingX * 64;
|
||||
glyph_slot->metrics.vertBearingY = vertBearingY * 64;
|
||||
if (glyph_slot->metrics.vertAdvance == 0)
|
||||
{
|
||||
glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64;
|
||||
}
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
// static
|
||||
FT_Error LLFontFreeTypeSvgRenderer::OnRender(FT_GlyphSlot glyph_slot, FT_Pointer*)
|
||||
{
|
||||
LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
|
||||
llassert(FT_Err_Ok == datap->Error);
|
||||
if (FT_Err_Ok != datap->Error)
|
||||
{
|
||||
return datap->Error;
|
||||
}
|
||||
|
||||
// Render to glyph bitmap
|
||||
NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer();
|
||||
nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch);
|
||||
nsvgDeleteRasterizer(nsvgRasterizer);
|
||||
nsvgDelete(datap->pNSvgImage);
|
||||
datap->pNSvgImage = nullptr;
|
||||
|
||||
// Convert from RGBA to BGRA
|
||||
U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer;
|
||||
for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++)
|
||||
{
|
||||
for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++)
|
||||
{
|
||||
size_t pixel_idx = y * w + x;
|
||||
size_t byte_idx = pixel_idx * 4;
|
||||
U8 alpha = byte_buffer[byte_idx + 3];
|
||||
// Store as ARGB (*TODO - do we still have to care about endianness?)
|
||||
pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
glyph_slot->format = FT_GLYPH_FORMAT_BITMAP;
|
||||
glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @file llfontfreetypesvg.h
|
||||
* @brief Freetype font library SVG glyph rendering
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, 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 <ft2build.h>
|
||||
#include FT_TYPES_H
|
||||
#include FT_MODULE_H
|
||||
#include FT_OTSVG_H
|
||||
|
||||
// See https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html
|
||||
class LLFontFreeTypeSvgRenderer
|
||||
{
|
||||
public:
|
||||
// Called when the very first OT-SVG glyph is rendered (across the entire lifetime of our FT_Library object)
|
||||
static FT_Error OnInit(FT_Pointer* state);
|
||||
|
||||
// Called when the ot-svg module is being freed (but only called if the init hook was called previously)
|
||||
static void OnFree(FT_Pointer* state);
|
||||
|
||||
// Called to preset the glyph slot, twice per glyph:
|
||||
// - when FT_Load_Glyph needs to preset the glyph slot (with cache == false)
|
||||
// - right before the svg module calls the render callback hook. (with cache == true)
|
||||
static FT_Error OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer* state);
|
||||
|
||||
// Called to render an OT-SVG glyph (right after the preset hook OnPresetGlypthSlot was called with cache set to TRUE)
|
||||
static FT_Error OnRender(FT_GlyphSlot glyph_slot, FT_Pointer* state);
|
||||
|
||||
// Called to deallocate our per glyph slot data
|
||||
static void OnDataFinalizer(void* objectp);
|
||||
};
|
||||
|
|
@ -89,14 +89,14 @@ void LLFontGL::destroyGL()
|
|||
mFontFreetype->destroyGL();
|
||||
}
|
||||
|
||||
BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
|
||||
BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n)
|
||||
{
|
||||
if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
|
||||
{
|
||||
mFontFreetype = new LLFontFreetype;
|
||||
}
|
||||
|
||||
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback, face_n);
|
||||
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, is_fallback, face_n);
|
||||
}
|
||||
|
||||
S32 LLFontGL::getNumFaces(const std::string& filename)
|
||||
|
|
@ -110,14 +110,14 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
|
|||
}
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
LLRectf rect_float(rect.mLeft, rect.mTop, rect.mRight, rect.mBottom);
|
||||
return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses);
|
||||
return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);
|
||||
}
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
F32 x = rect.mLeft;
|
||||
F32 y = 0.f;
|
||||
|
|
@ -138,12 +138,12 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
|
|||
y = rect.mBottom;
|
||||
break;
|
||||
}
|
||||
return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses);
|
||||
return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses, use_color);
|
||||
}
|
||||
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
|
||||
ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
|
||||
if (-1 == max_chars)
|
||||
{
|
||||
length = (S32)wstr.length() - begin_offset;
|
||||
max_chars = length = (S32)wstr.length() - begin_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -254,7 +254,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
|
||||
const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
|
||||
|
||||
|
||||
BOOL draw_ellipses = FALSE;
|
||||
if (use_ellipses)
|
||||
{
|
||||
|
|
@ -278,7 +277,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
|
||||
LLColor4U text_color(color);
|
||||
|
||||
S32 bitmap_num = -1;
|
||||
std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1);
|
||||
S32 glyph_count = 0;
|
||||
for (i = begin_offset; i < begin_offset + length; i++)
|
||||
{
|
||||
|
|
@ -288,7 +287,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
next_glyph = NULL;
|
||||
if(!fgi)
|
||||
{
|
||||
fgi = mFontFreetype->getGlyphInfo(wch);
|
||||
fgi = mFontFreetype->getGlyphInfo(wch, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color);
|
||||
}
|
||||
if (!fgi)
|
||||
{
|
||||
|
|
@ -296,8 +295,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
break;
|
||||
}
|
||||
// Per-glyph bitmap texture.
|
||||
S32 next_bitmap_num = fgi->mBitmapNum;
|
||||
if (next_bitmap_num != bitmap_num)
|
||||
std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry;
|
||||
if (next_bitmap_entry != bitmap_entry)
|
||||
{
|
||||
// Actually draw the queued glyphs before switching their texture;
|
||||
// otherwise the queued glyphs will be taken from wrong textures.
|
||||
|
|
@ -311,8 +310,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
glyph_count = 0;
|
||||
}
|
||||
|
||||
bitmap_num = next_bitmap_num;
|
||||
LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
|
||||
bitmap_entry = next_bitmap_entry;
|
||||
LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second);
|
||||
gGL.getTexUnit(0)->bind(font_image);
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +344,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
glyph_count = 0;
|
||||
}
|
||||
|
||||
drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);
|
||||
drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength);
|
||||
|
||||
chars_drawn++;
|
||||
cur_x += fgi->mXAdvance;
|
||||
|
|
@ -355,7 +354,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
if (next_char && (next_char < LAST_CHARACTER))
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color);
|
||||
cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +408,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
shadow,
|
||||
S32_MAX, max_pixels,
|
||||
right_x,
|
||||
FALSE);
|
||||
FALSE,
|
||||
use_color);
|
||||
gGL.popUIMatrix();
|
||||
}
|
||||
|
||||
|
|
@ -420,22 +420,22 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
|
||||
S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const
|
||||
{
|
||||
return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses);
|
||||
return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow);
|
||||
}
|
||||
|
||||
// font metrics - override for LLFontFreetype that returns units of virtual pixels
|
||||
|
|
@ -488,7 +488,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars) const
|
|||
return getWidthF32(wchars, 0, S32_MAX);
|
||||
}
|
||||
|
||||
F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const
|
||||
F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars) const
|
||||
{
|
||||
LLWString wtext = utf8str_to_wstring(utf8text);
|
||||
return getWidthF32(wtext.c_str(), begin_offset, max_chars);
|
||||
|
|
@ -512,7 +512,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
|
|||
next_glyph = NULL;
|
||||
if(!fgi)
|
||||
{
|
||||
fgi = mFontFreetype->getGlyphInfo(wch);
|
||||
fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
}
|
||||
|
||||
F32 advance = mFontFreetype->getXAdvance(fgi);
|
||||
|
|
@ -535,7 +535,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
|
|||
&& (next_char < LAST_CHARACTER))
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char, EFontGlyphType::Unspecified);
|
||||
cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
|
||||
}
|
||||
// Round after kerning.
|
||||
|
|
@ -556,7 +556,7 @@ void LLFontGL::generateASCIIglyphs()
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
|
||||
for (U32 i = 32; (i < 127); i++)
|
||||
{
|
||||
mFontFreetype->getGlyphInfo(i);
|
||||
mFontFreetype->getGlyphInfo(i, EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -630,7 +630,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
|
|||
next_glyph = NULL;
|
||||
if(!fgi)
|
||||
{
|
||||
fgi = mFontFreetype->getGlyphInfo(wch);
|
||||
fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
|
||||
if (NULL == fgi)
|
||||
{
|
||||
|
|
@ -655,7 +655,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
|
|||
if (((i+1) < max_chars) && wchars[i+1])
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1], EFontGlyphType::Unspecified);
|
||||
cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
|
||||
}
|
||||
|
||||
|
|
@ -702,7 +702,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
|
|||
{
|
||||
llwchar wch = wchars[i];
|
||||
|
||||
const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);
|
||||
const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
|
||||
// last character uses character width, since the whole character needs to be visible
|
||||
// other characters just use advance
|
||||
|
|
@ -777,7 +777,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t
|
|||
next_glyph = NULL;
|
||||
if(!glyph)
|
||||
{
|
||||
glyph = mFontFreetype->getGlyphInfo(wch);
|
||||
glyph = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
}
|
||||
|
||||
F32 char_width = mFontFreetype->getXAdvance(glyph);
|
||||
|
|
@ -807,7 +807,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t
|
|||
&& (wchars[(pos + 1)]))
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1], EFontGlyphType::Unspecified);
|
||||
cur_x += mFontFreetype->getXKerning(glyph, next_glyph);
|
||||
}
|
||||
|
||||
|
|
@ -847,6 +847,26 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
|
|||
LLFontGL::loadDefaultFonts();
|
||||
}
|
||||
|
||||
void LLFontGL::dumpTextures()
|
||||
{
|
||||
if (mFontFreetype.notNull())
|
||||
{
|
||||
mFontFreetype->dumpFontBitmaps();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontGL::dumpFonts()
|
||||
{
|
||||
sFontRegistry->dump();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontGL::dumpFontTextures()
|
||||
{
|
||||
sFontRegistry->dumpTextures();
|
||||
}
|
||||
|
||||
// Force standard fonts to get generated up front.
|
||||
// This is primarily for error detection purposes.
|
||||
// Don't do this during initClass because it can be slow and we want to get
|
||||
|
|
@ -1009,6 +1029,20 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
|
|||
return gl_vfont_align;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontEmoji()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0));
|
||||
return fontp;;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontEmojiHuge()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Huge", 0));
|
||||
return fontp;;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontMonospace()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public:
|
|||
|
||||
void destroyGL();
|
||||
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback, S32 face_n = 0);
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n);
|
||||
|
||||
S32 getNumFaces(const std::string& filename);
|
||||
|
||||
|
|
@ -98,7 +98,8 @@ public:
|
|||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
BOOL use_ellipses = FALSE,
|
||||
BOOL use_color = TRUE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset,
|
||||
const LLRectf& rect,
|
||||
|
|
@ -107,7 +108,8 @@ public:
|
|||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
BOOL use_ellipses = FALSE,
|
||||
BOOL use_color = TRUE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset,
|
||||
F32 x, F32 y,
|
||||
|
|
@ -116,12 +118,13 @@ public:
|
|||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
BOOL use_ellipses = FALSE,
|
||||
BOOL use_color = TRUE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const;
|
||||
|
||||
// renderUTF8 does a conversion, so is slower!
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, F32* right_x = NULL, BOOL use_ellipses = FALSE, BOOL use_color = TRUE) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
|
||||
|
||||
|
|
@ -132,12 +135,12 @@ public:
|
|||
|
||||
S32 getWidth(const std::string& utf8text) const;
|
||||
S32 getWidth(const llwchar* wchars) const;
|
||||
S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars ) const;
|
||||
S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars) const;
|
||||
S32 getWidth(const llwchar* wchars, S32 offset, S32 max_chars) const;
|
||||
|
||||
F32 getWidthF32(const std::string& utf8text) const;
|
||||
F32 getWidthF32(const llwchar* wchars) const;
|
||||
F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const;
|
||||
F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars) const;
|
||||
F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const;
|
||||
|
||||
// The following are called often, frequently with large buffers, so do not use a string interface
|
||||
|
|
@ -165,6 +168,10 @@ public:
|
|||
|
||||
static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true);
|
||||
|
||||
void dumpTextures();
|
||||
static void dumpFonts();
|
||||
static void dumpFontTextures();
|
||||
|
||||
// Load sans-serif, sans-serif-small, etc.
|
||||
// Slow, requires multiple seconds to load fonts.
|
||||
static bool loadDefaultFonts();
|
||||
|
|
@ -187,6 +194,8 @@ public:
|
|||
|
||||
static void setFontDisplay(BOOL flag) { sDisplayFont = flag; }
|
||||
|
||||
static LLFontGL* getFontEmoji();
|
||||
static LLFontGL* getFontEmojiHuge();
|
||||
static LLFontGL* getFontMonospace();
|
||||
static LLFontGL* getFontSansSerifSmall();
|
||||
static LLFontGL* getFontSansSerifSmallBold();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node);
|
|||
const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/";
|
||||
const std::string MACOSX_FONT_SUPPLEMENTAL = "Supplemental/";
|
||||
|
||||
LLFontDescriptor::char_functor_map_t LLFontDescriptor::mCharFunctors({
|
||||
{ "is_emoji", LLStringOps::isEmoji }
|
||||
});
|
||||
|
||||
LLFontDescriptor::LLFontDescriptor():
|
||||
mStyle(0)
|
||||
{
|
||||
|
|
@ -55,22 +59,22 @@ LLFontDescriptor::LLFontDescriptor():
|
|||
LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
||||
const std::string& size,
|
||||
const U8 style,
|
||||
const string_vec_t& file_names):
|
||||
const font_file_info_vec_t& font_files):
|
||||
mName(name),
|
||||
mSize(size),
|
||||
mStyle(style),
|
||||
mFileNames(file_names)
|
||||
mFontFiles(font_files)
|
||||
{
|
||||
}
|
||||
|
||||
LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
||||
const std::string& size,
|
||||
const U8 style,
|
||||
const string_vec_t& file_names,
|
||||
const string_vec_t& ft_collection_listections) :
|
||||
LLFontDescriptor(name, size, style, file_names)
|
||||
const font_file_info_vec_t& font_list,
|
||||
const font_file_info_vec_t& font_collection_files) :
|
||||
LLFontDescriptor(name, size, style, font_list)
|
||||
{
|
||||
mFontCollectionsList = ft_collection_listections;
|
||||
mFontCollectionFiles = font_collection_files;
|
||||
}
|
||||
|
||||
LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
||||
|
|
@ -82,7 +86,6 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
|
||||
{
|
||||
if (mName < b.mName)
|
||||
|
|
@ -175,7 +178,19 @@ LLFontDescriptor LLFontDescriptor::normalize() const
|
|||
if (removeSubString(new_name,"Italic"))
|
||||
new_style |= LLFontGL::ITALIC;
|
||||
|
||||
return LLFontDescriptor(new_name,new_size,new_style,getFileNames(),getFontCollectionsList());
|
||||
return LLFontDescriptor(new_name,new_size,new_style, getFontFiles(), getFontCollectionFiles());
|
||||
}
|
||||
|
||||
void LLFontDescriptor::addFontFile(const std::string& file_name, const std::string& char_functor)
|
||||
{
|
||||
char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
|
||||
mFontFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
|
||||
}
|
||||
|
||||
void LLFontDescriptor::addFontCollectionFile(const std::string& file_name, const std::string& char_functor)
|
||||
{
|
||||
char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
|
||||
mFontCollectionFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
|
||||
}
|
||||
|
||||
LLFontRegistry::LLFontRegistry(bool create_gl_textures)
|
||||
|
|
@ -273,17 +288,24 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
|
|||
if (child->hasName("file"))
|
||||
{
|
||||
std::string font_file_name = child->getTextContents();
|
||||
desc.getFileNames().push_back(font_file_name);
|
||||
|
||||
std::string char_functor;
|
||||
|
||||
if (child->hasAttribute("functor"))
|
||||
{
|
||||
child->getAttributeString("functor", char_functor);
|
||||
}
|
||||
|
||||
if (child->hasAttribute("load_collection"))
|
||||
{
|
||||
BOOL col = FALSE;
|
||||
child->getAttributeBOOL("load_collection", col);
|
||||
if (col)
|
||||
{
|
||||
desc.getFontCollectionsList().push_back(font_file_name);
|
||||
desc.addFontCollectionFile(font_file_name, char_functor);
|
||||
}
|
||||
}
|
||||
|
||||
desc.addFontFile(font_file_name, char_functor);
|
||||
}
|
||||
else if (child->hasName("os"))
|
||||
{
|
||||
|
|
@ -326,19 +348,19 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node)
|
|||
// A little roundabout because the map key is const,
|
||||
// so we have to fetch it, make a new map key, and
|
||||
// replace the old entry.
|
||||
string_vec_t match_file_names = match_desc->getFileNames();
|
||||
match_file_names.insert(match_file_names.begin(),
|
||||
desc.getFileNames().begin(),
|
||||
desc.getFileNames().end());
|
||||
font_file_info_vec_t font_files = match_desc->getFontFiles();
|
||||
font_files.insert(font_files.begin(),
|
||||
desc.getFontFiles().begin(),
|
||||
desc.getFontFiles().end());
|
||||
|
||||
string_vec_t collections_list = match_desc->getFontCollectionsList();
|
||||
collections_list.insert(collections_list.begin(),
|
||||
desc.getFontCollectionsList().begin(),
|
||||
desc.getFontCollectionsList().end());
|
||||
font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles();
|
||||
font_collection_files.insert(font_collection_files.begin(),
|
||||
desc.getFontCollectionFiles().begin(),
|
||||
desc.getFontCollectionFiles().end());
|
||||
|
||||
LLFontDescriptor new_desc = *match_desc;
|
||||
new_desc.getFileNames() = match_file_names;
|
||||
new_desc.getFontCollectionsList() = collections_list;
|
||||
new_desc.setFontFiles(font_files);
|
||||
new_desc.setFontCollectionFiles(font_collection_files);
|
||||
registry->mFontMap.erase(*match_desc);
|
||||
registry->mFontMap[new_desc] = NULL;
|
||||
}
|
||||
|
|
@ -423,82 +445,80 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
|
|||
|
||||
// Build list of font names to look for.
|
||||
// Files specified for this font come first, followed by those from the default descriptor.
|
||||
string_vec_t file_names = match_desc->getFileNames();
|
||||
string_vec_t ft_collection_list = match_desc->getFontCollectionsList();
|
||||
string_vec_t default_file_names;
|
||||
font_file_info_vec_t font_files = match_desc->getFontFiles();
|
||||
font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles();
|
||||
LLFontDescriptor default_desc("default",s_template_string,0);
|
||||
const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc);
|
||||
if (match_default_desc)
|
||||
{
|
||||
file_names.insert(file_names.end(),
|
||||
match_default_desc->getFileNames().begin(),
|
||||
match_default_desc->getFileNames().end());
|
||||
ft_collection_list.insert(ft_collection_list.end(),
|
||||
match_default_desc->getFontCollectionsList().begin(),
|
||||
match_default_desc->getFontCollectionsList().end());
|
||||
font_files.insert(font_files.end(),
|
||||
match_default_desc->getFontFiles().begin(),
|
||||
match_default_desc->getFontFiles().end());
|
||||
font_collection_files.insert(font_collection_files.end(),
|
||||
match_default_desc->getFontCollectionFiles().begin(),
|
||||
match_default_desc->getFontCollectionFiles().end());
|
||||
}
|
||||
|
||||
// Add ultimate fallback list - generated dynamically on linux,
|
||||
// null elsewhere.
|
||||
file_names.insert(file_names.end(),
|
||||
getUltimateFallbackList().begin(),
|
||||
getUltimateFallbackList().end());
|
||||
std::transform(getUltimateFallbackList().begin(), getUltimateFallbackList().end(), std::back_inserter(font_files),
|
||||
[](const std::string& file_name) { return LLFontFileInfo(file_name); });
|
||||
|
||||
// Load fonts based on names.
|
||||
if (file_names.empty())
|
||||
if (font_files.empty())
|
||||
{
|
||||
LL_WARNS() << "createFont failed, no file names specified" << LL_ENDL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLFontFreetype::font_vector_t fontlist;
|
||||
LLFontGL *result = NULL;
|
||||
|
||||
// Snarf all fonts we can into fontlist. First will get pulled
|
||||
// off the list and become the "head" font, set to non-fallback.
|
||||
// The first font will get pulled will be the "head" font, set to non-fallback.
|
||||
// Rest will consitute the fallback list.
|
||||
BOOL is_first_found = TRUE;
|
||||
|
||||
std::string local_path = LLFontGL::getFontPathLocal();
|
||||
std::string sys_path = LLFontGL::getFontPathSystem();
|
||||
|
||||
string_vec_t font_search_paths;
|
||||
font_search_paths.push_back(LLFontGL::getFontPathLocal());
|
||||
font_search_paths.push_back(LLFontGL::getFontPathSystem());
|
||||
#if LL_DARWIN
|
||||
font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY);
|
||||
font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL);
|
||||
font_search_paths.push_back(LLFontGL::getFontPathSystem() + MACOSX_FONT_SUPPLEMENTAL);
|
||||
#endif
|
||||
|
||||
// The fontname string may contain multiple font file names separated by semicolons.
|
||||
// Break it apart and try loading each one, in order.
|
||||
for(string_vec_t::iterator file_name_it = file_names.begin();
|
||||
file_name_it != file_names.end();
|
||||
++file_name_it)
|
||||
for(font_file_info_vec_t::iterator font_file_it = font_files.begin();
|
||||
font_file_it != font_files.end();
|
||||
++font_file_it)
|
||||
{
|
||||
LLFontGL *fontp = NULL;
|
||||
string_vec_t font_paths;
|
||||
font_paths.push_back(local_path + *file_name_it);
|
||||
font_paths.push_back(sys_path + *file_name_it);
|
||||
#if LL_DARWIN
|
||||
font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + *file_name_it);
|
||||
font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL + *file_name_it);
|
||||
font_paths.push_back(sys_path + MACOSX_FONT_SUPPLEMENTAL + *file_name_it);
|
||||
#endif
|
||||
|
||||
bool is_ft_collection = (std::find(ft_collection_list.begin(), ft_collection_list.end(), *file_name_it) != ft_collection_list.end());
|
||||
|
||||
bool is_ft_collection = (std::find_if(font_collection_files.begin(), font_collection_files.end(),
|
||||
[&font_file_it](const LLFontFileInfo& ffi) { return font_file_it->FileName == ffi.FileName; }) != font_collection_files.end());
|
||||
|
||||
// *HACK: Fallback fonts don't render, so we can use that to suppress
|
||||
// creation of OpenGL textures for test apps. JC
|
||||
BOOL is_fallback = !is_first_found || !mCreateGLTextures;
|
||||
F32 extra_scale = (is_fallback)?fallback_scale:1.0;
|
||||
F32 point_size_scale = extra_scale * point_size;
|
||||
bool is_font_loaded = false;
|
||||
for(string_vec_t::iterator font_paths_it = font_paths.begin();
|
||||
font_paths_it != font_paths.end();
|
||||
++font_paths_it)
|
||||
for(string_vec_t::iterator font_search_path_it = font_search_paths.begin();
|
||||
font_search_path_it != font_search_paths.end();
|
||||
++font_search_path_it)
|
||||
{
|
||||
const std::string font_path = *font_search_path_it + font_file_it->FileName;
|
||||
|
||||
fontp = new LLFontGL;
|
||||
S32 num_faces = is_ft_collection ? fontp->getNumFaces(*font_paths_it) : 1;
|
||||
S32 num_faces = is_ft_collection ? fontp->getNumFaces(font_path) : 1;
|
||||
for (S32 i = 0; i < num_faces; i++)
|
||||
{
|
||||
if (fontp == NULL)
|
||||
{
|
||||
fontp = new LLFontGL;
|
||||
}
|
||||
if (fontp->loadFace(*font_paths_it, point_size_scale,
|
||||
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback, i))
|
||||
if (fontp->loadFace(font_path, point_size_scale,
|
||||
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, is_fallback, i))
|
||||
{
|
||||
is_font_loaded = true;
|
||||
if (is_first_found)
|
||||
|
|
@ -508,7 +528,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
|
|||
}
|
||||
else
|
||||
{
|
||||
fontlist.push_back(fontp->mFontFreetype);
|
||||
result->mFontFreetype->addFallbackFont(fontp->mFontFreetype, font_file_it->CharFunctor);
|
||||
|
||||
delete fontp;
|
||||
fontp = NULL;
|
||||
}
|
||||
|
|
@ -523,17 +544,12 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
|
|||
}
|
||||
if(!is_font_loaded)
|
||||
{
|
||||
LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << LL_ENDL;
|
||||
LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << font_file_it->FileName << LL_ENDL;
|
||||
delete fontp;
|
||||
fontp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (result && !fontlist.empty())
|
||||
{
|
||||
result->mFontFreetype->setFallbackFonts(fontlist);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result->mFontDescriptor = desc;
|
||||
|
|
@ -720,11 +736,22 @@ void LLFontRegistry::dump()
|
|||
<< " size=[" << desc.getSize() << "]"
|
||||
<< " fileNames="
|
||||
<< LL_ENDL;
|
||||
for (string_vec_t::const_iterator file_it=desc.getFileNames().begin();
|
||||
file_it != desc.getFileNames().end();
|
||||
for (font_file_info_vec_t::const_iterator file_it=desc.getFontFiles().begin();
|
||||
file_it != desc.getFontFiles().end();
|
||||
++file_it)
|
||||
{
|
||||
LL_INFOS() << " file: " << *file_it <<LL_ENDL;
|
||||
LL_INFOS() << " file: " << file_it->FileName << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontRegistry::dumpTextures()
|
||||
{
|
||||
for (const auto& fontEntry : mFontMap)
|
||||
{
|
||||
if (fontEntry.second)
|
||||
{
|
||||
fontEntry.second->dumpTextures();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,32 @@ class LLFontGL;
|
|||
|
||||
typedef std::vector<std::string> string_vec_t;
|
||||
|
||||
struct LLFontFileInfo
|
||||
{
|
||||
LLFontFileInfo(const std::string& file_name, const std::function<bool(llwchar)>& char_functor = nullptr)
|
||||
: FileName(file_name)
|
||||
, CharFunctor(char_functor)
|
||||
{
|
||||
}
|
||||
|
||||
LLFontFileInfo(const LLFontFileInfo& ffi)
|
||||
: FileName(ffi.FileName)
|
||||
, CharFunctor(ffi.CharFunctor)
|
||||
{
|
||||
}
|
||||
|
||||
std::string FileName;
|
||||
std::function<bool(llwchar)> CharFunctor;
|
||||
};
|
||||
typedef std::vector<LLFontFileInfo> font_file_info_vec_t;
|
||||
|
||||
class LLFontDescriptor
|
||||
{
|
||||
public:
|
||||
LLFontDescriptor();
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names, const string_vec_t& font_collections);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list, const font_file_info_vec_t& font_collection_list);
|
||||
LLFontDescriptor normalize() const;
|
||||
|
||||
bool operator<(const LLFontDescriptor& b) const;
|
||||
|
|
@ -51,19 +70,26 @@ public:
|
|||
void setName(const std::string& name) { mName = name; }
|
||||
const std::string& getSize() const { return mSize; }
|
||||
void setSize(const std::string& size) { mSize = size; }
|
||||
const std::vector<std::string>& getFileNames() const { return mFileNames; }
|
||||
std::vector<std::string>& getFileNames() { return mFileNames; }
|
||||
const std::vector<std::string>& getFontCollectionsList() const { return mFontCollectionsList; }
|
||||
std::vector<std::string>& getFontCollectionsList() { return mFontCollectionsList; }
|
||||
|
||||
void addFontFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
|
||||
const font_file_info_vec_t & getFontFiles() const { return mFontFiles; }
|
||||
void setFontFiles(const font_file_info_vec_t& font_files) { mFontFiles = font_files; }
|
||||
void addFontCollectionFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
|
||||
const font_file_info_vec_t& getFontCollectionFiles() const { return mFontCollectionFiles; }
|
||||
void setFontCollectionFiles(const font_file_info_vec_t& font_collection_files) { mFontCollectionFiles = font_collection_files; }
|
||||
|
||||
const U8 getStyle() const { return mStyle; }
|
||||
void setStyle(U8 style) { mStyle = style; }
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mSize;
|
||||
string_vec_t mFileNames;
|
||||
string_vec_t mFontCollectionsList;
|
||||
font_file_info_vec_t mFontFiles;
|
||||
font_file_info_vec_t mFontCollectionFiles;
|
||||
U8 mStyle;
|
||||
|
||||
typedef std::map<std::string, std::function<bool(llwchar)>> char_functor_map_t;
|
||||
static char_functor_map_t mCharFunctors;
|
||||
};
|
||||
|
||||
class LLFontRegistry
|
||||
|
|
@ -94,6 +120,7 @@ public:
|
|||
bool nameToSize(const std::string& size_name, F32& size);
|
||||
|
||||
void dump();
|
||||
void dumpTextures();
|
||||
|
||||
const string_vec_t& getUltimateFallbackList() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -2890,7 +2890,7 @@ void LLGLSyncFence::wait()
|
|||
if (mSync)
|
||||
{
|
||||
while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
|
||||
{
|
||||
{ //track the number of times we've waited here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ set(llui_SOURCE_FILES
|
|||
lldockcontrol.cpp
|
||||
lldraghandle.cpp
|
||||
lleditmenuhandler.cpp
|
||||
llemojidictionary.cpp
|
||||
llemojihelper.cpp
|
||||
llf32uictrl.cpp
|
||||
llfiltereditor.cpp
|
||||
llflashtimer.cpp
|
||||
|
|
@ -139,6 +141,8 @@ set(llui_HEADER_FILES
|
|||
lldockablefloater.h
|
||||
lldockcontrol.h
|
||||
lleditmenuhandler.h
|
||||
llemojidictionary.h
|
||||
llemojihelper.h
|
||||
llf32uictrl.h
|
||||
llfiltereditor.h
|
||||
llflashtimer.h
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ LLButton::Params::Params()
|
|||
label_shadow("label_shadow", true),
|
||||
auto_resize("auto_resize", false),
|
||||
use_ellipses("use_ellipses", false),
|
||||
use_font_color("use_font_color", true),
|
||||
image_unselected("image_unselected"),
|
||||
image_selected("image_selected"),
|
||||
image_hover_selected("image_hover_selected"),
|
||||
|
|
@ -161,6 +162,7 @@ LLButton::LLButton(const LLButton::Params& p)
|
|||
mDropShadowedText(p.label_shadow),
|
||||
mAutoResize(p.auto_resize),
|
||||
mUseEllipses( p.use_ellipses ),
|
||||
mUseFontColor( p.use_font_color),
|
||||
mHAlign(p.font_halign),
|
||||
mLeftHPad(p.pad_left),
|
||||
mRightHPad(p.pad_right),
|
||||
|
|
@ -962,7 +964,7 @@ void LLButton::draw()
|
|||
LLFontGL::NORMAL,
|
||||
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
|
||||
S32_MAX, text_width,
|
||||
NULL, mUseEllipses);
|
||||
NULL, mUseEllipses, mUseFontColor);
|
||||
}
|
||||
|
||||
LLUICtrl::draw();
|
||||
|
|
@ -1022,6 +1024,16 @@ BOOL LLButton::toggleState()
|
|||
return flipped;
|
||||
}
|
||||
|
||||
void LLButton::setLabel( const std::string& label )
|
||||
{
|
||||
mUnselectedLabel = mSelectedLabel = label;
|
||||
}
|
||||
|
||||
void LLButton::setLabel( const LLUIString& label )
|
||||
{
|
||||
mUnselectedLabel = mSelectedLabel = label;
|
||||
}
|
||||
|
||||
void LLButton::setLabel( const LLStringExplicit& label )
|
||||
{
|
||||
setLabelUnselected(label);
|
||||
|
|
@ -1053,14 +1065,7 @@ bool LLButton::labelIsTruncated() const
|
|||
|
||||
const LLUIString& LLButton::getCurrentLabel() const
|
||||
{
|
||||
if( getToggleState() )
|
||||
{
|
||||
return mSelectedLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mUnselectedLabel;
|
||||
}
|
||||
return getToggleState() ? mSelectedLabel : mUnselectedLabel;
|
||||
}
|
||||
|
||||
void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public:
|
|||
Optional<bool> label_shadow;
|
||||
Optional<bool> auto_resize;
|
||||
Optional<bool> use_ellipses;
|
||||
Optional<bool> use_font_color;
|
||||
|
||||
// images
|
||||
Optional<LLUIImage*> image_unselected,
|
||||
|
|
@ -174,6 +175,7 @@ public:
|
|||
void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; }
|
||||
void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; }
|
||||
void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; }
|
||||
void setUseFontColor( BOOL use_font_color) { mUseFontColor = use_font_color; }
|
||||
|
||||
|
||||
boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb);
|
||||
|
|
@ -238,6 +240,8 @@ public:
|
|||
|
||||
void autoResize(); // resize with label of current btn state
|
||||
void resize(LLUIString label); // resize with label input
|
||||
void setLabel(const std::string& label);
|
||||
void setLabel(const LLUIString& label);
|
||||
void setLabel( const LLStringExplicit& label);
|
||||
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
|
||||
void setLabelUnselected(const LLStringExplicit& label);
|
||||
|
|
@ -353,6 +357,7 @@ protected:
|
|||
bool mDropShadowedText;
|
||||
bool mAutoResize;
|
||||
bool mUseEllipses;
|
||||
bool mUseFontColor;
|
||||
bool mBorderEnabled;
|
||||
bool mFlashing;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,469 @@
|
|||
/**
|
||||
* @file llemojidictionary.cpp
|
||||
* @brief Implementation of LLEmojiDictionary
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lldir.h"
|
||||
#include "llemojidictionary.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
//
|
||||
|
||||
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_SKIP("skip");
|
||||
// https://www.compart.com/en/unicode/U+1F302
|
||||
static const S32 GROUP_OTHERS_IMAGE_INDEX = 0x1F302;
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
template<class T>
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected:
|
||||
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) {}
|
||||
|
||||
bool operator()(const LLEmojiDescriptor& descr) const
|
||||
{
|
||||
for (const auto& short_code : descr.ShortCodes)
|
||||
{
|
||||
if (boost::icontains(short_code, mNeedle))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (boost::icontains(descr.Category, mNeedle))
|
||||
return true;
|
||||
|
||||
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
|
||||
//
|
||||
|
||||
LLEmojiDictionary::LLEmojiDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
void LLEmojiDictionary::initClass()
|
||||
{
|
||||
LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLEmojiDictionary::searchInShortCode(std::size_t& begin, std::size_t& end, const std::string& shortCode, const std::string& needle)
|
||||
{
|
||||
begin = 0;
|
||||
end = 1;
|
||||
std::size_t index = 1;
|
||||
// Search for begin
|
||||
char d = tolower(needle[index++]);
|
||||
while (end < shortCode.size())
|
||||
{
|
||||
char s = tolower(shortCode[end++]);
|
||||
if (s == d)
|
||||
{
|
||||
begin = end - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!begin)
|
||||
return false;
|
||||
// Search for end
|
||||
d = tolower(needle[index++]);
|
||||
if (!d)
|
||||
return true;
|
||||
while (end < shortCode.size() && index <= needle.size())
|
||||
{
|
||||
char s = tolower(shortCode[end++]);
|
||||
if (s == d)
|
||||
{
|
||||
if (index == needle.size())
|
||||
return true;
|
||||
d = tolower(needle[index++]);
|
||||
continue;
|
||||
}
|
||||
switch (s)
|
||||
{
|
||||
case L'-':
|
||||
case L'_':
|
||||
case L'+':
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::findByShortCode(
|
||||
std::vector<LLEmojiSearchResult>& result,
|
||||
const std::string& needle
|
||||
) const
|
||||
{
|
||||
result.clear();
|
||||
|
||||
if (needle.empty() || needle.front() != ':')
|
||||
return;
|
||||
|
||||
std::map<llwchar, std::vector<LLEmojiSearchResult>> results;
|
||||
|
||||
for (const LLEmojiDescriptor& d : mEmojis)
|
||||
{
|
||||
if (!d.ShortCodes.empty())
|
||||
{
|
||||
const std::string& shortCode = d.ShortCodes.front();
|
||||
if (shortCode.size() >= needle.size() && shortCode.front() == needle.front())
|
||||
{
|
||||
std::size_t begin, end;
|
||||
if (searchInShortCode(begin, end, shortCode, needle))
|
||||
{
|
||||
results[begin].emplace_back(d.Character, shortCode, begin, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& it : results)
|
||||
{
|
||||
#ifdef __cpp_lib_containers_ranges
|
||||
result.append_range(it.second);
|
||||
#else
|
||||
result.insert(result.end(), it.second.cbegin(), it.second.cend());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::loadTranslations()
|
||||
{
|
||||
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();
|
||||
|
||||
// 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_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 = GROUP_OTHERS_IMAGE_INDEX;
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
std::list<std::string> LLEmojiDictionary::loadCategories(const LLSD& sd)
|
||||
{
|
||||
static const std::string key("Categories");
|
||||
return llsd_array_to_list<std::string>(sd[key]);
|
||||
}
|
||||
|
||||
std::list<std::string> LLEmojiDictionary::loadShortCodes(const LLSD& sd)
|
||||
{
|
||||
static const std::string key("ShortCodes");
|
||||
auto toLower = [](std::string& str) { LLStringUtil::toLower(str); };
|
||||
return llsd_array_to_list<std::string>(sd[key], toLower);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* @file llemojidictionary.h
|
||||
* @brief Header file for LLEmojiDictionary
|
||||
*
|
||||
* $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 "lldictionary.h"
|
||||
#include "llinitdestroyclass.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiDescriptor class
|
||||
//
|
||||
|
||||
struct LLEmojiDescriptor
|
||||
{
|
||||
llwchar Character;
|
||||
std::string Category;
|
||||
std::list<std::string> ShortCodes;
|
||||
std::string getShortCodes() const;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiGroup class
|
||||
//
|
||||
|
||||
struct LLEmojiGroup
|
||||
{
|
||||
llwchar Character;
|
||||
std::list<std::string> Categories;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiSearchResult class
|
||||
//
|
||||
|
||||
struct LLEmojiSearchResult
|
||||
{
|
||||
llwchar Character;
|
||||
std::string String;
|
||||
std::size_t Begin, End;
|
||||
|
||||
LLEmojiSearchResult(llwchar character, const std::string& string, std::size_t begin, std::size_t end)
|
||||
: Character(character)
|
||||
, String(string)
|
||||
, Begin(begin)
|
||||
, End(end)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiDictionary class
|
||||
//
|
||||
|
||||
class LLEmojiDictionary : public LLParamSingleton<LLEmojiDictionary>, public LLInitClass<LLEmojiDictionary>
|
||||
{
|
||||
LLSINGLETON(LLEmojiDictionary);
|
||||
~LLEmojiDictionary() override {};
|
||||
|
||||
public:
|
||||
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;
|
||||
static bool searchInShortCode(std::size_t& begin, std::size_t& end, const std::string& shortCode, const std::string& needle);
|
||||
void findByShortCode(std::vector<LLEmojiSearchResult>& result, 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 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 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::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;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* @file llemojihelper.h
|
||||
* @brief Header file for LLEmojiHelper
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llemojidictionary.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "llfloater.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "lluictrl.h"
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
//
|
||||
|
||||
constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_picker";
|
||||
constexpr S32 HELPER_FLOATER_OFFSET_X = 0;
|
||||
constexpr S32 HELPER_FLOATER_OFFSET_Y = 0;
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiHelper
|
||||
//
|
||||
|
||||
std::string LLEmojiHelper::getToolTip(llwchar ch) const
|
||||
{
|
||||
return LLEmojiDictionary::instance().getNameFromEmoji(ch);
|
||||
}
|
||||
|
||||
bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const
|
||||
{
|
||||
return mHostHandle.get() == ctrl_p;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos)
|
||||
{
|
||||
// If the cursor is currently on a colon start the check one character further back
|
||||
S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1;
|
||||
|
||||
auto isPartOfShortcode = [](llwchar ch) {
|
||||
switch (ch)
|
||||
{
|
||||
case L'-':
|
||||
case L'_':
|
||||
case L'+':
|
||||
return true;
|
||||
default:
|
||||
return LLStringOps::isAlnum(ch);
|
||||
}
|
||||
};
|
||||
while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1]))
|
||||
{
|
||||
shortCodePos--;
|
||||
}
|
||||
|
||||
bool isShortCode = (L':' == wtext[shortCodePos - 1]) && (cursorPos - shortCodePos >= 2);
|
||||
if (pShortCodePos)
|
||||
*pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1;
|
||||
return isShortCode;
|
||||
}
|
||||
|
||||
void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> cb)
|
||||
{
|
||||
// Commit immediately if the user already typed a full shortcode
|
||||
if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code))
|
||||
{
|
||||
cb(emojiDescrp->Character);
|
||||
hideHelper();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHelperHandle.isDead())
|
||||
{
|
||||
LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER);
|
||||
mHelperHandle = pHelperFloater->getHandle();
|
||||
mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2));
|
||||
}
|
||||
setHostCtrl(hostctrl_p);
|
||||
mEmojiCommitCb = cb;
|
||||
|
||||
S32 floater_x, floater_y;
|
||||
if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))
|
||||
{
|
||||
LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater* pHelperFloater = mHelperHandle.get();
|
||||
LLRect rect = pHelperFloater->getRect();
|
||||
S32 left = floater_x - HELPER_FLOATER_OFFSET_X;
|
||||
S32 top = floater_y - HELPER_FLOATER_OFFSET_Y + rect.getHeight();
|
||||
rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight());
|
||||
pHelperFloater->setRect(rect);
|
||||
pHelperFloater->openFloater(LLSD().with("hint", short_code));
|
||||
}
|
||||
|
||||
void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p, bool strict)
|
||||
{
|
||||
mIsHideDisabled &= !strict;
|
||||
if (mIsHideDisabled || (ctrl_p && !isActive(ctrl_p)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setHostCtrl(nullptr);
|
||||
}
|
||||
|
||||
bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask)
|
||||
{
|
||||
if (mHelperHandle.isDead() || !isActive(ctrl_p))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mHelperHandle.get()->handleKey(key, mask, true);
|
||||
}
|
||||
|
||||
void LLEmojiHelper::onCommitEmoji(llwchar emoji)
|
||||
{
|
||||
if (!mHostHandle.isDead() && mEmojiCommitCb)
|
||||
{
|
||||
mEmojiCommitCb(emoji);
|
||||
}
|
||||
}
|
||||
|
||||
void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p)
|
||||
{
|
||||
const LLUICtrl* pCurHostCtrl = mHostHandle.get();
|
||||
if (pCurHostCtrl != hostctrl_p)
|
||||
{
|
||||
mHostCtrlFocusLostConn.disconnect();
|
||||
mHostHandle.markDead();
|
||||
mEmojiCommitCb = {};
|
||||
|
||||
if (!mHelperHandle.isDead())
|
||||
{
|
||||
mHelperHandle.get()->closeFloater();
|
||||
}
|
||||
|
||||
if (hostctrl_p)
|
||||
{
|
||||
mHostHandle = hostctrl_p->getHandle();
|
||||
mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* @file llemojihelper.h
|
||||
* @brief Header file for LLEmojiHelper
|
||||
*
|
||||
* $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 "llhandle.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLFloater;
|
||||
class LLUICtrl;
|
||||
|
||||
class LLEmojiHelper : public LLSingleton<LLEmojiHelper>
|
||||
{
|
||||
LLSINGLETON(LLEmojiHelper) {}
|
||||
~LLEmojiHelper() override {}
|
||||
|
||||
public:
|
||||
// General
|
||||
std::string getToolTip(llwchar ch) const;
|
||||
bool isActive(const LLUICtrl* ctrl_p) const;
|
||||
static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr);
|
||||
void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> commit_cb);
|
||||
void hideHelper(const LLUICtrl* ctrl_p = nullptr, bool strict = false);
|
||||
void setIsHideDisabled(bool disabled) { mIsHideDisabled = disabled; };
|
||||
|
||||
// Eventing
|
||||
bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask);
|
||||
void onCommitEmoji(llwchar emoji);
|
||||
|
||||
protected:
|
||||
LLUICtrl* getHostCtrl() const { return mHostHandle.get(); }
|
||||
void setHostCtrl(LLUICtrl* hostctrl_p);
|
||||
|
||||
private:
|
||||
LLHandle<LLUICtrl> mHostHandle;
|
||||
LLHandle<LLFloater> mHelperHandle;
|
||||
boost::signals2::connection mHostCtrlFocusLostConn;
|
||||
boost::signals2::connection mHelperCommitConn;
|
||||
std::function<void(llwchar)> mEmojiCommitCb;
|
||||
bool mIsHideDisabled;
|
||||
};
|
||||
|
|
@ -182,6 +182,7 @@ LLFloater::Params::Params()
|
|||
save_visibility("save_visibility", false),
|
||||
can_dock("can_dock", false),
|
||||
show_title("show_title", true),
|
||||
auto_close("auto_close", false),
|
||||
positioning("positioning", LLFloaterEnums::POSITIONING_RELATIVE),
|
||||
header_height("header_height", 0),
|
||||
legacy_header_height("legacy_header_height", 0),
|
||||
|
|
@ -254,6 +255,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
|
|||
mCanClose(p.can_close),
|
||||
mDragOnLeft(p.can_drag_on_left),
|
||||
mResizable(p.can_resize),
|
||||
mAutoClose(p.auto_close),
|
||||
mPositioning(p.positioning),
|
||||
mMinWidth(p.min_width),
|
||||
mMinHeight(p.min_height),
|
||||
|
|
@ -504,6 +506,7 @@ void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)
|
|||
|
||||
void LLFloater::destroy()
|
||||
{
|
||||
gFloaterView->onDestroyFloater(this);
|
||||
// LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before
|
||||
// it was deleted via LLMortician::updateClass(). See EXT-8458.
|
||||
LLFloaterReg::removeInstance(mInstanceName, mKey);
|
||||
|
|
@ -681,7 +684,7 @@ void LLFloater::openFloater(const LLSD& key)
|
|||
if (getHost() != NULL)
|
||||
{
|
||||
getHost()->setMinimized(FALSE);
|
||||
getHost()->setVisibleAndFrontmost(mAutoFocus);
|
||||
getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
|
||||
getHost()->showFloater(this);
|
||||
}
|
||||
else
|
||||
|
|
@ -693,7 +696,7 @@ void LLFloater::openFloater(const LLSD& key)
|
|||
}
|
||||
applyControlsAndPosition(floater_to_stack);
|
||||
setMinimized(FALSE);
|
||||
setVisibleAndFrontmost(mAutoFocus);
|
||||
setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
|
||||
}
|
||||
|
||||
mOpenSignal(this, key);
|
||||
|
|
@ -829,6 +832,24 @@ void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)
|
|||
LLPanel::reshape(width, height, called_from_parent);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloater::translate(S32 x, S32 y)
|
||||
{
|
||||
LLView::translate(x, y);
|
||||
|
||||
if (!mTranslateWithDependents || mDependents.empty())
|
||||
return;
|
||||
|
||||
for (const LLHandle<LLFloater>& handle : mDependents)
|
||||
{
|
||||
LLFloater* floater = handle.get();
|
||||
if (floater && floater->getSnapTarget() == getHandle())
|
||||
{
|
||||
floater->LLView::translate(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloater::releaseFocus()
|
||||
{
|
||||
LLUI::getInstance()->removePopup(this);
|
||||
|
|
@ -1117,9 +1138,9 @@ BOOL LLFloater::canSnapTo(const LLView* other_view)
|
|||
|
||||
if (other_view != getParent())
|
||||
{
|
||||
const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view);
|
||||
if (other_floaterp
|
||||
&& other_floaterp->getSnapTarget() == getHandle()
|
||||
const LLFloater* other_floaterp = dynamic_cast<const LLFloater*>(other_view);
|
||||
if (other_floaterp
|
||||
&& other_floaterp->getSnapTarget() == getHandle()
|
||||
&& mDependents.find(other_floaterp->getHandle()) != mDependents.end())
|
||||
{
|
||||
// this is a dependent that is already snapped to us, so don't snap back to it
|
||||
|
|
@ -1509,30 +1530,40 @@ BOOL LLFloater::isFrontmost()
|
|||
&& floater_view->getFrontmost() == this);
|
||||
}
|
||||
|
||||
void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)
|
||||
void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition, BOOL resize)
|
||||
{
|
||||
mDependents.insert(floaterp->getHandle());
|
||||
floaterp->mDependeeHandle = getHandle();
|
||||
|
||||
if (reposition)
|
||||
{
|
||||
floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
|
||||
LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp);
|
||||
if (resize)
|
||||
{
|
||||
const LLRect& base = getRect();
|
||||
if (rect.mTop == base.mTop)
|
||||
rect.mBottom = base.mBottom;
|
||||
else if (rect.mLeft == base.mLeft)
|
||||
rect.mRight = base.mRight;
|
||||
floaterp->reshape(rect.getWidth(), rect.getHeight(), FALSE);
|
||||
}
|
||||
floaterp->setRect(rect);
|
||||
floaterp->setSnapTarget(getHandle());
|
||||
}
|
||||
gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE);
|
||||
if (floaterp->isFrontmost())
|
||||
{
|
||||
// make sure to bring self and sibling floaters to front
|
||||
gFloaterView->bringToFront(floaterp);
|
||||
gFloaterView->bringToFront(floaterp, floaterp->getAutoFocus() && !getIsChrome());
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition)
|
||||
void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition, BOOL resize)
|
||||
{
|
||||
LLFloater* dependent_floaterp = dependent.get();
|
||||
if(dependent_floaterp)
|
||||
{
|
||||
addDependentFloater(dependent_floaterp, reposition);
|
||||
addDependentFloater(dependent_floaterp, reposition, resize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1542,6 +1573,44 @@ void LLFloater::removeDependentFloater(LLFloater* floaterp)
|
|||
floaterp->mDependeeHandle = LLHandle<LLFloater>();
|
||||
}
|
||||
|
||||
void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels)
|
||||
{
|
||||
LLRect total_rect = getRect();
|
||||
|
||||
for (const LLHandle<LLFloater>& handle : mDependents)
|
||||
{
|
||||
LLFloater* floater = handle.get();
|
||||
if (floater && floater->getSnapTarget() == getHandle())
|
||||
{
|
||||
total_rect.unionWith(floater->getRect());
|
||||
}
|
||||
}
|
||||
|
||||
S32 delta_left = left.notEmpty() ? left.mRight - total_rect.mRight : 0;
|
||||
S32 delta_bottom = bottom.notEmpty() ? bottom.mTop - total_rect.mTop : 0;
|
||||
S32 delta_right = right.notEmpty() ? right.mLeft - total_rect.mLeft : 0;
|
||||
|
||||
// move floater with dependings fully onscreen
|
||||
mTranslateWithDependents = true;
|
||||
if (translateRectIntoRect(total_rect, constraint, min_overlap_pixels))
|
||||
{
|
||||
clearSnapTarget();
|
||||
}
|
||||
else if (delta_left > 0 && total_rect.mTop < left.mTop && total_rect.mBottom > left.mBottom)
|
||||
{
|
||||
translate(delta_left, 0);
|
||||
}
|
||||
else if (delta_bottom > 0 && total_rect.mLeft > bottom.mLeft && total_rect.mRight < bottom.mRight)
|
||||
{
|
||||
translate(0, delta_bottom);
|
||||
}
|
||||
else if (delta_right < 0 && total_rect.mTop < right.mTop && total_rect.mBottom > right.mBottom)
|
||||
{
|
||||
translate(delta_right, 0);
|
||||
}
|
||||
mTranslateWithDependents = false;
|
||||
}
|
||||
|
||||
BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index)
|
||||
{
|
||||
if( mButtonsEnabled[index] )
|
||||
|
|
@ -1630,6 +1699,7 @@ BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
|
|||
return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloater::bringToFront( S32 x, S32 y )
|
||||
{
|
||||
if (getVisible() && pointInView(x, y))
|
||||
|
|
@ -1644,12 +1714,20 @@ void LLFloater::bringToFront( S32 x, S32 y )
|
|||
LLFloaterView* parent = dynamic_cast<LLFloaterView*>( getParent() );
|
||||
if (parent)
|
||||
{
|
||||
parent->bringToFront( this );
|
||||
parent->bringToFront(this, !getIsChrome());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloater::goneFromFront()
|
||||
{
|
||||
if (mAutoClose)
|
||||
{
|
||||
closeFloater();
|
||||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key)
|
||||
|
|
@ -2487,13 +2565,18 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore
|
|||
|
||||
if (mFrontChild == child)
|
||||
{
|
||||
if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
|
||||
if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))
|
||||
{
|
||||
child->setFocus(TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFrontChild)
|
||||
{
|
||||
mFrontChild->goneFromFront();
|
||||
}
|
||||
|
||||
mFrontChild = child;
|
||||
|
||||
// *TODO: make this respect floater's mAutoFocus value, instead of
|
||||
|
|
@ -2851,10 +2934,17 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
|
|||
// floater is hosted elsewhere, so ignore
|
||||
return;
|
||||
}
|
||||
|
||||
if (floater->getDependee() &&
|
||||
floater->getDependee() == floater->getSnapTarget().get())
|
||||
{
|
||||
// floater depends on other and snaps to it, so ignore
|
||||
return;
|
||||
}
|
||||
|
||||
LLRect::tCoordType screen_width = getSnapRect().getWidth();
|
||||
LLRect::tCoordType screen_height = getSnapRect().getHeight();
|
||||
|
||||
|
||||
// only automatically resize non-minimized, resizable floaters
|
||||
if( floater->isResizable() && !floater->isMinimized() )
|
||||
{
|
||||
|
|
@ -2896,29 +2986,10 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
|
|||
}
|
||||
}
|
||||
|
||||
const LLRect& floater_rect = floater->getRect();
|
||||
const LLRect& constraint = snap_in_toolbars ? getSnapRect() : gFloaterView->getRect();
|
||||
S32 min_overlap_pixels = allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX;
|
||||
|
||||
S32 delta_left = mToolbarLeftRect.notEmpty() ? mToolbarLeftRect.mRight - floater_rect.mRight : 0;
|
||||
S32 delta_bottom = mToolbarBottomRect.notEmpty() ? mToolbarBottomRect.mTop - floater_rect.mTop : 0;
|
||||
S32 delta_right = mToolbarRightRect.notEmpty() ? mToolbarRightRect.mLeft - floater_rect.mLeft : 0;
|
||||
|
||||
// move window fully onscreen
|
||||
if (floater->translateIntoRect( snap_in_toolbars ? getSnapRect() : gFloaterView->getRect(), allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX ))
|
||||
{
|
||||
floater->clearSnapTarget();
|
||||
}
|
||||
else if (delta_left > 0 && floater_rect.mTop < mToolbarLeftRect.mTop && floater_rect.mBottom > mToolbarLeftRect.mBottom)
|
||||
{
|
||||
floater->translate(delta_left, 0);
|
||||
}
|
||||
else if (delta_bottom > 0 && floater_rect.mLeft > mToolbarBottomRect.mLeft && floater_rect.mRight < mToolbarBottomRect.mRight)
|
||||
{
|
||||
floater->translate(0, delta_bottom);
|
||||
}
|
||||
else if (delta_right < 0 && floater_rect.mTop < mToolbarRightRect.mTop && floater_rect.mBottom > mToolbarRightRect.mBottom)
|
||||
{
|
||||
floater->translate(delta_right, 0);
|
||||
}
|
||||
floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels);
|
||||
}
|
||||
|
||||
void LLFloaterView::draw()
|
||||
|
|
@ -3005,6 +3076,9 @@ LLFloater *LLFloaterView::getBackmost() const
|
|||
|
||||
void LLFloaterView::syncFloaterTabOrder()
|
||||
{
|
||||
if (mFrontChild && !mFrontChild->isDead() && mFrontChild->getIsChrome())
|
||||
return;
|
||||
|
||||
// look for a visible modal dialog, starting from first
|
||||
LLModalDialog* modal_dialog = NULL;
|
||||
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
|
||||
|
|
@ -3040,7 +3114,34 @@ void LLFloaterView::syncFloaterTabOrder()
|
|||
LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);
|
||||
if (gFocusMgr.childHasKeyboardFocus(floaterp))
|
||||
{
|
||||
bringToFront(floaterp, FALSE);
|
||||
if (mFrontChild != floaterp)
|
||||
{
|
||||
// Grab a list of the top floaters that want to stay on top of the focused floater
|
||||
std::list<LLFloater*> listTop;
|
||||
if (mFrontChild && !mFrontChild->canFocusStealFrontmost())
|
||||
{
|
||||
for (LLView* childp : *getChildList())
|
||||
{
|
||||
LLFloater* child_floaterp = static_cast<LLFloater*>(childp);
|
||||
if (child_floaterp->canFocusStealFrontmost())
|
||||
break;
|
||||
listTop.push_back(child_floaterp);
|
||||
}
|
||||
}
|
||||
|
||||
bringToFront(floaterp, FALSE);
|
||||
|
||||
// Restore top floaters
|
||||
if (!listTop.empty())
|
||||
{
|
||||
for (LLView* childp : listTop)
|
||||
{
|
||||
sendChildToFront(childp);
|
||||
}
|
||||
mFrontChild = listTop.back();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3133,6 +3234,14 @@ void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LL
|
|||
}
|
||||
}
|
||||
|
||||
void LLFloaterView::onDestroyFloater(LLFloater* floater)
|
||||
{
|
||||
if (mFrontChild == floater)
|
||||
{
|
||||
mFrontChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloater::setInstanceName(const std::string& name)
|
||||
{
|
||||
if (name != mInstanceName)
|
||||
|
|
@ -3225,6 +3334,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
|
|||
mDefaultRelativeY = p.rel_y;
|
||||
|
||||
mPositioning = p.positioning;
|
||||
mAutoClose = p.auto_close;
|
||||
|
||||
mSaveRect = p.save_rect;
|
||||
if (p.save_visibility)
|
||||
|
|
|
|||
|
|
@ -117,8 +117,6 @@ struct LLCoordFloater : LLCoord<LL_COORD_FLOATER>
|
|||
bool operator!=(const LLCoordFloater& other) const { return !(*this == other); }
|
||||
|
||||
void setFloater(LLFloater& floater);
|
||||
|
||||
|
||||
};
|
||||
|
||||
class LLFloater : public LLPanel, public LLInstanceTracker<LLFloater>
|
||||
|
|
@ -169,7 +167,8 @@ public:
|
|||
save_visibility,
|
||||
save_dock_state,
|
||||
can_dock,
|
||||
show_title;
|
||||
show_title,
|
||||
auto_close;
|
||||
|
||||
Optional<LLFloaterEnums::EOpenPositioning> positioning;
|
||||
|
||||
|
|
@ -242,6 +241,7 @@ public:
|
|||
virtual void closeHostedFloater();
|
||||
|
||||
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
/*virtual*/ void translate(S32 x, S32 y);
|
||||
|
||||
// Release keyboard and mouse focus
|
||||
void releaseFocus();
|
||||
|
|
@ -260,10 +260,11 @@ public:
|
|||
std::string getShortTitle() const;
|
||||
virtual void setMinimized(BOOL b);
|
||||
void moveResizeHandlesToFront();
|
||||
void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE);
|
||||
void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE);
|
||||
void addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE);
|
||||
void addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE);
|
||||
LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); }
|
||||
void removeDependentFloater(LLFloater* dependent);
|
||||
void removeDependentFloater(LLFloater* dependent);
|
||||
void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels);
|
||||
BOOL isMinimized() const { return mMinimized; }
|
||||
/// isShown() differs from getVisible() in that isShown() also considers
|
||||
/// isMinimized(). isShown() is true only if visible and not minimized.
|
||||
|
|
@ -318,6 +319,9 @@ public:
|
|||
/*virtual*/ void setVisible(BOOL visible); // do not override
|
||||
/*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override
|
||||
|
||||
bool canFocusStealFrontmost() const { return mFocusStealsFrontmost; }
|
||||
void setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; }
|
||||
|
||||
void setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE);
|
||||
virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
|
||||
|
||||
|
|
@ -391,6 +395,7 @@ protected:
|
|||
void setInstanceName(const std::string& name);
|
||||
|
||||
virtual void bringToFront(S32 x, S32 y);
|
||||
virtual void goneFromFront();
|
||||
|
||||
void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized
|
||||
const LLRect& getExpandedRect() const { return mExpandedRect; }
|
||||
|
|
@ -486,8 +491,10 @@ private:
|
|||
BOOL mCanTearOff;
|
||||
BOOL mCanMinimize;
|
||||
BOOL mCanClose;
|
||||
bool mFocusStealsFrontmost = true; // FALSE if we don't want the currently focused floater to cover this floater without user interaction
|
||||
BOOL mDragOnLeft;
|
||||
BOOL mResizable;
|
||||
BOOL mAutoClose;
|
||||
|
||||
LLFloaterEnums::EOpenPositioning mPositioning;
|
||||
LLCoordFloater mPosition;
|
||||
|
|
@ -507,6 +514,7 @@ private:
|
|||
typedef std::set<LLHandle<LLFloater> > handle_set_t;
|
||||
typedef std::set<LLHandle<LLFloater> >::iterator handle_set_iter_t;
|
||||
handle_set_t mDependents;
|
||||
bool mTranslateWithDependents { false };
|
||||
|
||||
bool mButtonsEnabled[BUTTON_COUNT];
|
||||
F32 mButtonScale;
|
||||
|
|
@ -603,6 +611,7 @@ public:
|
|||
LLFloater* getFrontmostClosableFloater();
|
||||
|
||||
void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect);
|
||||
void onDestroyFloater(LLFloater* floater);
|
||||
|
||||
private:
|
||||
void hiddenFloaterClosed(LLFloater* floater);
|
||||
|
|
|
|||
|
|
@ -888,7 +888,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y
|
|||
//
|
||||
font->renderUTF8(mLabel, 0, x, y, color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, TRUE);
|
||||
S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/TRUE);
|
||||
}
|
||||
|
||||
void LLFolderViewItem::draw()
|
||||
|
|
@ -997,7 +997,7 @@ void LLFolderViewItem::draw()
|
|||
{
|
||||
suffix_font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE );
|
||||
S32_MAX, S32_MAX, &right_x);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------//
|
||||
|
|
@ -1009,9 +1009,9 @@ void LLFolderViewItem::draw()
|
|||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
filter_string_length, S32_MAX, &right_x, FALSE );
|
||||
font->renderUTF8(combined_string, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
filter_string_length, S32_MAX, &right_x);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1020,8 +1020,9 @@ void LLFolderViewItem::draw()
|
|||
{
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, filter_offset + label_filter_length) - font->getWidthF32(mLabel, filter_offset, label_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( mLabel, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, label_filter_length, S32_MAX, &right_x, FALSE );
|
||||
font->renderUTF8(mLabel, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
label_filter_length, S32_MAX, &right_x);
|
||||
}
|
||||
|
||||
S32 suffix_filter_length = label_filter_length > 0 ? filter_string_length - label_filter_length : filter_string_length;
|
||||
|
|
@ -1030,7 +1031,9 @@ void LLFolderViewItem::draw()
|
|||
S32 suffix_offset = llmax(0, filter_offset - (S32)mLabel.size());
|
||||
F32 match_string_left = text_left + font->getWidthF32(mLabel, 0, mLabel.size()) + suffix_font->getWidthF32(mLabelSuffix, 0, suffix_offset + suffix_filter_length) - suffix_font->getWidthF32(mLabelSuffix, suffix_offset, suffix_filter_length);
|
||||
F32 yy = (F32)getRect().getHeight() - suffix_font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
suffix_font->renderUTF8( mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, suffix_filter_length, S32_MAX, &right_x, FALSE );
|
||||
suffix_font->renderUTF8(mLabelSuffix, suffix_offset, match_string_left, yy, sFilterTextColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
suffix_filter_length, S32_MAX, &right_x);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ LLLineEditor::Params::Params()
|
|||
background_image_disabled("background_image_disabled"),
|
||||
background_image_focused("background_image_focused"),
|
||||
bg_image_always_focused("bg_image_always_focused", false),
|
||||
show_label_focused("show_label_focused", false),
|
||||
select_on_focus("select_on_focus", false),
|
||||
revert_on_esc("revert_on_esc", true),
|
||||
spellcheck("spellcheck", false),
|
||||
|
|
@ -154,6 +155,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
|
|||
mBgImageDisabled( p.background_image_disabled ),
|
||||
mBgImageFocused( p.background_image_focused ),
|
||||
mShowImageFocused( p.bg_image_always_focused ),
|
||||
mShowLabelFocused( p.show_label_focused ),
|
||||
mUseBgColor(p.use_bg_color),
|
||||
mHaveHistory(FALSE),
|
||||
mReplaceNewlinesWithSpaces( TRUE ),
|
||||
|
|
@ -1759,6 +1761,20 @@ void LLLineEditor::drawBackground()
|
|||
}
|
||||
}
|
||||
|
||||
//virtual
|
||||
const std::string LLLineEditor::getToolTip() const
|
||||
{
|
||||
if (sDebugUnicode)
|
||||
{
|
||||
std::string text = getText();
|
||||
std::string tooltip = utf8str_showBytesUTF8(text);
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
return LLUICtrl::getToolTip();
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLLineEditor::draw()
|
||||
{
|
||||
F32 alpha = getDrawContext().mAlpha;
|
||||
|
|
@ -2091,7 +2107,7 @@ void LLLineEditor::draw()
|
|||
//draw label if no text is provided
|
||||
//but we should draw it in a different color
|
||||
//to give indication that it is not text you typed in
|
||||
if (0 == mText.length() && mReadOnly)
|
||||
if (0 == mText.length() && (mReadOnly || mShowLabelFocused))
|
||||
{
|
||||
mGLFont->render(mLabel.getWString(), 0,
|
||||
mTextLeftEdge, (F32)text_bottom,
|
||||
|
|
@ -2127,7 +2143,7 @@ void LLLineEditor::draw()
|
|||
LLFontGL::NO_SHADOW,
|
||||
S32_MAX,
|
||||
mTextRightEdge - ll_round(rendered_pixels_right),
|
||||
&rendered_pixels_right, FALSE);
|
||||
&rendered_pixels_right);
|
||||
}
|
||||
// Draw children (border)
|
||||
LLView::draw();
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ public:
|
|||
commit_on_focus_lost,
|
||||
ignore_tab,
|
||||
bg_image_always_focused,
|
||||
show_label_focused,
|
||||
is_password,
|
||||
allow_emoji,
|
||||
use_bg_color;
|
||||
|
|
@ -119,54 +120,55 @@ protected:
|
|||
friend class LLUICtrlFactory;
|
||||
friend class LLFloaterEditUI;
|
||||
void showContextMenu(S32 x, S32 y);
|
||||
|
||||
public:
|
||||
virtual ~LLLineEditor();
|
||||
|
||||
// mousehandler overrides
|
||||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask);
|
||||
/*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask);
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
|
||||
/*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char);
|
||||
/*virtual*/ void onMouseCaptureLost();
|
||||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask) override;
|
||||
/*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask) override;
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask) override;
|
||||
/*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char) override;
|
||||
/*virtual*/ void onMouseCaptureLost() override;
|
||||
|
||||
// LLEditMenuHandler overrides
|
||||
virtual void cut();
|
||||
virtual BOOL canCut() const;
|
||||
virtual void copy();
|
||||
virtual BOOL canCopy() const;
|
||||
virtual void paste();
|
||||
virtual BOOL canPaste() const;
|
||||
/*virtual*/ void cut() override;
|
||||
/*virtual*/ BOOL canCut() const override;
|
||||
/*virtual*/ void copy() override;
|
||||
/*virtual*/ BOOL canCopy() const override;
|
||||
/*virtual*/ void paste() override;
|
||||
/*virtual*/ BOOL canPaste() const override;
|
||||
|
||||
virtual void updatePrimary();
|
||||
virtual void copyPrimary();
|
||||
virtual void pastePrimary();
|
||||
virtual BOOL canPastePrimary() const;
|
||||
|
||||
virtual void doDelete();
|
||||
virtual BOOL canDoDelete() const;
|
||||
/*virtual*/ void doDelete() override;
|
||||
/*virtual*/ BOOL canDoDelete() const override;
|
||||
|
||||
virtual void selectAll();
|
||||
virtual BOOL canSelectAll() const;
|
||||
/*virtual*/ void selectAll() override;
|
||||
/*virtual*/ BOOL canSelectAll() const override;
|
||||
|
||||
virtual void deselect();
|
||||
virtual BOOL canDeselect() const;
|
||||
/*virtual*/ void deselect() override;
|
||||
/*virtual*/ BOOL canDeselect() const override;
|
||||
|
||||
// LLSpellCheckMenuHandler overrides
|
||||
/*virtual*/ bool getSpellCheck() const;
|
||||
/*virtual*/ bool getSpellCheck() const override;
|
||||
|
||||
/*virtual*/ const std::string& getSuggestion(U32 index) const;
|
||||
/*virtual*/ U32 getSuggestionCount() const;
|
||||
/*virtual*/ void replaceWithSuggestion(U32 index);
|
||||
/*virtual*/ const std::string& getSuggestion(U32 index) const override;
|
||||
/*virtual*/ U32 getSuggestionCount() const override;
|
||||
/*virtual*/ void replaceWithSuggestion(U32 index) override;
|
||||
|
||||
/*virtual*/ void addToDictionary();
|
||||
/*virtual*/ bool canAddToDictionary() const;
|
||||
/*virtual*/ void addToDictionary() override;
|
||||
/*virtual*/ bool canAddToDictionary() const override;
|
||||
|
||||
/*virtual*/ void addToIgnore();
|
||||
/*virtual*/ bool canAddToIgnore() const;
|
||||
/*virtual*/ void addToIgnore() override;
|
||||
/*virtual*/ bool canAddToIgnore() const override;
|
||||
|
||||
// Spell checking helper functions
|
||||
std::string getMisspelledWord(U32 pos) const;
|
||||
|
|
@ -174,27 +176,28 @@ public:
|
|||
void onSpellCheckSettingsChange();
|
||||
|
||||
// view overrides
|
||||
virtual void draw();
|
||||
virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE);
|
||||
virtual void onFocusReceived();
|
||||
virtual void onFocusLost();
|
||||
virtual void setEnabled(BOOL enabled);
|
||||
/*virtual*/ const std::string getToolTip() const override;
|
||||
/*virtual*/ void draw() override;
|
||||
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
|
||||
/*virtual*/ void onFocusReceived() override;
|
||||
/*virtual*/ void onFocusLost() override;
|
||||
/*virtual*/ void setEnabled(BOOL enabled) override;
|
||||
|
||||
// UI control overrides
|
||||
virtual void clear();
|
||||
virtual void onTabInto();
|
||||
virtual void setFocus( BOOL b );
|
||||
virtual void setRect(const LLRect& rect);
|
||||
virtual BOOL acceptsTextInput() const;
|
||||
virtual void onCommit();
|
||||
virtual BOOL isDirty() const; // Returns TRUE if user changed value at all
|
||||
virtual void resetDirty(); // Clear dirty state
|
||||
/*virtual*/ void clear() override;
|
||||
/*virtual*/ void onTabInto() override;
|
||||
/*virtual*/ void setFocus(BOOL b) override;
|
||||
/*virtual*/ void setRect(const LLRect& rect) override;
|
||||
/*virtual*/ BOOL acceptsTextInput() const override;
|
||||
/*virtual*/ void onCommit() override;
|
||||
/*virtual*/ BOOL isDirty() const override; // Returns TRUE if user changed value at all
|
||||
/*virtual*/ void resetDirty() override; // Clear dirty state
|
||||
|
||||
// assumes UTF8 text
|
||||
virtual void setValue(const LLSD& value );
|
||||
virtual LLSD getValue() const;
|
||||
virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text );
|
||||
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
|
||||
/*virtual*/ void setValue(const LLSD& value) override;
|
||||
/*virtual*/ LLSD getValue() const override;
|
||||
/*virtual*/ BOOL setTextArg(const std::string& key, const LLStringExplicit& text) override;
|
||||
/*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override;
|
||||
|
||||
void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; }
|
||||
const std::string& getLabel() { return mLabel.getString(); }
|
||||
|
|
@ -216,7 +219,7 @@ public:
|
|||
|
||||
// Selects characters 'start' to 'end'.
|
||||
void setSelection(S32 start, S32 end);
|
||||
virtual void getSelectionRange(S32 *position, S32 *length) const;
|
||||
/*virtual*/ void getSelectionRange(S32 *position, S32 *length) const override;
|
||||
|
||||
void setCommitOnFocusLost( BOOL b ) { mCommitOnFocusLost = b; }
|
||||
void setRevertOnEsc( BOOL b ) { mRevertOnEsc = b; }
|
||||
|
|
@ -316,14 +319,14 @@ public:
|
|||
void updateAllowingLanguageInput();
|
||||
BOOL hasPreeditString() const;
|
||||
// Implementation (overrides) of LLPreeditor
|
||||
virtual void resetPreedit();
|
||||
virtual void updatePreedit(const LLWString &preedit_string,
|
||||
const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position);
|
||||
virtual void markAsPreedit(S32 position, S32 length);
|
||||
virtual void getPreeditRange(S32 *position, S32 *length) const;
|
||||
virtual BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const;
|
||||
virtual S32 getPreeditFontSize() const;
|
||||
virtual LLWString getPreeditString() const { return getWText(); }
|
||||
/*virtual*/ void resetPreedit() override;
|
||||
/*virtual*/ void updatePreedit(const LLWString &preedit_string,
|
||||
const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) override;
|
||||
/*virtual*/ void markAsPreedit(S32 position, S32 length) override;
|
||||
/*virtual*/ void getPreeditRange(S32 *position, S32 *length) const override;
|
||||
/*virtual*/ BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const override;
|
||||
/*virtual*/ S32 getPreeditFontSize() const override;
|
||||
/*virtual*/ LLWString getPreeditString() const override { return getWText(); }
|
||||
|
||||
void setText(const LLStringExplicit &new_text, bool use_size_limit);
|
||||
|
||||
|
|
@ -400,6 +403,7 @@ protected:
|
|||
BOOL mReadOnly;
|
||||
|
||||
BOOL mShowImageFocused;
|
||||
BOOL mShowLabelFocused;
|
||||
|
||||
bool mAllowEmoji;
|
||||
bool mUseBgColor;
|
||||
|
|
|
|||
|
|
@ -573,6 +573,11 @@ void LLMenuItemGL::onVisibilityChange(BOOL new_visibility)
|
|||
//
|
||||
// This class represents a separator.
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LLMenuItemSeparatorGL::Params::Params()
|
||||
: on_visible("on_visible")
|
||||
{
|
||||
}
|
||||
|
||||
LLMenuItemSeparatorGL::LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p) :
|
||||
LLMenuItemGL( p )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -235,10 +235,10 @@ public:
|
|||
struct Params : public LLInitParam::Block<Params, LLMenuItemGL::Params>
|
||||
{
|
||||
Optional<EnableCallbackParam > on_visible;
|
||||
Params() : on_visible("on_visible")
|
||||
{}
|
||||
Params();
|
||||
};
|
||||
LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());
|
||||
|
||||
LLMenuItemSeparatorGL(const LLMenuItemSeparatorGL::Params& p = LLMenuItemSeparatorGL::Params());
|
||||
|
||||
/*virtual*/ void draw( void );
|
||||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
|
|
|
|||
|
|
@ -914,7 +914,7 @@ public:
|
|||
/* virtual */ LLNotificationPtr add(const std::string& name,
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
LLNotificationFunctorRegistry::ResponseFunctor functor);
|
||||
LLNotificationFunctorRegistry::ResponseFunctor functor) override;
|
||||
LLNotificationPtr add(const LLNotification::Params& p);
|
||||
|
||||
void add(const LLNotificationPtr pNotif);
|
||||
|
|
@ -965,8 +965,8 @@ public:
|
|||
bool isVisibleByRules(LLNotificationPtr pNotification);
|
||||
|
||||
private:
|
||||
/*virtual*/ void initSingleton();
|
||||
/*virtual*/ void cleanupSingleton();
|
||||
/*virtual*/ void initSingleton() override;
|
||||
/*virtual*/ void cleanupSingleton() override;
|
||||
|
||||
void loadPersistentNotifications();
|
||||
|
||||
|
|
|
|||
|
|
@ -475,13 +475,15 @@ void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent)
|
|||
{
|
||||
up_button->reshape(up_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness));
|
||||
down_button->reshape(down_button->getRect().getWidth(), llmin(getRect().getHeight() / 2, mThickness));
|
||||
up_button->setOrigin(up_button->getRect().mLeft, getRect().getHeight() - up_button->getRect().getHeight());
|
||||
up_button->setOrigin(0, getRect().getHeight() - up_button->getRect().getHeight());
|
||||
down_button->setOrigin(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
up_button->reshape(llmin(getRect().getWidth() / 2, mThickness), up_button->getRect().getHeight());
|
||||
down_button->reshape(llmin(getRect().getWidth() / 2, mThickness), down_button->getRect().getHeight());
|
||||
down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), down_button->getRect().mBottom);
|
||||
up_button->setOrigin(0, 0);
|
||||
down_button->setOrigin(getRect().getWidth() - down_button->getRect().getWidth(), 0);
|
||||
}
|
||||
updateThumbRect();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ LLScrollContainer::Params::Params()
|
|||
bg_color("color"),
|
||||
border_visible("border_visible"),
|
||||
hide_scrollbar("hide_scrollbar"),
|
||||
ignore_arrow_keys("ignore_arrow_keys"),
|
||||
min_auto_scroll_rate("min_auto_scroll_rate", 100),
|
||||
max_auto_scroll_rate("max_auto_scroll_rate", 1000),
|
||||
max_auto_scroll_zone("max_auto_scroll_zone", 16),
|
||||
|
|
@ -86,6 +87,7 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
|
|||
mBackgroundColor(p.bg_color()),
|
||||
mIsOpaque(p.is_opaque),
|
||||
mHideScrollbar(p.hide_scrollbar),
|
||||
mIgnoreArrowKeys(p.ignore_arrow_keys),
|
||||
mReserveScrollCorner(p.reserve_scroll_corner),
|
||||
mMinAutoScrollRate(p.min_auto_scroll_rate),
|
||||
mMaxAutoScrollRate(p.max_auto_scroll_rate),
|
||||
|
|
@ -204,10 +206,29 @@ void LLScrollContainer::reshape(S32 width, S32 height,
|
|||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
|
||||
{
|
||||
if (mIgnoreArrowKeys)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
case KEY_PAGE_UP:
|
||||
case KEY_PAGE_DOWN:
|
||||
case KEY_HOME:
|
||||
case KEY_END:
|
||||
return FALSE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// allow scrolled view to handle keystrokes in case it delegated keyboard focus
|
||||
// to the scroll container.
|
||||
// to the scroll container.
|
||||
// NOTE: this should not recurse indefinitely as handleKeyHere
|
||||
// should not propagate to parent controls, so mScrolledView should *not*
|
||||
// call LLScrollContainer::handleKeyHere in turn
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ public:
|
|||
Optional<bool> is_opaque,
|
||||
reserve_scroll_corner,
|
||||
border_visible,
|
||||
hide_scrollbar;
|
||||
hide_scrollbar,
|
||||
ignore_arrow_keys;
|
||||
Optional<F32> min_auto_scroll_rate,
|
||||
max_auto_scroll_rate;
|
||||
Optional<U32> max_auto_scroll_zone;
|
||||
|
|
@ -149,6 +150,7 @@ private:
|
|||
F32 mMaxAutoScrollRate;
|
||||
U32 mMaxAutoScrollZone;
|
||||
bool mHideScrollbar;
|
||||
bool mIgnoreArrowKeys;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,18 +45,24 @@ public:
|
|||
|
||||
|
||||
/*
|
||||
* A set of panels that are displayed in a vertical sequence inside a scroll container.
|
||||
* A set of panels that are displayed in a sequence inside a scroll container.
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ void LLScrollListCtrl::clearRows()
|
|||
LLScrollListItem* LLScrollListCtrl::getFirstSelected() const
|
||||
{
|
||||
item_list::const_iterator iter;
|
||||
for(iter = mItemList.begin(); iter != mItemList.end(); iter++)
|
||||
for (iter = mItemList.begin(); iter != mItemList.end(); iter++)
|
||||
{
|
||||
LLScrollListItem* item = *iter;
|
||||
if (item->getSelected())
|
||||
|
|
@ -1269,7 +1269,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen
|
|||
LLScrollListItem* item = getItemByLabel(label, case_sensitive, column);
|
||||
|
||||
bool found = NULL != item;
|
||||
if(found)
|
||||
if (found)
|
||||
{
|
||||
selectItem(item, -1);
|
||||
}
|
||||
|
|
@ -2747,7 +2747,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)
|
|||
S32 LLScrollListCtrl::getLinesPerPage()
|
||||
{
|
||||
//if mPageLines is NOT provided display all item
|
||||
if(mPageLines)
|
||||
if (mPageLines)
|
||||
{
|
||||
return mPageLines;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ public:
|
|||
S32 getItemIndex( LLScrollListItem* item ) const;
|
||||
S32 getItemIndex( const LLUUID& item_id ) const;
|
||||
|
||||
void setCommentText( const std::string& comment_text);
|
||||
void setCommentText( const std::string& comment_text);
|
||||
LLScrollListItem* addSeparator(EAddPosition pos);
|
||||
|
||||
// "Simple" interface: use this when you're creating a list that contains only unique strings, only
|
||||
|
|
@ -263,7 +263,7 @@ public:
|
|||
BOOL selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); // FALSE if item not found
|
||||
BOOL selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1);
|
||||
BOOL selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1);
|
||||
LLScrollListItem* getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 );
|
||||
LLScrollListItem* getItemByLabel(const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0);
|
||||
const std::string getSelectedItemLabel(S32 column = 0) const;
|
||||
LLSD getSelectedValue();
|
||||
|
||||
|
|
@ -322,7 +322,7 @@ public:
|
|||
|
||||
virtual S32 getScrollPos() const;
|
||||
virtual void setScrollPos( S32 pos );
|
||||
S32 getSearchColumn();
|
||||
S32 getSearchColumn();
|
||||
void setSearchColumn(S32 column) { mSearchColumn = column; }
|
||||
S32 getColumnIndexFromOffset(S32 x);
|
||||
S32 getColumnOffsetFromIndex(S32 index);
|
||||
|
|
@ -371,13 +371,13 @@ public:
|
|||
// Used "internally" by the scroll bar.
|
||||
void onScrollChange( S32 new_pos, LLScrollbar* src );
|
||||
|
||||
static void onClickColumn(void *userdata);
|
||||
static void onClickColumn(void *userdata);
|
||||
|
||||
virtual void updateColumns(bool force_update = false);
|
||||
S32 calcMaxContentWidth();
|
||||
bool updateColumnWidths();
|
||||
virtual void updateColumns(bool force_update = false);
|
||||
S32 calcMaxContentWidth();
|
||||
bool updateColumnWidths();
|
||||
|
||||
void setHeadingHeight(S32 heading_height);
|
||||
void setHeadingHeight(S32 heading_height);
|
||||
/**
|
||||
* Sets max visible lines without scroolbar, if this value equals to 0,
|
||||
* then display all items.
|
||||
|
|
@ -398,18 +398,20 @@ public:
|
|||
virtual void deselect();
|
||||
virtual BOOL canDeselect() const;
|
||||
|
||||
void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; }
|
||||
void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width);
|
||||
S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
|
||||
void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; }
|
||||
void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width);
|
||||
S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }
|
||||
|
||||
std::string getSortColumnName();
|
||||
BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }
|
||||
BOOL hasSortOrder() const;
|
||||
void clearSortOrder();
|
||||
|
||||
void setAlternateSort() { mAlternateSort = true; }
|
||||
void setAlternateSort() { mAlternateSort = TRUE; }
|
||||
|
||||
S32 selectMultiple( uuid_vec_t ids );
|
||||
void selectPrevItem(BOOL extend_selection = FALSE);
|
||||
void selectNextItem(BOOL extend_selection = FALSE);
|
||||
S32 selectMultiple(uuid_vec_t ids);
|
||||
// conceptually const, but mutates mItemList
|
||||
void updateSort() const;
|
||||
// sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example)
|
||||
|
|
@ -454,8 +456,6 @@ protected:
|
|||
void updateLineHeight();
|
||||
|
||||
private:
|
||||
void selectPrevItem(BOOL extend_selection);
|
||||
void selectNextItem(BOOL extend_selection);
|
||||
void drawItems();
|
||||
|
||||
void updateLineHeightInsert(LLScrollListItem* item);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public:
|
|||
protected:
|
||||
void addToDictFile(const std::string& dict_path, const std::string& word);
|
||||
void initHunspell(const std::string& dict_language);
|
||||
void initSingleton();
|
||||
void initSingleton() override;
|
||||
|
||||
public:
|
||||
typedef std::list<std::string> dict_list_t;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
#include "lltextbase.h"
|
||||
|
||||
#include "llemojidictionary.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "lllocalcliprect.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llscrollcontainer.h"
|
||||
|
|
@ -161,10 +163,12 @@ LLTextBase::Params::Params()
|
|||
line_spacing("line_spacing"),
|
||||
max_text_length("max_length", 255),
|
||||
font_shadow("font_shadow"),
|
||||
text_valign("text_valign"),
|
||||
wrap("wrap"),
|
||||
trusted_content("trusted_content", true),
|
||||
always_show_icons("always_show_icons", false),
|
||||
use_ellipses("use_ellipses", false),
|
||||
use_color("use_color", true),
|
||||
parse_urls("parse_urls", false),
|
||||
force_urls_external("force_urls_external", false),
|
||||
parse_highlights("parse_highlights", false)
|
||||
|
|
@ -208,6 +212,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mVPad(p.v_pad),
|
||||
mHAlign(p.font_halign),
|
||||
mVAlign(p.font_valign),
|
||||
mTextVAlign(p.text_valign.isProvided() ? p.text_valign.getValue() : p.font_valign.getValue()),
|
||||
mLineSpacingMult(p.line_spacing.multiple),
|
||||
mLineSpacingPixels(p.line_spacing.pixels),
|
||||
mClip(p.clip),
|
||||
|
|
@ -222,6 +227,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mPlainText ( p.plain_text ),
|
||||
mWordWrap(p.wrap),
|
||||
mUseEllipses( p.use_ellipses ),
|
||||
mUseColor(p.use_color),
|
||||
mParseHTML(p.parse_urls),
|
||||
mForceUrlsExternal(p.force_urls_external),
|
||||
mParseHighlights(p.parse_highlights),
|
||||
|
|
@ -582,7 +588,7 @@ void LLTextBase::drawCursor()
|
|||
fontp = segmentp->getStyle()->getFont();
|
||||
fontp->render(text, mCursorPos, cursor_rect,
|
||||
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
|
||||
LLFontGL::LEFT, mVAlign,
|
||||
LLFontGL::LEFT, mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
1);
|
||||
|
|
@ -896,6 +902,28 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
|
|||
}
|
||||
}
|
||||
|
||||
// Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us)
|
||||
{
|
||||
LLStyleSP emoji_style;
|
||||
LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL;
|
||||
for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++)
|
||||
{
|
||||
llwchar code = wstr[text_kitty];
|
||||
bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code);
|
||||
if (isEmoji)
|
||||
{
|
||||
if (!emoji_style)
|
||||
{
|
||||
emoji_style = new LLStyle(getStyleParams());
|
||||
emoji_style->setFont(LLFontGL::getFontEmoji());
|
||||
}
|
||||
|
||||
S32 new_seg_start = pos + text_kitty;
|
||||
insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getViewModel()->getEditableDisplay().insert(pos, wstr);
|
||||
|
||||
if ( truncate() )
|
||||
|
|
@ -1079,6 +1107,7 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert)
|
|||
needsReflow(reflow_start_index);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
// handle triple click
|
||||
|
|
@ -1133,6 +1162,7 @@ BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleMouseDown(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1152,6 +1182,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleMouseUp(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1163,6 +1194,7 @@ BOOL LLTextBase::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleMiddleMouseDown(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1174,6 +1206,7 @@ BOOL LLTextBase::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleMiddleMouseUp(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1185,6 +1218,7 @@ BOOL LLTextBase::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleRightMouseDown(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1196,6 +1230,7 @@ BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleRightMouseUp(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
//Don't start triple click timer if user have clicked on scrollbar
|
||||
|
|
@ -1215,6 +1250,7 @@ BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleDoubleClick(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1226,6 +1262,7 @@ BOOL LLTextBase::handleHover(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleHover(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1237,6 +1274,7 @@ BOOL LLTextBase::handleScrollWheel(S32 x, S32 y, S32 clicks)
|
|||
return LLUICtrl::handleScrollWheel(x, y, clicks);
|
||||
}
|
||||
|
||||
//virtual
|
||||
BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
|
||||
|
|
@ -1248,7 +1286,20 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
|
|||
return LLUICtrl::handleToolTip(x, y, mask);
|
||||
}
|
||||
|
||||
//virtual
|
||||
const std::string LLTextBase::getToolTip() const
|
||||
{
|
||||
if (sDebugUnicode)
|
||||
{
|
||||
std::string text = getText();
|
||||
std::string tooltip = utf8str_showBytesUTF8(text);
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
return LLUICtrl::getToolTip();
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape)
|
||||
|
|
@ -1275,6 +1326,7 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
|
|||
}
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLTextBase::draw()
|
||||
{
|
||||
// reflow if needed, on demand
|
||||
|
|
@ -1985,21 +2037,8 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaini
|
|||
|
||||
LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
|
||||
{
|
||||
|
||||
static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();
|
||||
|
||||
S32 text_len = 0;
|
||||
if (!useLabel())
|
||||
{
|
||||
text_len = getLength();
|
||||
}
|
||||
else
|
||||
{
|
||||
text_len = mLabel.getWString().length();
|
||||
}
|
||||
|
||||
if (index > text_len) { return mSegments.end(); }
|
||||
|
||||
// when there are no segments, we return the end iterator, which must be checked by caller
|
||||
if (mSegments.size() <= 1) { return mSegments.begin(); }
|
||||
|
||||
|
|
@ -2013,18 +2052,6 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i
|
|||
{
|
||||
static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment();
|
||||
|
||||
S32 text_len = 0;
|
||||
if (!useLabel())
|
||||
{
|
||||
text_len = getLength();
|
||||
}
|
||||
else
|
||||
{
|
||||
text_len = mLabel.getWString().length();
|
||||
}
|
||||
|
||||
if (index > text_len) { return mSegments.end(); }
|
||||
|
||||
// when there are no segments, we return the end iterator, which must be checked by caller
|
||||
if (mSegments.size() <= 1) { return mSegments.begin(); }
|
||||
|
||||
|
|
@ -2188,8 +2215,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
|
|||
S32 start=0,end=0;
|
||||
LLUrlMatch match;
|
||||
std::string text = new_text;
|
||||
while ( LLUrlRegistry::instance().findUrl(text, match,
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted() || mAlwaysShowIcons))
|
||||
while (LLUrlRegistry::instance().findUrl(text, match,
|
||||
boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons))
|
||||
{
|
||||
start = match.getStart();
|
||||
end = match.getEnd()+1;
|
||||
|
|
@ -2437,18 +2464,18 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
|
|||
LLStyle::Params normal_style_params(style_params);
|
||||
normal_style_params.font.style("NORMAL");
|
||||
LLStyleConstSP normal_sp(new LLStyle(normal_style_params));
|
||||
segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this ));
|
||||
segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this));
|
||||
}
|
||||
else
|
||||
{
|
||||
segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this ));
|
||||
segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this));
|
||||
}
|
||||
|
||||
insertStringNoUndo(getLength(), wide_text, &segments);
|
||||
}
|
||||
|
||||
// Set the cursor and scroll position
|
||||
if( selection_start != selection_end )
|
||||
if (selection_start != selection_end)
|
||||
{
|
||||
mSelectionStart = selection_start;
|
||||
mSelectionEnd = selection_end;
|
||||
|
|
@ -2456,7 +2483,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
|
|||
mIsSelecting = was_selecting;
|
||||
setCursorPos(cursor_pos);
|
||||
}
|
||||
else if( cursor_was_at_end )
|
||||
else if (cursor_was_at_end)
|
||||
{
|
||||
setCursorPos(getLength());
|
||||
}
|
||||
|
|
@ -2468,25 +2495,28 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
|
|||
|
||||
void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only)
|
||||
{
|
||||
if (new_text.empty()) return;
|
||||
if (new_text.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type pos = new_text.find("\n",start);
|
||||
std::string::size_type pos = new_text.find("\n", start);
|
||||
|
||||
while(pos!=-1)
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
if(pos!=start)
|
||||
if (pos != start)
|
||||
{
|
||||
std::string str = std::string(new_text,start,pos-start);
|
||||
appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only);
|
||||
appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only);
|
||||
}
|
||||
appendLineBreakSegment(style_params);
|
||||
start = pos+1;
|
||||
pos = new_text.find("\n",start);
|
||||
pos = new_text.find("\n", start);
|
||||
}
|
||||
|
||||
std::string str = std::string(new_text,start,new_text.length()-start);
|
||||
appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only);
|
||||
std::string str = std::string(new_text, start, new_text.length() - start);
|
||||
appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3318,12 +3348,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
|
|||
font->render(text, start,
|
||||
rect,
|
||||
color,
|
||||
LLFontGL::LEFT, mEditor.mVAlign,
|
||||
LLFontGL::LEFT, mEditor.mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
mStyle->getShadowType(),
|
||||
length,
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(),
|
||||
mEditor.getUseColor());
|
||||
}
|
||||
rect.mLeft = right_x;
|
||||
|
||||
|
|
@ -3337,12 +3368,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
|
|||
font->render(text, start,
|
||||
rect,
|
||||
mStyle->getSelectedColor().get(),
|
||||
LLFontGL::LEFT, mEditor.mVAlign,
|
||||
LLFontGL::LEFT, mEditor.mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
length,
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(),
|
||||
mEditor.getUseColor());
|
||||
}
|
||||
rect.mLeft = right_x;
|
||||
if( selection_end < seg_end )
|
||||
|
|
@ -3354,12 +3386,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
|
|||
font->render(text, start,
|
||||
rect,
|
||||
color,
|
||||
LLFontGL::LEFT, mEditor.mVAlign,
|
||||
LLFontGL::LEFT, mEditor.mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
mStyle->getShadowType(),
|
||||
length,
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(),
|
||||
mEditor.getUseColor());
|
||||
}
|
||||
return right_x;
|
||||
}
|
||||
|
|
@ -3590,6 +3623,33 @@ const S32 LLLabelTextSegment::getLength() const
|
|||
return mEditor.getWlabel().length();
|
||||
}
|
||||
|
||||
//
|
||||
// LLEmojiTextSegment
|
||||
//
|
||||
LLEmojiTextSegment::LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor)
|
||||
: LLNormalTextSegment(style, start, end, editor)
|
||||
{
|
||||
}
|
||||
|
||||
LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible)
|
||||
: LLNormalTextSegment(color, start, end, editor, is_visible)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (mTooltip.empty())
|
||||
{
|
||||
LLWString emoji = getWText().substr(getStart(), getEnd() - getStart());
|
||||
if (!emoji.empty())
|
||||
{
|
||||
mTooltip = LLEmojiHelper::instance().getToolTip(emoji[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return LLNormalTextSegment::handleToolTip(x, y, mask);
|
||||
}
|
||||
|
||||
//
|
||||
// LLOnHoverChangeableTextSegment
|
||||
//
|
||||
|
|
|
|||
|
|
@ -178,6 +178,18 @@ protected:
|
|||
/*virtual*/ const S32 getLength() const;
|
||||
};
|
||||
|
||||
// Text segment that represents a single emoji character that has a different style (=font size) than the rest of
|
||||
// the document it belongs to
|
||||
class LLEmojiTextSegment : public LLNormalTextSegment
|
||||
{
|
||||
public:
|
||||
LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor);
|
||||
LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
|
||||
|
||||
bool canEdit() const override { return false; }
|
||||
BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
|
||||
};
|
||||
|
||||
// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)
|
||||
class LLOnHoverChangeableTextSegment : public LLNormalTextSegment
|
||||
{
|
||||
|
|
@ -273,7 +285,7 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr;
|
|||
/// as LLTextEditor and LLTextBox. It implements shared functionality
|
||||
/// such as Url highlighting and opening.
|
||||
///
|
||||
class LLTextBase
|
||||
class LLTextBase
|
||||
: public LLUICtrl,
|
||||
protected LLEditMenuHandler,
|
||||
public LLSpellCheckMenuHandler,
|
||||
|
|
@ -316,6 +328,7 @@ public:
|
|||
plain_text,
|
||||
wrap,
|
||||
use_ellipses,
|
||||
use_color,
|
||||
parse_urls,
|
||||
force_urls_external,
|
||||
parse_highlights,
|
||||
|
|
@ -335,55 +348,58 @@ public:
|
|||
|
||||
Optional<LLFontGL::ShadowType> font_shadow;
|
||||
|
||||
Optional<LLFontGL::VAlign> text_valign;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
// LLMouseHandler interface
|
||||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
|
||||
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) override;
|
||||
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
|
||||
|
||||
// LLView interface
|
||||
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ const std::string getToolTip() const override;
|
||||
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
|
||||
/*virtual*/ void draw() override;
|
||||
|
||||
// LLUICtrl interface
|
||||
/*virtual*/ BOOL acceptsTextInput() const { return !mReadOnly; }
|
||||
/*virtual*/ void setColor( const LLColor4& c );
|
||||
/*virtual*/ BOOL acceptsTextInput() const override { return !mReadOnly; }
|
||||
/*virtual*/ void setColor(const LLColor4& c) override;
|
||||
virtual void setReadOnlyColor(const LLColor4 &c);
|
||||
virtual void onVisibilityChange( BOOL new_visibility );
|
||||
/*virtual*/ void onVisibilityChange(BOOL new_visibility) override;
|
||||
|
||||
/*virtual*/ void setValue(const LLSD& value );
|
||||
/*virtual*/ LLTextViewModel* getViewModel() const;
|
||||
/*virtual*/ void setValue(const LLSD& value) override;
|
||||
/*virtual*/ LLTextViewModel* getViewModel() const override;
|
||||
|
||||
// LLEditMenuHandler interface
|
||||
/*virtual*/ BOOL canDeselect() const;
|
||||
/*virtual*/ void deselect();
|
||||
/*virtual*/ BOOL canDeselect() const override;
|
||||
/*virtual*/ void deselect() override;
|
||||
|
||||
virtual void onFocusReceived();
|
||||
virtual void onFocusLost();
|
||||
virtual void onFocusReceived() override;
|
||||
virtual void onFocusLost() override;
|
||||
|
||||
void setParseHTML(bool parse_html) { mParseHTML = parse_html; }
|
||||
|
||||
// LLSpellCheckMenuHandler overrides
|
||||
/*virtual*/ bool getSpellCheck() const;
|
||||
/*virtual*/ bool getSpellCheck() const override;
|
||||
|
||||
/*virtual*/ const std::string& getSuggestion(U32 index) const;
|
||||
/*virtual*/ U32 getSuggestionCount() const;
|
||||
/*virtual*/ void replaceWithSuggestion(U32 index);
|
||||
/*virtual*/ const std::string& getSuggestion(U32 index) const override;
|
||||
/*virtual*/ U32 getSuggestionCount() const override;
|
||||
/*virtual*/ void replaceWithSuggestion(U32 index) override;
|
||||
|
||||
/*virtual*/ void addToDictionary();
|
||||
/*virtual*/ bool canAddToDictionary() const;
|
||||
/*virtual*/ void addToDictionary() override;
|
||||
/*virtual*/ bool canAddToDictionary() const override;
|
||||
|
||||
/*virtual*/ void addToIgnore();
|
||||
/*virtual*/ bool canAddToIgnore() const;
|
||||
/*virtual*/ void addToIgnore() override;
|
||||
/*virtual*/ bool canAddToIgnore() const override;
|
||||
|
||||
// Spell checking helper functions
|
||||
std::string getMisspelledWord(U32 pos) const;
|
||||
|
|
@ -394,6 +410,7 @@ public:
|
|||
// used by LLTextSegment layout code
|
||||
bool getWordWrap() { return mWordWrap; }
|
||||
bool getUseEllipses() { return mUseEllipses; }
|
||||
bool getUseColor() { return mUseColor; }
|
||||
bool truncate(); // returns true of truncation occurred
|
||||
|
||||
bool isContentTrusted() {return mTrustedContent;}
|
||||
|
|
@ -416,7 +433,7 @@ public:
|
|||
void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params());
|
||||
|
||||
void setLabel(const LLStringExplicit& label);
|
||||
virtual BOOL setLabelArg(const std::string& key, const LLStringExplicit& text );
|
||||
/*virtual*/ BOOL setLabelArg(const std::string& key, const LLStringExplicit& text) override;
|
||||
|
||||
const std::string& getLabel() { return mLabel.getString(); }
|
||||
const LLWString& getWlabel() { return mLabel.getWString();}
|
||||
|
|
@ -633,7 +650,8 @@ protected:
|
|||
S32 normalizeUri(std::string& uri);
|
||||
|
||||
protected:
|
||||
virtual std::string _getSearchText() const
|
||||
// virtual
|
||||
std::string _getSearchText() const override
|
||||
{
|
||||
return mLabel.getString() + getToolTip();
|
||||
}
|
||||
|
|
@ -687,8 +705,9 @@ protected:
|
|||
// configuration
|
||||
S32 mHPad; // padding on left of text
|
||||
S32 mVPad; // padding above text
|
||||
LLFontGL::HAlign mHAlign;
|
||||
LLFontGL::VAlign mVAlign;
|
||||
LLFontGL::HAlign mHAlign; // horizontal alignment of the document in its entirety
|
||||
LLFontGL::VAlign mVAlign; // vertical alignment of the document in its entirety
|
||||
LLFontGL::VAlign mTextVAlign; // vertical alignment of a text segment within a single line of text
|
||||
F32 mLineSpacingMult; // multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding)
|
||||
S32 mLineSpacingPixels; // padding between lines
|
||||
bool mBorderVisible;
|
||||
|
|
@ -697,6 +716,7 @@ protected:
|
|||
bool mParseHighlights; // highlight user-defined keywords
|
||||
bool mWordWrap;
|
||||
bool mUseEllipses;
|
||||
bool mUseColor;
|
||||
bool mTrackEnd; // if true, keeps scroll position at end of document during resize
|
||||
bool mReadOnly;
|
||||
bool mBGVisible; // render background?
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "llmath.h"
|
||||
|
||||
#include "llclipboard.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "llscrollbar.h"
|
||||
#include "llstl.h"
|
||||
#include "llstring.h"
|
||||
|
|
@ -238,6 +239,7 @@ LLTextEditor::Params::Params()
|
|||
default_color("default_color"),
|
||||
commit_on_focus_lost("commit_on_focus_lost", false),
|
||||
show_context_menu("show_context_menu"),
|
||||
show_emoji_helper("show_emoji_helper"),
|
||||
enable_tooltip_paste("enable_tooltip_paste")
|
||||
{
|
||||
addSynonym(prevalidate_callback, "text_type");
|
||||
|
|
@ -258,6 +260,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
|
|||
mTabsToNextField(p.ignore_tab),
|
||||
mPrevalidateFunc(p.prevalidate_callback()),
|
||||
mShowContextMenu(p.show_context_menu),
|
||||
mShowEmojiHelper(p.show_emoji_helper),
|
||||
mEnableTooltipPaste(p.enable_tooltip_paste),
|
||||
mPassDelete(FALSE),
|
||||
mKeepSelectionOnReturn(false)
|
||||
|
|
@ -505,6 +508,16 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out,
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::setShowEmojiHelper(bool show)
|
||||
{
|
||||
if (!mShowEmojiHelper)
|
||||
{
|
||||
LLEmojiHelper::instance().hideHelper(this);
|
||||
}
|
||||
|
||||
mShowEmojiHelper = show;
|
||||
}
|
||||
|
||||
BOOL LLTextEditor::selectionContainsLineBreaks()
|
||||
{
|
||||
if (hasSelection())
|
||||
|
|
@ -668,6 +681,28 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p
|
|||
endSelection();
|
||||
}
|
||||
|
||||
void LLTextEditor::insertEmoji(llwchar emoji)
|
||||
{
|
||||
LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL;
|
||||
auto styleParams = LLStyle::Params();
|
||||
styleParams.font = LLFontGL::getFontEmoji();
|
||||
auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this);
|
||||
insert(mCursorPos, LLWString(1, emoji), false, segment);
|
||||
setCursorPos(mCursorPos + 1);
|
||||
}
|
||||
|
||||
void LLTextEditor::handleEmojiCommit(llwchar emoji)
|
||||
{
|
||||
S32 shortCodePos;
|
||||
if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos))
|
||||
{
|
||||
remove(shortCodePos, mCursorPos - shortCodePos, true);
|
||||
setCursorPos(shortCodePos);
|
||||
|
||||
insertEmoji(emoji);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
|
|
@ -934,6 +969,12 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
|
|||
|
||||
S32 LLTextEditor::execute( TextCmd* cmd )
|
||||
{
|
||||
if (!mReadOnly && mShowEmojiHelper)
|
||||
{
|
||||
// Any change to our contents should always hide the helper
|
||||
LLEmojiHelper::instance().hideHelper(this);
|
||||
}
|
||||
|
||||
S32 delta = 0;
|
||||
if( cmd->execute(this, &delta) )
|
||||
{
|
||||
|
|
@ -983,7 +1024,7 @@ S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)
|
|||
// store text segments
|
||||
getSegmentsInRange(segments_to_remove, pos, pos + length, false);
|
||||
|
||||
if(pos <= end_pos)
|
||||
if (pos <= end_pos)
|
||||
{
|
||||
removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
|
||||
}
|
||||
|
|
@ -1007,11 +1048,12 @@ S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
|
|||
// a pseudo-tab (up to for spaces in a row)
|
||||
void LLTextEditor::removeCharOrTab()
|
||||
{
|
||||
if( !getEnabled() )
|
||||
if (!getEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if( mCursorPos > 0 )
|
||||
|
||||
if (mCursorPos > 0)
|
||||
{
|
||||
S32 chars_to_remove = 1;
|
||||
|
||||
|
|
@ -1023,14 +1065,14 @@ void LLTextEditor::removeCharOrTab()
|
|||
if (offset > 0)
|
||||
{
|
||||
chars_to_remove = offset % SPACES_PER_TAB;
|
||||
if( chars_to_remove == 0 )
|
||||
if (chars_to_remove == 0)
|
||||
{
|
||||
chars_to_remove = SPACES_PER_TAB;
|
||||
}
|
||||
|
||||
for( S32 i = 0; i < chars_to_remove; i++ )
|
||||
for (S32 i = 0; i < chars_to_remove; i++)
|
||||
{
|
||||
if (text[ mCursorPos - i - 1] != ' ')
|
||||
if (text[mCursorPos - i - 1] != ' ')
|
||||
{
|
||||
// Fewer than a full tab's worth of spaces, so
|
||||
// just delete a single character.
|
||||
|
|
@ -1044,8 +1086,10 @@ void LLTextEditor::removeCharOrTab()
|
|||
for (S32 i = 0; i < chars_to_remove; i++)
|
||||
{
|
||||
setCursorPos(mCursorPos - 1);
|
||||
remove( mCursorPos, 1, FALSE );
|
||||
remove(mCursorPos, 1, false);
|
||||
}
|
||||
|
||||
tryToShowEmojiHelper();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1056,7 +1100,7 @@ void LLTextEditor::removeCharOrTab()
|
|||
// Remove a single character from the text
|
||||
S32 LLTextEditor::removeChar(S32 pos)
|
||||
{
|
||||
return remove( pos, 1, FALSE );
|
||||
return remove(pos, 1, false);
|
||||
}
|
||||
|
||||
void LLTextEditor::removeChar()
|
||||
|
|
@ -1065,10 +1109,12 @@ void LLTextEditor::removeChar()
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCursorPos > 0)
|
||||
{
|
||||
setCursorPos(mCursorPos - 1);
|
||||
removeChar(mCursorPos);
|
||||
tryToShowEmojiHelper();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1127,6 +1173,7 @@ void LLTextEditor::addChar(llwchar wc)
|
|||
}
|
||||
|
||||
setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
|
||||
tryToShowEmojiHelper();
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
|
|
@ -1146,6 +1193,37 @@ void LLTextEditor::addChar(llwchar wc)
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::showEmojiHelper()
|
||||
{
|
||||
if (mReadOnly || !mShowEmojiHelper)
|
||||
return;
|
||||
|
||||
const LLRect cursorRect(getLocalRectFromDocIndex(mCursorPos));
|
||||
auto cb = [this](llwchar emoji) { insertEmoji(emoji); };
|
||||
LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, LLStringUtil::null, cb);
|
||||
}
|
||||
|
||||
void LLTextEditor::tryToShowEmojiHelper()
|
||||
{
|
||||
if (mReadOnly || !mShowEmojiHelper)
|
||||
return;
|
||||
|
||||
S32 shortCodePos;
|
||||
LLWString wtext(getWText());
|
||||
if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos))
|
||||
{
|
||||
const LLRect cursorRect(getLocalRectFromDocIndex(shortCodePos));
|
||||
const LLWString wpart(wtext.substr(shortCodePos, mCursorPos - shortCodePos));
|
||||
const std::string part(wstring_to_utf8str(wpart));
|
||||
auto cb = [this](llwchar emoji) { handleEmojiCommit(emoji); };
|
||||
LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, part, cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLEmojiHelper::instance().hideHelper();
|
||||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::addLineBreakChar(BOOL group_together)
|
||||
{
|
||||
if( !getEnabled() )
|
||||
|
|
@ -1778,6 +1856,11 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (mEnableTooltipPaste &&
|
||||
LLToolTipMgr::instance().toolTipVisible() &&
|
||||
KEY_TAB == key)
|
||||
|
|
@ -1819,6 +1902,12 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
|
|||
{
|
||||
resetCursorBlink();
|
||||
needsScroll();
|
||||
|
||||
if (mShowEmojiHelper)
|
||||
{
|
||||
// Dismiss the helper whenever we handled a key that it didn't
|
||||
LLEmojiHelper::instance().hideHelper(this);
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
|
|
@ -1837,7 +1926,12 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)
|
|||
// Handle most keys only if the text editor is writeable.
|
||||
if( !mReadOnly )
|
||||
{
|
||||
if( mAutoIndent && '}' == uni_char )
|
||||
if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( mAutoIndent && '}' == uni_char )
|
||||
{
|
||||
unindentLineBeforeCloseBrace();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public:
|
|||
ignore_tab,
|
||||
commit_on_focus_lost,
|
||||
show_context_menu,
|
||||
show_emoji_helper,
|
||||
enable_tooltip_paste,
|
||||
auto_indent;
|
||||
|
||||
|
|
@ -91,6 +92,9 @@ public:
|
|||
|
||||
static S32 spacesPerTab();
|
||||
|
||||
void insertEmoji(llwchar emoji);
|
||||
void handleEmojiCommit(llwchar emoji);
|
||||
|
||||
// mousehandler overrides
|
||||
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
|
|
@ -202,6 +206,10 @@ public:
|
|||
void setShowContextMenu(bool show) { mShowContextMenu = show; }
|
||||
bool getShowContextMenu() const { return mShowContextMenu; }
|
||||
|
||||
void showEmojiHelper();
|
||||
void setShowEmojiHelper(bool show);
|
||||
bool getShowEmojiHelper() const { return mShowEmojiHelper; }
|
||||
|
||||
void setPassDelete(BOOL b) { mPassDelete = b; }
|
||||
|
||||
protected:
|
||||
|
|
@ -248,6 +256,7 @@ protected:
|
|||
S32 insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment);
|
||||
S32 remove(S32 pos, S32 length, bool group_with_next_op);
|
||||
|
||||
void tryToShowEmojiHelper();
|
||||
void focusLostHelper();
|
||||
void updateAllowingLanguageInput();
|
||||
BOOL hasPreeditString() const;
|
||||
|
|
@ -318,6 +327,7 @@ private:
|
|||
|
||||
BOOL mAllowEmbeddedItems;
|
||||
bool mShowContextMenu;
|
||||
bool mShowEmojiHelper;
|
||||
bool mEnableTooltipPaste;
|
||||
bool mPassDelete;
|
||||
bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter
|
||||
|
|
|
|||
|
|
@ -768,25 +768,20 @@ void LLUICtrl::setIsChrome(BOOL is_chrome)
|
|||
|
||||
// virtual
|
||||
BOOL LLUICtrl::getIsChrome() const
|
||||
{
|
||||
{
|
||||
if (mIsChrome)
|
||||
return TRUE;
|
||||
|
||||
LLView* parent_ctrl = getParent();
|
||||
while(parent_ctrl)
|
||||
while (parent_ctrl)
|
||||
{
|
||||
if(parent_ctrl->isCtrl())
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (parent_ctrl->isCtrl())
|
||||
return ((LLUICtrl*)parent_ctrl)->getIsChrome();
|
||||
|
||||
parent_ctrl = parent_ctrl->getParent();
|
||||
}
|
||||
|
||||
if(parent_ctrl)
|
||||
{
|
||||
return mIsChrome || ((LLUICtrl*)parent_ctrl)->getIsChrome();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mIsChrome ;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ public:
|
|||
class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLTextInputFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override
|
||||
{
|
||||
return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->acceptsTextInput(), TRUE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ public:
|
|||
LLUIString() : mArgs(NULL), mNeedsResult(false), mNeedsWResult(false) {}
|
||||
LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args);
|
||||
LLUIString(const std::string& instring) : mArgs(NULL) { assign(instring); }
|
||||
LLUIString(const LLWString& instring) : mArgs(NULL) { insert(0, instring); }
|
||||
~LLUIString() { delete mArgs; }
|
||||
|
||||
void assign(const std::string& instring);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ static const S32 LINE_HEIGHT = 15;
|
|||
|
||||
S32 LLView::sDepth = 0;
|
||||
bool LLView::sDebugRects = false;
|
||||
bool LLView::sDebugUnicode = false;
|
||||
bool LLView::sIsRectDirty = false;
|
||||
LLRect LLView::sDirtyRect;
|
||||
bool LLView::sDebugRectsShowNames = true;
|
||||
|
|
@ -520,7 +521,7 @@ BOOL LLView::focusNext(LLView::child_list_t & result)
|
|||
{
|
||||
next = result.rbegin();
|
||||
}
|
||||
if((*next)->isCtrl())
|
||||
if ((*next)->isCtrl() && ((LLUICtrl*)*next)->hasTabStop())
|
||||
{
|
||||
LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next);
|
||||
ctrl->setFocus(TRUE);
|
||||
|
|
@ -1024,7 +1025,7 @@ BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
|
|||
handled = handleUnicodeCharHere(uni_char);
|
||||
if (handled && LLView::sDebugKeys)
|
||||
{
|
||||
LL_INFOS() << "Unicode key handled by " << getName() << LL_ENDL;
|
||||
LL_INFOS() << "Unicode key " << wchar_utf8_preview(uni_char) << " is handled by " << getName() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1336,8 +1337,7 @@ void LLView::drawDebugRect()
|
|||
std::string debug_text = llformat("%s (%d x %d)", getName().c_str(),
|
||||
debug_rect.getWidth(), debug_rect.getHeight());
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
|
||||
LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
|
||||
}
|
||||
}
|
||||
LLUI::popMatrix();
|
||||
|
|
@ -1753,23 +1753,26 @@ LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S3
|
|||
const S32 KEEP_ONSCREEN_PIXELS_WIDTH = llmin(min_overlap_pixels, input.getWidth());
|
||||
const S32 KEEP_ONSCREEN_PIXELS_HEIGHT = llmin(min_overlap_pixels, input.getHeight());
|
||||
|
||||
if( input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft )
|
||||
if (KEEP_ONSCREEN_PIXELS_WIDTH <= constraint.getWidth() &&
|
||||
KEEP_ONSCREEN_PIXELS_HEIGHT <= constraint.getHeight())
|
||||
{
|
||||
delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH);
|
||||
}
|
||||
else if( input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight )
|
||||
{
|
||||
delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH);
|
||||
}
|
||||
if (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH < constraint.mLeft)
|
||||
{
|
||||
delta.mX = constraint.mLeft - (input.mRight - KEEP_ONSCREEN_PIXELS_WIDTH);
|
||||
}
|
||||
else if (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH > constraint.mRight)
|
||||
{
|
||||
delta.mX = constraint.mRight - (input.mLeft + KEEP_ONSCREEN_PIXELS_WIDTH);
|
||||
}
|
||||
|
||||
if( input.mTop > constraint.mTop )
|
||||
{
|
||||
delta.mY = constraint.mTop - input.mTop;
|
||||
}
|
||||
else
|
||||
if( input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom )
|
||||
{
|
||||
delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT);
|
||||
if (input.mTop > constraint.mTop)
|
||||
{
|
||||
delta.mY = constraint.mTop - input.mTop;
|
||||
}
|
||||
else if (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT < constraint.mBottom)
|
||||
{
|
||||
delta.mY = constraint.mBottom - (input.mTop - KEEP_ONSCREEN_PIXELS_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
return delta;
|
||||
|
|
@ -1780,13 +1783,19 @@ LLCoordGL getNeededTranslation(const LLRect& input, const LLRect& constraint, S3
|
|||
// (Why top and left? That's where the drag bars are for floaters.)
|
||||
BOOL LLView::translateIntoRect(const LLRect& constraint, S32 min_overlap_pixels)
|
||||
{
|
||||
LLCoordGL translation = getNeededTranslation(getRect(), constraint, min_overlap_pixels);
|
||||
return translateRectIntoRect(getRect(), constraint, min_overlap_pixels);
|
||||
}
|
||||
|
||||
BOOL LLView::translateRectIntoRect(const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels)
|
||||
{
|
||||
LLCoordGL translation = getNeededTranslation(rect, constraint, min_overlap_pixels);
|
||||
|
||||
if (translation.mX != 0 || translation.mY != 0)
|
||||
{
|
||||
translate(translation.mX, translation.mY);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1966,7 +1975,7 @@ private:
|
|||
class SortByTabOrder : public LLQuerySorter, public LLSingleton<SortByTabOrder>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(SortByTabOrder);
|
||||
/*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const
|
||||
/*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const override
|
||||
{
|
||||
children.sort(CompareByTabOrder(parent->getTabOrder(), parent->getDefaultTabGroup()));
|
||||
}
|
||||
|
|
@ -1990,7 +1999,7 @@ const LLViewQuery & LLView::getTabOrderQuery()
|
|||
class LLFocusRootsFilter : public LLQueryFilter, public LLSingleton<LLFocusRootsFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLFocusRootsFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override
|
||||
{
|
||||
return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ public:
|
|||
Alternative<std::string> string;
|
||||
Alternative<U32> flags;
|
||||
|
||||
Follows();
|
||||
Follows();
|
||||
};
|
||||
|
||||
struct Params : public LLInitParam::Block<Params>
|
||||
|
|
@ -369,6 +369,7 @@ public:
|
|||
virtual void translate( S32 x, S32 y );
|
||||
void setOrigin( S32 x, S32 y ) { mRect.translate( x - mRect.mLeft, y - mRect.mBottom ); }
|
||||
BOOL translateIntoRect( const LLRect& constraint, S32 min_overlap_pixels = S32_MAX);
|
||||
BOOL translateRectIntoRect( const LLRect& rect, const LLRect& constraint, S32 min_overlap_pixels = S32_MAX);
|
||||
BOOL translateIntoRectWithExclusion( const LLRect& inside, const LLRect& exclude, S32 min_overlap_pixels = S32_MAX);
|
||||
void centerWithin(const LLRect& bounds);
|
||||
|
||||
|
|
@ -658,8 +659,11 @@ public:
|
|||
// Draw debug rectangles around widgets to help with alignment and spacing
|
||||
static bool sDebugRects;
|
||||
|
||||
static bool sIsRectDirty;
|
||||
static LLRect sDirtyRect;
|
||||
// Show hexadecimal byte values of unicode symbols in a tooltip
|
||||
static bool sDebugUnicode;
|
||||
|
||||
static bool sIsRectDirty;
|
||||
static LLRect sDirtyRect;
|
||||
|
||||
// Draw widget names and sizes when drawing debug rectangles, turning this
|
||||
// off is useful to make the rectangles themselves easier to see.
|
||||
|
|
@ -702,19 +706,15 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co
|
|||
if (!result)
|
||||
{
|
||||
result = LLUICtrlFactory::getDefaultWidget<T>(name);
|
||||
if (!result)
|
||||
{
|
||||
LL_ERRS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
// *NOTE: You cannot call mFoo = getChild<LLFoo>("bar")
|
||||
// in a floater or panel constructor. The widgets will not
|
||||
// be ready. Instead, put it in postBuild().
|
||||
LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL;
|
||||
return NULL;
|
||||
}
|
||||
// *NOTE: You cannot call mFoo = getChild<LLFoo>("bar")
|
||||
// in a floater or panel constructor. The widgets will not
|
||||
// be ready. Instead, put it in postBuild().
|
||||
LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL;
|
||||
|
||||
getDefaultWidgetContainer().addChild(result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,37 +55,37 @@ public:
|
|||
class LLLeavesFilter : public LLQueryFilter, public LLSingleton<LLLeavesFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLLeavesFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;
|
||||
};
|
||||
|
||||
class LLRootsFilter : public LLQueryFilter, public LLSingleton<LLRootsFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLRootsFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;
|
||||
};
|
||||
|
||||
class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLVisibleFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;
|
||||
};
|
||||
|
||||
class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLEnabledFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;
|
||||
};
|
||||
|
||||
class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLTabStopFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;
|
||||
};
|
||||
|
||||
class LLCtrlFilter : public LLQueryFilter, public LLSingleton<LLCtrlFilter>
|
||||
{
|
||||
LLSINGLETON_EMPTY_CTOR(LLCtrlFilter);
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const;
|
||||
/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
|
|
|||
|
|
@ -733,23 +733,52 @@ attributedStringInfo getSegments(NSAttributedString *str)
|
|||
|
||||
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if (!mHasMarkedText)
|
||||
// SL-19801 Special workaround for system emoji picker
|
||||
if ([aString length] == 2)
|
||||
{
|
||||
for (NSInteger i = 0; i < [aString length]; i++)
|
||||
{
|
||||
callUnicodeCallback([aString characterAtIndex:i], mModifiers);
|
||||
}
|
||||
} else {
|
||||
resetPreedit();
|
||||
// We may never get this point since unmarkText may be called before insertText ever gets called once we submit our text.
|
||||
// But just in case...
|
||||
|
||||
for (NSInteger i = 0; i < [aString length]; i++)
|
||||
{
|
||||
handleUnicodeCharacter([aString characterAtIndex:i]);
|
||||
}
|
||||
mHasMarkedText = FALSE;
|
||||
@try
|
||||
{
|
||||
uint32_t b0 = [aString characterAtIndex:0];
|
||||
uint32_t b1 = [aString characterAtIndex:1];
|
||||
if (((b0 & 0xF000) == 0xD000) && ((b1 & 0xF000) == 0xD000))
|
||||
{
|
||||
uint32_t b = 0x10000 | ((b0 & 0x3F) << 10) | (b1 & 0x3FF);
|
||||
callUnicodeCallback(b, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@catch(NSException * e)
|
||||
{
|
||||
// One of the characters is an attribute string?
|
||||
NSLog(@"Encountered an unsupported attributed character. Exception: %@ String: %@", e.name, aString);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@try
|
||||
{
|
||||
if (!mHasMarkedText)
|
||||
{
|
||||
for (NSInteger i = 0; i < [aString length]; i++)
|
||||
{
|
||||
callUnicodeCallback([aString characterAtIndex:i], mModifiers);
|
||||
}
|
||||
} else {
|
||||
resetPreedit();
|
||||
// We may never get this point since unmarkText may be called before insertText ever gets called once we submit our text.
|
||||
// But just in case...
|
||||
|
||||
for (NSInteger i = 0; i < [aString length]; i++)
|
||||
{
|
||||
handleUnicodeCharacter([aString characterAtIndex:i]);
|
||||
}
|
||||
mHasMarkedText = FALSE;
|
||||
}
|
||||
}
|
||||
@catch(NSException * e)
|
||||
{
|
||||
NSLog(@"Failed to process an attributed string. Exception: %@ String: %@", e.name, aString);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) insertNewline:(id)sender
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ include(DragDrop)
|
|||
include(EXPAT)
|
||||
include(FMODSTUDIO)
|
||||
include(Hunspell)
|
||||
include(ICU4C)
|
||||
include(JPEGEncoderBasic)
|
||||
include(JsonCpp)
|
||||
include(LLAppearance)
|
||||
|
|
@ -207,6 +208,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterdisplayname.cpp
|
||||
llfloatereditenvironmentbase.cpp
|
||||
llfloatereditextdaycycle.cpp
|
||||
llfloateremojipicker.cpp
|
||||
llfloaterenvironmentadjust.cpp
|
||||
llfloaterevent.cpp
|
||||
llfloaterexperiencepicker.cpp
|
||||
|
|
@ -418,6 +420,7 @@ set(viewer_SOURCE_FILES
|
|||
llpaneleditsky.cpp
|
||||
llpaneleditwater.cpp
|
||||
llpaneleditwearable.cpp
|
||||
llpanelemojicomplete.cpp
|
||||
llpanelenvironment.cpp
|
||||
llpanelexperiencelisteditor.cpp
|
||||
llpanelexperiencelog.cpp
|
||||
|
|
@ -858,6 +861,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterdisplayname.h
|
||||
llfloatereditenvironmentbase.h
|
||||
llfloatereditextdaycycle.h
|
||||
llfloateremojipicker.h
|
||||
llfloaterenvironmentadjust.h
|
||||
llfloaterevent.h
|
||||
llfloaterexperiencepicker.h
|
||||
|
|
@ -1061,6 +1065,7 @@ set(viewer_HEADER_FILES
|
|||
llpaneleditsky.h
|
||||
llpaneleditwater.h
|
||||
llpaneleditwearable.h
|
||||
llpanelemojicomplete.h
|
||||
llpanelenvironment.h
|
||||
llpanelexperiencelisteditor.h
|
||||
llpanelexperiencelog.h
|
||||
|
|
@ -1927,6 +1932,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
|||
${LLPHYSICSEXTENSIONS_LIBRARIES}
|
||||
ll::bugsplat
|
||||
ll::tracy
|
||||
ll::icu4c
|
||||
)
|
||||
|
||||
if( TARGET ll::intel_memops )
|
||||
|
|
@ -1940,6 +1946,28 @@ endif()
|
|||
set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
|
||||
"Path to artwork files.")
|
||||
|
||||
message("Copying fonts")
|
||||
file(GLOB FONT_FILE_GLOB_LIST
|
||||
"${AUTOBUILD_INSTALL_DIR}/fonts/*"
|
||||
)
|
||||
file(COPY ${FONT_FILE_GLOB_LIST} DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/fonts")
|
||||
|
||||
# Copy over the Emoji/shortcodes mapping XML files (and create dependency
|
||||
# if they are changed, CMake will run again and copy over new versions)
|
||||
message("Copying Emoji/shortcode mappings")
|
||||
set(emoji_mapping_src_folder ${AUTOBUILD_INSTALL_DIR}/xui)
|
||||
set(emoji_mapping_dst_folder ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui)
|
||||
|
||||
# Note Turkey is missing from this set (not available in Emoji package yet)
|
||||
set(country_codes "da;de;en;es;fr;it;ja;pl;pt;ru;zh")
|
||||
foreach(elem ${country_codes})
|
||||
set(emoji_mapping_src_file
|
||||
"${emoji_mapping_src_folder}/${elem}/emoji_characters.xml")
|
||||
set(emoji_mapping_dst_file
|
||||
"${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml")
|
||||
configure_file(${emoji_mapping_src_file} ${emoji_mapping_dst_file} COPYONLY)
|
||||
endforeach()
|
||||
|
||||
if (LINUX)
|
||||
set(product SecondLife-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION})
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
7.1.3
|
||||
7.1.4
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -9521,7 +9521,7 @@
|
|||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>https://jira.secondlife.com/secure/CreateIssueDetails!init.jspa?pid=10610&issuetype=1&environment=[ENVIRONMENT]&customfield_10253=[LOCATION]</string>
|
||||
<string>https://feedback.secondlife.com/</string>
|
||||
</map>
|
||||
<key>RevokePermsOnStopAnimation</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -1,187 +0,0 @@
|
|||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
|
||||
Bitstream Vera Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute the
|
||||
Font Software, including without limitation the rights to use, copy, merge,
|
||||
publish, distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice shall
|
||||
be included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional glyphs or characters may be added to the Fonts, only if the fonts
|
||||
are renamed to names not containing either the words "Bitstream" or the word
|
||||
"Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or Font
|
||||
Software that has been modified and is distributed under the "Bitstream
|
||||
Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but no
|
||||
copy of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
||||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
||||
FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font Software
|
||||
without prior written authorization from the Gnome Foundation or Bitstream
|
||||
Inc., respectively. For further information, contact: fonts at gnome dot
|
||||
org.
|
||||
|
||||
Arev Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and
|
||||
associated documentation files (the "Font Software"), to reproduce
|
||||
and distribute the modifications to the Bitstream Vera Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Tavmjong Bah" or the word "Arev".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Tavmjong Bah Arev" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Tavmjong Bah shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Font Software without prior written authorization
|
||||
from Tavmjong Bah. For further information, contact: tavmjong @ free
|
||||
. fr.
|
||||
|
||||
TeX Gyre DJV Math
|
||||
-----------------
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
|
||||
Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski
|
||||
(on behalf of TeX users groups) are in public domain.
|
||||
|
||||
Letters imported from Euler Fraktur from AMSfonts are (c) American
|
||||
Mathematical Society (see below).
|
||||
Bitstream Vera Fonts Copyright
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera
|
||||
is a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license (“Fonts”) and associated
|
||||
documentation
|
||||
files (the “Font Software”), to reproduce and distribute the Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute,
|
||||
and/or sell copies of the Font Software, and to permit persons to whom
|
||||
the Font Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be
|
||||
included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional
|
||||
glyphs or characters may be added to the Fonts, only if the fonts are
|
||||
renamed
|
||||
to names not containing either the words “Bitstream” or the word “Vera”.
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or
|
||||
Font Software
|
||||
that has been modified and is distributed under the “Bitstream Vera”
|
||||
names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy
|
||||
of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
|
||||
SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN
|
||||
ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
|
||||
INABILITY TO USE
|
||||
THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Except as contained in this notice, the names of GNOME, the GNOME
|
||||
Foundation,
|
||||
and Bitstream Inc., shall not be used in advertising or otherwise to promote
|
||||
the sale, use or other dealings in this Font Software without prior written
|
||||
authorization from the GNOME Foundation or Bitstream Inc., respectively.
|
||||
For further information, contact: fonts at gnome dot org.
|
||||
|
||||
AMSFonts (v. 2.2) copyright
|
||||
|
||||
The PostScript Type 1 implementation of the AMSFonts produced by and
|
||||
previously distributed by Blue Sky Research and Y&Y, Inc. are now freely
|
||||
available for general use. This has been accomplished through the
|
||||
cooperation
|
||||
of a consortium of scientific publishers with Blue Sky Research and Y&Y.
|
||||
Members of this consortium include:
|
||||
|
||||
Elsevier Science IBM Corporation Society for Industrial and Applied
|
||||
Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS)
|
||||
|
||||
In order to assure the authenticity of these fonts, copyright will be
|
||||
held by
|
||||
the American Mathematical Society. This is not meant to restrict in any way
|
||||
the legitimate use of the fonts, such as (but not limited to) electronic
|
||||
distribution of documents containing these fonts, inclusion of these fonts
|
||||
into other public domain or commercial font collections or computer
|
||||
applications, use of the outline data to create derivative fonts and/or
|
||||
faces, etc. However, the AMS does require that the AMS copyright notice be
|
||||
removed from any derivative versions of the fonts which have been altered in
|
||||
any way. In addition, to ensure the fidelity of TeX documents using Computer
|
||||
Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces,
|
||||
has requested that any alterations which yield different font metrics be
|
||||
given a different name.
|
||||
|
||||
$Id$
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -203,7 +203,7 @@ public:
|
|||
void setSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
private:
|
||||
/*virtual*/ void initSingleton();
|
||||
/*virtual*/ void initSingleton() override;
|
||||
|
||||
LLAutoReplaceSettings mSettings; ///< configuration information
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class LLChannelManager : public LLSingleton<LLChannelManager>
|
|||
LLSINGLETON(LLChannelManager);
|
||||
virtual ~LLChannelManager();
|
||||
|
||||
void cleanupSingleton();
|
||||
void cleanupSingleton() override;
|
||||
public:
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1096,6 +1096,8 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
|
|||
editor_params.enabled = false; // read only
|
||||
editor_params.show_context_menu = "true";
|
||||
editor_params.trusted_content = false;
|
||||
editor_params.text_valign = LLFontGL::VAlign::VCENTER;
|
||||
editor_params.use_color = true;
|
||||
mEditor = LLUICtrlFactory::create<LLTextEditor>(editor_params, this);
|
||||
mEditor->setIsFriendCallback(LLAvatarActions::isFriend);
|
||||
mEditor->setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0));
|
||||
|
|
@ -1213,9 +1215,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
|
||||
llassert(mEditor);
|
||||
if (!mEditor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool from_me = chat.mFromID == gAgent.getID();
|
||||
mEditor->setPlainText(use_plain_text_chat_history);
|
||||
|
|
@ -1225,26 +1225,16 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
mUnreadChatSources.insert(chat.mFromName);
|
||||
mMoreChatPanel->setVisible(TRUE);
|
||||
std::string chatters;
|
||||
for (unread_chat_source_t::iterator it = mUnreadChatSources.begin();
|
||||
it != mUnreadChatSources.end();)
|
||||
for (const std::string& source : mUnreadChatSources)
|
||||
{
|
||||
chatters += *it;
|
||||
if (++it != mUnreadChatSources.end())
|
||||
{
|
||||
chatters += ", ";
|
||||
}
|
||||
chatters += chatters.size() ? ", " + source : source;
|
||||
}
|
||||
LLStringUtil::format_map_t args;
|
||||
args["SOURCES"] = chatters;
|
||||
|
||||
if (mUnreadChatSources.size() == 1)
|
||||
{
|
||||
mMoreChatText->setValue(LLTrans::getString("unread_chat_single", args));
|
||||
}
|
||||
else
|
||||
{
|
||||
mMoreChatText->setValue(LLTrans::getString("unread_chat_multiple", args));
|
||||
}
|
||||
std::string xml_desc = mUnreadChatSources.size() == 1 ?
|
||||
"unread_chat_single" : "unread_chat_multiple";
|
||||
mMoreChatText->setValue(LLTrans::getString(xml_desc, args));
|
||||
S32 height = mMoreChatText->getTextPixelHeight() + 5;
|
||||
mMoreChatPanel->reshape(mMoreChatPanel->getRect().getWidth(), height);
|
||||
}
|
||||
|
|
@ -1292,11 +1282,11 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
body_message_params.font.style = "ITALIC";
|
||||
}
|
||||
|
||||
if(chat.mChatType == CHAT_TYPE_WHISPER)
|
||||
if (chat.mChatType == CHAT_TYPE_WHISPER)
|
||||
{
|
||||
body_message_params.font.style = "ITALIC";
|
||||
}
|
||||
else if(chat.mChatType == CHAT_TYPE_SHOUT)
|
||||
else if (chat.mChatType == CHAT_TYPE_SHOUT)
|
||||
{
|
||||
body_message_params.font.style = "BOLD";
|
||||
}
|
||||
|
|
@ -1343,10 +1333,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
}
|
||||
|
||||
// names showing
|
||||
if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size() != 0)
|
||||
if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size())
|
||||
{
|
||||
// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text.
|
||||
if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
|
||||
if (chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())
|
||||
{
|
||||
// for object IMs, create a secondlife:///app/objectim SLapp
|
||||
std::string url = LLViewerChat::getSenderSLURL(chat, args);
|
||||
|
|
@ -1406,36 +1396,27 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
&& mIsLastMessageFromLog == message_from_log) //distinguish between current and previous chat session's histories
|
||||
{
|
||||
view = getSeparator();
|
||||
p.top_pad = mTopSeparatorPad;
|
||||
p.bottom_pad = mBottomSeparatorPad;
|
||||
if (!view)
|
||||
{
|
||||
// Might be wiser to make this LL_ERRS, getSeparator() should work in case of correct instalation.
|
||||
LL_WARNS() << "Failed to create separator from " << mMessageSeparatorFilename << ": can't append to history" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
p.top_pad = mTopSeparatorPad;
|
||||
p.bottom_pad = mBottomSeparatorPad;
|
||||
}
|
||||
else
|
||||
{
|
||||
view = getHeader(chat, name_params, args);
|
||||
if (mEditor->getLength() == 0)
|
||||
p.top_pad = 0;
|
||||
else
|
||||
p.top_pad = mTopHeaderPad;
|
||||
if (teleport_separator)
|
||||
{
|
||||
p.bottom_pad = mBottomSeparatorPad;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.bottom_pad = mBottomHeaderPad;
|
||||
}
|
||||
if (!view)
|
||||
{
|
||||
LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
if (!view)
|
||||
{
|
||||
LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
p.top_pad = mEditor->getLength() ? mTopHeaderPad : 0;
|
||||
p.bottom_pad = teleport_separator ? mBottomSeparatorPad : mBottomHeaderPad;
|
||||
}
|
||||
p.view = view;
|
||||
|
||||
|
|
@ -1508,11 +1489,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
|
|||
}
|
||||
}
|
||||
// usual messages showing
|
||||
else if(!teleport_separator)
|
||||
else if (!teleport_separator)
|
||||
{
|
||||
std::string message = irc_me ? chat.mText.substr(3) : chat.mText;
|
||||
|
||||
|
||||
//MESSAGE TEXT PROCESSING
|
||||
//*HACK getting rid of redundant sender names in system notifications sent using sender name (see EXT-5010)
|
||||
if (use_plain_text_chat_history && !from_me && chat.mFromID.notNull())
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ class LLChicletBar
|
|||
|
||||
public:
|
||||
|
||||
BOOL postBuild();
|
||||
BOOL postBuild() override;
|
||||
|
||||
LLChicletPanel* getChicletPanel() { return mChicletPanel; }
|
||||
|
||||
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
|
||||
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent) override;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -125,11 +125,11 @@ public:
|
|||
void removeObserver(LLConversationLogObserver* observer);
|
||||
|
||||
// LLIMSessionObserver triggers
|
||||
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg);
|
||||
virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}; // Stub
|
||||
virtual void sessionRemoved(const LLUUID& session_id){} // Stub
|
||||
virtual void sessionVoiceOrIMStarted(const LLUUID& session_id){}; // Stub
|
||||
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id){}; // Stub
|
||||
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg) override;
|
||||
virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) override {}; // Stub
|
||||
virtual void sessionRemoved(const LLUUID& session_id) override{} // Stub
|
||||
virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) override{}; // Stub
|
||||
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) override{}; // Stub
|
||||
|
||||
void notifyObservers();
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public:
|
|||
mStyle->getShadowType(),
|
||||
end - start, draw_rect.getWidth(),
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(), mEditor.getUseColor());
|
||||
return right_x;
|
||||
}
|
||||
/*virtual*/ bool canEdit() const { return false; }
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class LLFeatureManager : public LLFeatureList, public LLSingleton<LLFeatureManag
|
|||
~LLFeatureManager() {cleanupFeatureTables();}
|
||||
|
||||
// initialize this by loading feature table and gpu table
|
||||
void initSingleton();
|
||||
void initSingleton() override;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -737,7 +737,6 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)
|
||||
{
|
||||
getChildView("Find")->setEnabled(caller->getText().size() > 0);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* @file llfloateremojipicker.h
|
||||
* @brief Header file for llfloateremojipicker
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, 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$
|
||||
*/
|
||||
|
||||
#ifndef LLFLOATEREMOJIPICKER_H
|
||||
#define LLFLOATEREMOJIPICKER_H
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLEmojiGridRow;
|
||||
class LLEmojiGridIcon;
|
||||
struct LLEmojiDescriptor;
|
||||
struct LLEmojiSearchResult;
|
||||
|
||||
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;
|
||||
|
||||
LLFloaterEmojiPicker(const LLSD& key);
|
||||
|
||||
virtual BOOL postBuild() override;
|
||||
virtual void dirtyRect() override;
|
||||
virtual void goneFromFront() override;
|
||||
|
||||
void hideFloater() const;
|
||||
|
||||
static std::list<llwchar>& getRecentlyUsed();
|
||||
static void onEmojiUsed(llwchar emoji);
|
||||
|
||||
static void loadState();
|
||||
static void saveState();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
void fillGroups();
|
||||
void fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);
|
||||
void fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);
|
||||
void fillGroupEmojis(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats, U32 index);
|
||||
void createGroupButton(LLButton::Params& params, const LLRect& rect, llwchar emoji);
|
||||
void resizeGroupButtons();
|
||||
void selectEmojiGroup(U32 index);
|
||||
void fillEmojis(bool fromResize = false);
|
||||
void fillEmojisCategory(const std::vector<LLEmojiSearchResult>& emojis,
|
||||
const std::string& category, const LLPanel::Params& row_panel_params, const LLUICtrl::Params& row_list_params,
|
||||
const LLPanel::Params& icon_params, const LLRect& icon_rect, S32 max_icons, const LLColor4& bg);
|
||||
void createEmojiIcon(const LLEmojiSearchResult& emoji,
|
||||
const std::string& category, const LLPanel::Params& row_panel_params, const LLUICtrl::Params& row_list_params,
|
||||
const LLPanel::Params& icon_params, const LLRect& icon_rect, S32 max_icons, const LLColor4& bg,
|
||||
LLEmojiGridRow*& row, int& icon_index);
|
||||
void showPreview(bool show);
|
||||
|
||||
void onGroupButtonClick(LLUICtrl* ctrl);
|
||||
void onGroupButtonMouseEnter(LLUICtrl* ctrl);
|
||||
void onGroupButtonMouseLeave(LLUICtrl* ctrl);
|
||||
void onEmojiMouseEnter(LLUICtrl* ctrl);
|
||||
void onEmojiMouseLeave(LLUICtrl* ctrl);
|
||||
void onEmojiMouseDown(LLUICtrl* ctrl);
|
||||
void onEmojiMouseUp(LLUICtrl* ctrl);
|
||||
|
||||
void selectFocusedIcon();
|
||||
bool moveFocusedIconUp();
|
||||
bool moveFocusedIconDown();
|
||||
bool moveFocusedIconPrev();
|
||||
bool moveFocusedIconNext();
|
||||
|
||||
void selectGridIcon(LLEmojiGridIcon* icon);
|
||||
void unselectGridIcon(LLEmojiGridIcon* icon);
|
||||
|
||||
void onOpen(const LLSD& key) override;
|
||||
virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override;
|
||||
|
||||
class LLPanel* mGroups { nullptr };
|
||||
class LLPanel* mBadge { nullptr };
|
||||
class LLScrollContainer* mEmojiScroll { nullptr };
|
||||
class LLScrollingPanelList* mEmojiGrid { nullptr };
|
||||
class LLEmojiPreviewPanel* mPreview { nullptr };
|
||||
class LLTextBox* mDummy { nullptr };
|
||||
|
||||
std::vector<S32> mFilteredEmojiGroups;
|
||||
std::vector<std::map<std::string, std::vector<LLEmojiSearchResult>>> mFilteredEmojis;
|
||||
std::vector<class LLButton*> mGroupButtons;
|
||||
|
||||
std::string mHint;
|
||||
std::string mFilterPattern;
|
||||
U32 mSelectedGroupIndex { 0 };
|
||||
S32 mRecentMaxIcons { 0 };
|
||||
S32 mFocusedIconRow { 0 };
|
||||
S32 mFocusedIconCol { 0 };
|
||||
LLEmojiGridIcon* mFocusedIcon { nullptr };
|
||||
LLEmojiGridIcon* mHoveredIcon { nullptr };
|
||||
|
||||
U64 mRecentReturnPressedMs { 0 };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -130,11 +130,12 @@ BOOL LLFloaterIMNearbyChat::postBuild()
|
|||
mInputEditor->setKeystrokeCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxKeystroke, this));
|
||||
mInputEditor->setFocusLostCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusLost, this));
|
||||
mInputEditor->setFocusReceivedCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusReceived, this));
|
||||
mInputEditor->setLabel(LLTrans::getString("NearbyChatTitle"));
|
||||
std::string nearbyChatTitle(LLTrans::getString("NearbyChatTitle"));
|
||||
mInputEditor->setLabel(nearbyChatTitle);
|
||||
|
||||
// Title must be defined BEFORE call to addConversationListItem() because
|
||||
// it is used to show the item's name in the conversations list
|
||||
setTitle(LLTrans::getString("NearbyChatTitle"));
|
||||
setTitle(nearbyChatTitle);
|
||||
|
||||
// obsolete, but may be needed for backward compatibility?
|
||||
gSavedSettings.declareS32("nearbychat_showicons_and_names", 2, "NearByChat header settings", LLControlVariable::PERSIST_NONDFT);
|
||||
|
|
@ -591,6 +592,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;
|
||||
|
|
|
|||
|
|
@ -249,6 +249,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,18 +33,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");
|
||||
|
|
@ -56,7 +59,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),
|
||||
|
|
@ -75,7 +78,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",
|
||||
|
|
@ -88,12 +91,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()
|
||||
|
|
@ -101,7 +104,7 @@ LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
|
|||
delete mRefreshTimer;
|
||||
}
|
||||
|
||||
//static
|
||||
// static
|
||||
LLFloaterIMSessionTab* LLFloaterIMSessionTab::findConversation(const LLUUID& uuid)
|
||||
{
|
||||
LLFloaterIMSessionTab* conv;
|
||||
|
|
@ -118,7 +121,7 @@ LLFloaterIMSessionTab* LLFloaterIMSessionTab::findConversation(const LLUUID& uui
|
|||
return conv;
|
||||
};
|
||||
|
||||
//static
|
||||
// static
|
||||
LLFloaterIMSessionTab* LLFloaterIMSessionTab::getConversation(const LLUUID& uuid)
|
||||
{
|
||||
LLFloaterIMSessionTab* conv;
|
||||
|
|
@ -134,14 +137,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);
|
||||
}
|
||||
|
|
@ -155,27 +160,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))
|
||||
|
|
@ -220,42 +224,60 @@ 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));
|
||||
|
||||
mEmojiRecentPanelToggleBtn = getChild<LLButton>("emoji_recent_panel_toggle_btn");
|
||||
mEmojiRecentPanelToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiRecentPanelToggleBtnClicked(); });
|
||||
|
||||
mEmojiRecentPanel = getChild<LLLayoutPanel>("emoji_recent_layout_panel");
|
||||
mEmojiRecentPanel->setVisible(false);
|
||||
|
||||
mEmojiRecentEmptyText = getChild<LLTextBox>("emoji_recent_empty_text");
|
||||
mEmojiRecentEmptyText->setToolTip(mEmojiRecentEmptyText->getText());
|
||||
mEmojiRecentEmptyText->setVisible(false);
|
||||
|
||||
mEmojiRecentIconsCtrl = getChild<LLPanelEmojiComplete>("emoji_recent_icons_ctrl");
|
||||
mEmojiRecentIconsCtrl->setCommitCallback([this](LLUICtrl*, const LLSD& value) { onRecentEmojiPicked(value); });
|
||||
mEmojiRecentIconsCtrl->setVisible(false);
|
||||
|
||||
mEmojiPickerShowBtn = getChild<LLButton>("emoji_picker_show_btn");
|
||||
mEmojiPickerShowBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnClicked(); });
|
||||
|
||||
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");
|
||||
mRightPartPanel = getChild<LLLayoutPanel>("right_part_holder");
|
||||
|
||||
|
|
@ -307,17 +329,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);
|
||||
|
|
@ -357,6 +379,7 @@ LLParticipantList* LLFloaterIMSessionTab::getParticipantList()
|
|||
return dynamic_cast<LLParticipantList*>(LLFloaterIMContainer::getInstance()->getSessionModel(mSessionID));
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLFloaterIMSessionTab::draw()
|
||||
{
|
||||
if (mRefreshTimer->hasExpired())
|
||||
|
|
@ -381,23 +404,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);
|
||||
|
|
@ -407,13 +431,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()
|
||||
|
|
@ -426,53 +451,130 @@ void LLFloaterIMSessionTab::onInputEditorClicked()
|
|||
gToolBarView->flashCommand(LLCommandId("chat"), false);
|
||||
}
|
||||
|
||||
void LLFloaterIMSessionTab::onEmojiRecentPanelToggleBtnClicked()
|
||||
{
|
||||
BOOL show = mEmojiRecentPanel->getVisible() ? FALSE : TRUE;
|
||||
if (show)
|
||||
{
|
||||
initEmojiRecentPanel();
|
||||
}
|
||||
|
||||
mEmojiRecentPanel->setVisible(show);
|
||||
mInputEditor->setFocus(TRUE);
|
||||
}
|
||||
|
||||
void LLFloaterIMSessionTab::onEmojiPickerShowBtnClicked()
|
||||
{
|
||||
mInputEditor->setFocus(TRUE);
|
||||
mInputEditor->showEmojiHelper();
|
||||
}
|
||||
|
||||
void LLFloaterIMSessionTab::initEmojiRecentPanel()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
mInputEditor->insertEmoji(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterIMSessionTab::closeFloater(bool app_quitting)
|
||||
{
|
||||
LLFloaterEmojiPicker::saveState();
|
||||
super::closeFloater(app_quitting);
|
||||
}
|
||||
|
||||
std::string LLFloaterIMSessionTab::appendTime()
|
||||
{
|
||||
time_t utc_time;
|
||||
utc_time = time_corrected();
|
||||
std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:["
|
||||
+LLTrans::getString("TimeMin")+"]";
|
||||
std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:"
|
||||
"[" + LLTrans::getString("TimeMin") + "]";
|
||||
|
||||
LLSD substitution;
|
||||
|
||||
substitution["datetime"] = (S32) utc_time;
|
||||
LLStringUtil::format (timeStr, substitution);
|
||||
substitution["datetime"] = (S32)time_corrected();
|
||||
LLStringUtil::format(timeStr, substitution);
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
|
||||
void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD &args)
|
||||
void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD& args)
|
||||
{
|
||||
if (chat.mMuted || !mChatHistory)
|
||||
return;
|
||||
|
||||
// Update the participant activity time
|
||||
LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance();
|
||||
if (im_box)
|
||||
{
|
||||
im_box->setTimeNow(mSessionID,chat.mFromID);
|
||||
im_box->setTimeNow(mSessionID, chat.mFromID);
|
||||
}
|
||||
|
||||
|
||||
LLChat& tmp_chat = const_cast<LLChat&>(chat);
|
||||
|
||||
if(tmp_chat.mTimeStr.empty())
|
||||
if (tmp_chat.mTimeStr.empty())
|
||||
tmp_chat.mTimeStr = appendTime();
|
||||
|
||||
if (!chat.mMuted)
|
||||
{
|
||||
tmp_chat.mFromName = chat.mFromName;
|
||||
LLSD chat_args;
|
||||
if (args) chat_args = args;
|
||||
chat_args["use_plain_text_chat_history"] =
|
||||
gSavedSettings.getBOOL("PlainTextChatHistory");
|
||||
chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime");
|
||||
chat_args["show_names_for_p2p_conv"] =
|
||||
!mIsP2PChat || gSavedSettings.getBOOL("IMShowNamesForP2PConv");
|
||||
tmp_chat.mFromName = chat.mFromName;
|
||||
|
||||
if (mChatHistory)
|
||||
{
|
||||
mChatHistory->appendMessage(chat, chat_args);
|
||||
}
|
||||
}
|
||||
LLSD chat_args = args;
|
||||
chat_args["use_plain_text_chat_history"] =
|
||||
gSavedSettings.getBOOL("PlainTextChatHistory");
|
||||
chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime");
|
||||
chat_args["show_names_for_p2p_conv"] = !mIsP2PChat ||
|
||||
gSavedSettings.getBOOL("IMShowNamesForP2PConv");
|
||||
|
||||
mChatHistory->appendMessage(chat, chat_args);
|
||||
}
|
||||
|
||||
void LLFloaterIMSessionTab::updateUsedEmojis(LLWString text)
|
||||
{
|
||||
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
|
||||
llassert_always(dictionary);
|
||||
|
||||
bool emojiSent = false;
|
||||
for (llwchar& c : text)
|
||||
{
|
||||
if (dictionary->isEmoji(c))
|
||||
{
|
||||
LLFloaterEmojiPicker::onEmojiUsed(c);
|
||||
emojiSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emojiSent)
|
||||
return;
|
||||
|
||||
LLFloaterEmojiPicker::saveState();
|
||||
|
||||
if (mEmojiRecentPanel->getVisible())
|
||||
{
|
||||
initEmojiRecentPanel();
|
||||
}
|
||||
}
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT("Build Conversation View");
|
||||
|
|
@ -502,10 +604,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++;
|
||||
}
|
||||
}
|
||||
|
|
@ -525,10 +627,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
|
||||
{
|
||||
|
|
@ -578,11 +680,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)
|
||||
|
|
@ -638,7 +740,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();
|
||||
|
|
@ -766,7 +868,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)
|
||||
|
|
@ -783,12 +885,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?
|
||||
|
|
@ -817,10 +919,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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -846,7 +948,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -892,15 +994,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -937,12 +1039,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);
|
||||
|
|
@ -967,7 +1069,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);
|
||||
|
|
@ -995,8 +1097,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");
|
||||
|
||||
|
|
@ -1086,8 +1188,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
|
||||
|
|
@ -1099,8 +1201,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
|
||||
|
|
@ -1111,8 +1213,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
|
||||
|
|
@ -1122,19 +1224,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()
|
||||
|
|
@ -1142,8 +1244,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()) ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,10 +41,12 @@
|
|||
class LLPanelChatControlPanel;
|
||||
class LLChatEntry;
|
||||
class LLChatHistory;
|
||||
class LLPanelEmojiComplete;
|
||||
|
||||
class LLFloaterIMSessionTab
|
||||
: public LLTransientDockableFloater
|
||||
{
|
||||
using super = LLTransientDockableFloater;
|
||||
|
||||
public:
|
||||
LOG_CLASS(LLFloaterIMSessionTab);
|
||||
|
|
@ -68,9 +70,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;}
|
||||
|
||||
|
|
@ -80,6 +81,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);
|
||||
|
|
@ -136,15 +138,17 @@ 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 = 0);
|
||||
void appendMessage(const LLChat& chat, const LLSD& args = LLSD());
|
||||
|
||||
std::string appendTime();
|
||||
void assignResizeLimits();
|
||||
|
||||
void updateUsedEmojis(LLWString text);
|
||||
|
||||
S32 mFloaterExtraWidth;
|
||||
|
||||
bool mIsNearbyChat;
|
||||
|
|
@ -152,8 +156,7 @@ protected:
|
|||
|
||||
bool mMessagePaneExpanded;
|
||||
bool mIsParticipantListExpanded;
|
||||
S32 mMinFloaterHeight;
|
||||
|
||||
S32 mMinFloaterHeight;
|
||||
|
||||
LLIMModel::LLIMSession* mSession;
|
||||
|
||||
|
|
@ -168,32 +171,37 @@ protected:
|
|||
LLLayoutPanel* mContentPanel;
|
||||
LLLayoutPanel* mToolbarPanel;
|
||||
LLLayoutPanel* mInputButtonPanel;
|
||||
LLLayoutPanel* mEmojiRecentPanel;
|
||||
LLTextBox* 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* mEmojiRecentPanelToggleBtn;
|
||||
LLButton* mEmojiPickerShowBtn;
|
||||
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;
|
||||
|
|
@ -207,9 +215,14 @@ private:
|
|||
|
||||
void onInputEditorClicked();
|
||||
|
||||
void onEmojiRecentPanelToggleBtnClicked();
|
||||
void onEmojiPickerShowBtnClicked();
|
||||
void initEmojiRecentPanel();
|
||||
void onRecentEmojiPicked(const LLSD& value);
|
||||
|
||||
bool checkIfTornOff();
|
||||
bool mIsHostAttached;
|
||||
bool mHasVisibleBeenInitialized;
|
||||
bool mIsHostAttached;
|
||||
bool mHasVisibleBeenInitialized;
|
||||
|
||||
LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
|
||||
|
||||
|
|
|
|||
|
|
@ -1601,7 +1601,7 @@ void LLOverlapPanel::draw()
|
|||
LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5
|
||||
LLView::sDrawPreviewHighlights = FALSE;
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1619,7 +1619,7 @@ void LLOverlapPanel::draw()
|
|||
std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)");
|
||||
S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10;
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
|
||||
// widen panel enough to fit this text
|
||||
LLRect rect = getRect();
|
||||
setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop));
|
||||
|
|
@ -1685,7 +1685,7 @@ void LLOverlapPanel::draw()
|
|||
// draw currently-selected element at top of overlappers
|
||||
LLUI::translate(0,-mSpacing);
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
|
||||
LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height
|
||||
LLView::sPreviewClickedElement->draw();
|
||||
|
||||
|
|
@ -1700,7 +1700,7 @@ void LLOverlapPanel::draw()
|
|||
// draw name
|
||||
LLUI::translate(0,-mSpacing);
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW);
|
||||
|
||||
// draw element
|
||||
LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public:
|
|||
};
|
||||
|
||||
// LLFriendObserver implementation
|
||||
void changed(U32 mask)
|
||||
void changed(U32 mask) override
|
||||
{
|
||||
onFriendListUpdate(mask);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public:
|
|||
void notifyObservers();
|
||||
|
||||
// Overriding so we can update active gesture names and notify observers
|
||||
void changed(U32 mask);
|
||||
void changed(U32 mask) override;
|
||||
|
||||
BOOL matchPrefix(const std::string& in_str, std::string* out_str);
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ protected:
|
|||
void runStep(LLMultiGesture* gesture, LLGestureStep* step);
|
||||
|
||||
// LLInventoryCompletionObserver trigger
|
||||
void done();
|
||||
void done() override;
|
||||
|
||||
// Used by loadGesture
|
||||
static void onLoadComplete(const LLUUID& asset_uuid,
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
|
|||
LLUI::translate((F32) winX*1.0f/LLFontGL::sScaleX, (F32) winY*1.0f/(LLFontGL::sScaleY), -(((F32) winZ*2.f)-1.f));
|
||||
F32 right_x;
|
||||
|
||||
font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x);
|
||||
font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x, /*use_ellipses*/false, /*use_color*/true);
|
||||
|
||||
LLUI::popMatrix();
|
||||
gGL.popMatrix();
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ private:
|
|||
void loadAllFilters();
|
||||
void loadFiltersFromDir(const std::string& dir);
|
||||
|
||||
/*virtual*/ void initSingleton();
|
||||
/*virtual*/ void initSingleton() override;
|
||||
|
||||
// List of filters : first is the user friendly localized name, second is the xml file name
|
||||
std::map<std::string,std::string> mFiltersList;
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ public:
|
|||
static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent);
|
||||
|
||||
private:
|
||||
void initSingleton();
|
||||
void initSingleton() override;
|
||||
void onVoiceChannelChangedInt(const LLUUID &session_id);
|
||||
void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent);
|
||||
|
||||
|
|
|
|||
|
|
@ -2548,11 +2548,17 @@ void LLInventoryGallery::startDrag()
|
|||
{
|
||||
std::vector<EDragAndDropType> types;
|
||||
uuid_vec_t ids;
|
||||
LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_AGENT;
|
||||
for (LLUUID& selected_id : mSelectedItemIDs)
|
||||
{
|
||||
const LLInventoryItem* item = gInventory.getItem(selected_id);
|
||||
if (item)
|
||||
{
|
||||
if (item->getPermissions().getOwner() == ALEXANDRIA_LINDEN_ID)
|
||||
{
|
||||
src = LLToolDragAndDrop::SOURCE_LIBRARY;
|
||||
}
|
||||
|
||||
EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(item->getType());
|
||||
types.push_back(type);
|
||||
ids.push_back(selected_id);
|
||||
|
|
@ -2562,12 +2568,17 @@ void LLInventoryGallery::startDrag()
|
|||
if (cat && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID())
|
||||
&& !LLFolderType::lookupIsProtectedType((cat)->getPreferredType()))
|
||||
{
|
||||
if (cat->getOwnerID() == ALEXANDRIA_LINDEN_ID)
|
||||
{
|
||||
src = LLToolDragAndDrop::SOURCE_LIBRARY;
|
||||
}
|
||||
|
||||
EDragAndDropType type = LLViewerAssetType::lookupDragAndDropType(cat->getType());
|
||||
types.push_back(type);
|
||||
ids.push_back(selected_id);
|
||||
}
|
||||
}
|
||||
LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, LLToolDragAndDrop::SOURCE_AGENT);
|
||||
LLToolDragAndDrop::getInstance()->beginMultiDrag(types, ids, src);
|
||||
}
|
||||
|
||||
bool LLInventoryGallery::areViewsInitialized()
|
||||
|
|
|
|||
|
|
@ -2228,7 +2228,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial()
|
|||
LLSelectedTEGetMatData func(true);
|
||||
LLPermissions permissions;
|
||||
LLViewerInventoryItem* item_out;
|
||||
return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out);
|
||||
return can_use_objects_material(func, std::vector<PermissionBit>({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out);
|
||||
}
|
||||
|
||||
bool LLMaterialEditor::canSaveObjectsMaterial()
|
||||
|
|
@ -2236,7 +2236,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial()
|
|||
LLSelectedTEGetMatData func(true);
|
||||
LLPermissions permissions;
|
||||
LLViewerInventoryItem* item_out;
|
||||
return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out);
|
||||
return can_use_objects_material(func, std::vector<PermissionBit>({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out);
|
||||
}
|
||||
|
||||
bool LLMaterialEditor::canClipboardObjectsMaterial()
|
||||
|
|
@ -2262,7 +2262,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial()
|
|||
LLSelectedTEGetMatData func(true);
|
||||
LLPermissions permissions;
|
||||
LLViewerInventoryItem* item_out;
|
||||
return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out);
|
||||
return can_use_objects_material(func, std::vector<PermissionBit>({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out);
|
||||
}
|
||||
|
||||
void LLMaterialEditor::saveObjectsMaterialAs()
|
||||
|
|
@ -2270,7 +2270,7 @@ void LLMaterialEditor::saveObjectsMaterialAs()
|
|||
LLSelectedTEGetMatData func(true);
|
||||
LLPermissions permissions;
|
||||
LLViewerInventoryItem* item = nullptr;
|
||||
bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item);
|
||||
bool allowed = can_use_objects_material(func, std::vector<PermissionBit>({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item);
|
||||
if (!allowed)
|
||||
{
|
||||
LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class LLMuteList : public LLSingleton<LLMuteList>
|
|||
{
|
||||
LLSINGLETON(LLMuteList);
|
||||
~LLMuteList();
|
||||
/*virtual*/ void cleanupSingleton();
|
||||
/*virtual*/ void cleanupSingleton() override;
|
||||
public:
|
||||
// reasons for auto-unmuting a resident
|
||||
enum EAutoReason
|
||||
|
|
|
|||
|
|
@ -92,10 +92,10 @@ class LLNavigationBar
|
|||
|
||||
public:
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void setVisible(BOOL visible);
|
||||
/*virtual*/ void draw() override;
|
||||
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
/*virtual*/ BOOL postBuild() override;
|
||||
/*virtual*/ void setVisible(BOOL visible) override;
|
||||
|
||||
void handleLoginComplete();
|
||||
void clearHistoryCache();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue