Merge branch 'master' of https://bitbucket.org/Ansariel/phoenix-firestorm-gltf-maint2
commit
d1a0841f6c
|
|
@ -23,3 +23,4 @@ jobs:
|
|||
path-to-signatures: signatures.json
|
||||
remote-organization-name: secondlife
|
||||
remote-repository-name: cla-signatures
|
||||
allowlist: callum@mbp.localdomain
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ indra/newview/dbghelp.dll
|
|||
indra/newview/filters.xml
|
||||
indra/newview/fmod.dll
|
||||
indra/newview/fmod.log
|
||||
#indra/newview/fonts # <FS:Ansariel> Don't copy fonts to the source folder
|
||||
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
|
||||
|
|
|
|||
322
autobuild.xml
322
autobuild.xml
|
|
@ -530,11 +530,11 @@
|
|||
<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>
|
||||
|
|
@ -556,11 +556,11 @@
|
|||
<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>
|
||||
|
|
@ -573,7 +573,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>
|
||||
|
|
@ -634,11 +634,11 @@
|
|||
<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>
|
||||
|
|
@ -660,11 +660,11 @@
|
|||
<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>
|
||||
|
|
@ -677,7 +677,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>
|
||||
|
|
@ -885,6 +885,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>
|
||||
|
|
@ -1035,6 +1079,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>
|
||||
|
|
@ -1042,11 +1096,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>
|
||||
|
|
@ -1056,9 +1110,11 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>41db760508e6b48ae3a291ad2d1aef3d</string>
|
||||
<string>4a999279562e8f3e4ba02d3e78a844ddf6fe18f1</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://3p.firestormviewer.org/freetype-2.8.1.223020901-linux64-223020901.tar.bz2</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>
|
||||
|
|
@ -1068,26 +1124,18 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>2c2151b439cf92e03d9573dddbbdd3b6</string>
|
||||
<string>1837fdfd44204c78e79134944f824b0211817883</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://3p.firestormviewer.org/freetype-2.3.9.232991153-windows64-232991153.tar.bz2</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>
|
||||
|
|
@ -1162,11 +1210,11 @@
|
|||
<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>
|
||||
|
|
@ -1188,11 +1236,11 @@
|
|||
<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>
|
||||
|
|
@ -1205,7 +1253,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>
|
||||
|
|
@ -1301,6 +1349,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>
|
||||
|
|
@ -2202,6 +2298,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>
|
||||
|
|
@ -2909,6 +3061,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>
|
||||
|
|
@ -3224,7 +3418,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>
|
||||
|
|
@ -3244,11 +3438,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>
|
||||
|
|
@ -3265,7 +3459,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>
|
||||
|
|
@ -3285,11 +3479,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>
|
||||
|
|
@ -3492,11 +3686,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>
|
||||
|
|
@ -3526,7 +3720,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>-G</string>
|
||||
<string>Xcode</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3556,11 +3750,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>
|
||||
|
|
@ -3586,7 +3780,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<array>
|
||||
<string>-G</string>
|
||||
<string>Xcode</string>
|
||||
</array>
|
||||
</array>
|
||||
</map>
|
||||
<key>build</key>
|
||||
<map>
|
||||
|
|
@ -3717,11 +3911,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>
|
||||
|
|
@ -3744,7 +3938,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>
|
||||
|
|
@ -3876,11 +4070,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>
|
||||
|
|
@ -3890,11 +4084,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>
|
||||
<!-- FS:Ansariel: This will cause packages being installed twice
|
||||
<key>default</key>
|
||||
|
|
@ -3916,11 +4110,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>
|
||||
|
|
@ -3934,11 +4128,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>
|
||||
|
|
@ -3953,11 +4147,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>
|
||||
|
|
@ -3967,11 +4161,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>
|
||||
|
|
@ -3990,11 +4184,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>
|
||||
|
|
@ -4008,11 +4202,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>
|
||||
|
|
@ -4190,4 +4384,4 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<string>Firestorm Viewer</string>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
</llsd>
|
||||
|
|
|
|||
|
|
@ -241,6 +241,8 @@ Ansariel Hiller
|
|||
SL-15398
|
||||
SL-18432
|
||||
SL-19140
|
||||
SL-19575
|
||||
SL-19623
|
||||
SL-4126
|
||||
SL-20224
|
||||
Aralara Rajal
|
||||
|
|
@ -904,6 +906,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
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ set(cmake_SOURCE_FILES
|
|||
GoogleMock.cmake
|
||||
Havok.cmake
|
||||
Hunspell.cmake
|
||||
ICU4C.cmake
|
||||
JsonCpp.cmake
|
||||
LLAddBuildTest.cmake
|
||||
LLAppearance.cmake
|
||||
|
|
|
|||
|
|
@ -63,6 +63,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)
|
||||
|
||||
# <FS:Ansariel> Only copy OpenJPEG dll if needed
|
||||
if (NOT USE_KDU)
|
||||
set(release_files ${release_files} openjp2.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,4 +18,6 @@ if( NOT USE_CONAN )
|
|||
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)
|
||||
|
|
@ -320,6 +321,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
|
||||
|
|
|
|||
|
|
@ -843,7 +843,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)
|
||||
{
|
||||
|
|
@ -672,6 +695,7 @@ std::string mbcsstring_makeASCII(const std::string& wstr)
|
|||
}
|
||||
return out_str;
|
||||
}
|
||||
|
||||
std::string utf8str_removeCRLF(const std::string& utf8str)
|
||||
{
|
||||
if (0 == utf8str.length())
|
||||
|
|
@ -693,6 +717,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;
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
unsigned int ll_wstring_default_code_page()
|
||||
{
|
||||
|
|
@ -905,6 +1042,40 @@ std::string LLStringOps::sDayFormat;
|
|||
std::string LLStringOps::sAM;
|
||||
std::string LLStringOps::sPM;
|
||||
|
||||
// static
|
||||
bool LLStringOps::isEmoji(llwchar wch)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ public:
|
|||
static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
|
||||
static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
|
||||
|
||||
static bool isEmoji(llwchar wch);
|
||||
|
||||
static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
|
||||
static S32 collate(const llwchar* a, const llwchar* b);
|
||||
|
||||
|
|
@ -364,6 +366,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);
|
||||
|
|
@ -687,6 +691,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.
|
||||
|
|
@ -751,6 +757,9 @@ 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);
|
||||
|
||||
#if LL_WINDOWS
|
||||
/* @name Windows string helpers
|
||||
|
|
@ -1607,6 +1616,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();
|
||||
|
|
|
|||
|
|
@ -1108,6 +1108,14 @@ void LLDir::setSkinFolder(const std::string &skin_folder, const std::string& the
|
|||
addSearchSkinDir(mUserDefaultSkinDir);
|
||||
// then user-defined skins.
|
||||
addSearchSkinDir(mUserSkinDir);
|
||||
|
||||
// <FS:Ansariel> If working directory is different from executable directory, add executable subdirs as searchable folders
|
||||
if (mExecutableDir != mWorkingDir)
|
||||
{
|
||||
addSearchSkinDir(add(mExecutableDir, "skins"));
|
||||
addSearchSkinDir(add(mExecutableDir, "skins", "default"));
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
}
|
||||
|
||||
void LLDir::addSearchSkinDir(const std::string& skindir)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,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"
|
||||
|
|
@ -51,6 +54,8 @@
|
|||
|
||||
#include "llapr.h"
|
||||
|
||||
#define ENABLE_OT_SVG_SUPPORT
|
||||
|
||||
FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
|
||||
|
||||
LLFontManager *gFontManagerp = NULL;
|
||||
|
|
@ -83,6 +88,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()
|
||||
|
|
@ -92,8 +107,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
|
||||
|
|
@ -102,10 +118,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),
|
||||
|
|
@ -172,7 +203,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.
|
||||
|
|
@ -255,7 +286,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)
|
||||
{
|
||||
|
|
@ -266,7 +297,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;
|
||||
|
|
@ -377,14 +408,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
|
||||
|
|
@ -408,7 +436,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;
|
||||
|
|
@ -440,10 +468,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;
|
||||
|
||||
// <FS:ND> Use cached kerning if possible, only do so for glyphs < 256 for now
|
||||
|
|
@ -517,60 +545,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;
|
||||
|
|
@ -581,8 +643,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)
|
||||
|
|
@ -617,84 +683,104 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// <FS:ND> try to load given glyph, if that fails, fallback to ?. This can happen with invalid unicode codepoints.
|
||||
if( 0 != FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) )
|
||||
glyph_index = FT_Get_Char_Index( mFTFace, L'?');
|
||||
// </FS:ND>
|
||||
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(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) );
|
||||
// <FS:ND> try to load given glyph, if that fails, fallback to ?. This can happen with invalid unicode codepoints.
|
||||
if (FT_Err_Ok != error)
|
||||
{
|
||||
glyph_index = FT_Get_Char_Index( mFTFace, L'?');
|
||||
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
|
||||
}
|
||||
// </FS:ND>
|
||||
|
||||
llassert_always_msg(FT_Err_Ok == error, message.c_str());
|
||||
}
|
||||
|
||||
llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) );
|
||||
|
||||
|
|
@ -704,7 +790,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.
|
||||
|
|
@ -714,11 +800,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -740,7 +824,7 @@ void LLFontFreetype::resetBitmapCache()
|
|||
if(!mIsFallback)
|
||||
{
|
||||
// Add the empty glyph
|
||||
addGlyphFromFont(this, 0, 0);
|
||||
addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -754,6 +838,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;
|
||||
|
|
@ -769,17 +881,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,9 +74,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
|
||||
|
|
@ -89,7 +91,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;
|
||||
|
|
@ -102,7 +104,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);
|
||||
|
||||
|
|
@ -111,10 +113,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;
|
||||
|
|
@ -153,7 +153,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);
|
||||
|
||||
|
|
@ -161,6 +161,7 @@ public:
|
|||
|
||||
const std::string& getName() const;
|
||||
|
||||
void dumpFontBitmaps() const;
|
||||
const LLFontBitmapCache* getFontBitmapCache() const;
|
||||
|
||||
void setStyle(U8 style);
|
||||
|
|
@ -169,10 +170,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;
|
||||
|
|
@ -192,9 +194,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)
|
||||
{
|
||||
|
|
@ -283,7 +282,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++)
|
||||
{
|
||||
|
|
@ -293,7 +292,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)
|
||||
{
|
||||
|
|
@ -301,8 +300,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.
|
||||
|
|
@ -323,8 +322,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);
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +363,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;
|
||||
|
|
@ -374,7 +373,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);
|
||||
}
|
||||
|
||||
|
|
@ -435,7 +434,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();
|
||||
}
|
||||
|
||||
|
|
@ -446,22 +446,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
|
||||
|
|
@ -514,7 +514,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);
|
||||
|
|
@ -538,7 +538,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);
|
||||
|
|
@ -561,7 +561,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.
|
||||
|
|
@ -582,7 +582,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -656,7 +656,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)
|
||||
{
|
||||
|
|
@ -681,7 +681,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);
|
||||
}
|
||||
|
||||
|
|
@ -728,7 +728,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
|
||||
|
|
@ -803,7 +803,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);
|
||||
|
|
@ -833,7 +833,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);
|
||||
}
|
||||
|
||||
|
|
@ -903,6 +903,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
|
||||
|
|
@ -1069,6 +1089,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, const std::string& fonts_file, F32 size_mod = 0, 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)
|
||||
|
|
@ -181,7 +184,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, F32 size_mod)
|
||||
|
|
@ -308,17 +323,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"))
|
||||
{
|
||||
|
|
@ -361,19 +383,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;
|
||||
}
|
||||
|
|
@ -460,86 +482,84 @@ 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());
|
||||
// <FS:Kadah> User fonts: Also load from user_settings/fonts
|
||||
std::string usr_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "fonts", "");
|
||||
|
||||
font_search_paths.push_back(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "fonts", ""));
|
||||
// <FS:Ansariel> Search executable path as well - in case we run from within VS (seems to work without as well, but just to be safe)
|
||||
font_search_paths.push_back(gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "fonts", ""));
|
||||
#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);
|
||||
// <FS:Kadah> User fonts: Also load from user_settings/fonts
|
||||
font_paths.push_back(usr_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)
|
||||
|
|
@ -549,7 +569,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;
|
||||
}
|
||||
|
|
@ -564,17 +585,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;
|
||||
|
|
@ -761,11 +777,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -2934,7 +2934,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ set(llui_SOURCE_FILES
|
|||
lldockcontrol.cpp
|
||||
lldraghandle.cpp
|
||||
lleditmenuhandler.cpp
|
||||
llemojidictionary.cpp
|
||||
llemojihelper.cpp
|
||||
llf32uictrl.cpp
|
||||
llfiltereditor.cpp
|
||||
llflashtimer.cpp
|
||||
|
|
@ -143,6 +145,8 @@ set(llui_HEADER_FILES
|
|||
lldockablefloater.h
|
||||
lldockcontrol.h
|
||||
lleditmenuhandler.h
|
||||
llemojidictionary.h
|
||||
llemojihelper.h
|
||||
llf32uictrl.h
|
||||
llfiltereditor.h
|
||||
llflashtimer.h
|
||||
|
|
|
|||
|
|
@ -70,6 +70,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"),
|
||||
|
|
@ -167,6 +168,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),
|
||||
|
|
@ -1027,7 +1029,7 @@ void LLButton::draw()
|
|||
LLFontGL::NORMAL,
|
||||
mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,
|
||||
S32_MAX, text_width,
|
||||
NULL, mUseEllipses);
|
||||
NULL, mUseEllipses, mUseFontColor);
|
||||
}
|
||||
|
||||
// <FS:Zi> Add checkbox control toggle
|
||||
|
|
@ -1096,6 +1098,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);
|
||||
|
|
@ -1127,14 +1139,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,
|
||||
|
|
@ -178,6 +179,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);
|
||||
|
|
@ -248,6 +250,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);
|
||||
|
|
@ -370,6 +374,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;
|
||||
};
|
||||
|
|
@ -194,6 +194,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),
|
||||
|
|
@ -271,6 +272,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
|
|||
mCanSnooze(p.can_snooze), // <FS:Ansariel> FIRE-11724: Snooze group chat
|
||||
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),
|
||||
|
|
@ -539,6 +541,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);
|
||||
|
|
@ -737,7 +740,7 @@ void LLFloater::openFloater(const LLSD& key)
|
|||
if (getHost() != NULL)
|
||||
{
|
||||
getHost()->setMinimized(FALSE);
|
||||
getHost()->setVisibleAndFrontmost(mAutoFocus);
|
||||
getHost()->setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
|
||||
getHost()->showFloater(this);
|
||||
// <FS:Zi> Make sure the floater knows it's not torn off
|
||||
mTornOff = false;
|
||||
|
|
@ -754,7 +757,7 @@ void LLFloater::openFloater(const LLSD& key)
|
|||
}
|
||||
applyControlsAndPosition(floater_to_stack);
|
||||
setMinimized(FALSE);
|
||||
setVisibleAndFrontmost(mAutoFocus);
|
||||
setVisibleAndFrontmost(mAutoFocus && !getIsChrome());
|
||||
}
|
||||
|
||||
mOpenSignal(this, key);
|
||||
|
|
@ -896,6 +899,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);
|
||||
|
|
@ -1204,9 +1225,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
|
||||
|
|
@ -1596,30 +1617,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1629,6 +1660,79 @@ void LLFloater::removeDependentFloater(LLFloater* floaterp)
|
|||
floaterp->mDependeeHandle = LLHandle<LLFloater>();
|
||||
}
|
||||
|
||||
// <FS:Ansariel> Fix floater relocation
|
||||
//void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels)
|
||||
void LLFloater::fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& chatbar, const LLRect& utilitybar, const LLRect& constraint, S32 min_overlap_pixels)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
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;
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
S32 delta_bottom_chatbar = chatbar.notEmpty() ? chatbar.mTop - total_rect.mTop : 0;
|
||||
S32 delta_utility_bar = utilitybar.notEmpty() ? utilitybar.mTop - total_rect.mTop : 0;
|
||||
|
||||
// <FS:Ansariel> Fix floater relocation for vertical toolbars; Only header guarantees that floater can be dragged!
|
||||
S32 header_height = getHeaderHeight();
|
||||
|
||||
// move floater with dependings fully onscreen
|
||||
mTranslateWithDependents = true;
|
||||
if (translateRectIntoRect(total_rect, constraint, min_overlap_pixels))
|
||||
{
|
||||
clearSnapTarget();
|
||||
}
|
||||
// <FS:Ansariel> Fix floater relocation for vertical toolbars; Only header guarantees that floater can be dragged!
|
||||
//else if (delta_left > 0 && total_rect.mTop < left.mTop && total_rect.mBottom > left.mBottom)
|
||||
else if (delta_left > 0 && total_rect.mTop < left.mTop && (total_rect.mTop - header_height) > left.mBottom)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
translate(delta_left, 0);
|
||||
}
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
//else if (delta_bottom > 0 && total_rect.mLeft > bottom.mLeft && total_rect.mRight < bottom.mRight)
|
||||
else if (delta_bottom > 0 && ((total_rect.mLeft > bottom.mLeft && total_rect.mRight < bottom.mRight) // floater completely within toolbar rect
|
||||
|| (total_rect.mLeft > bottom.mLeft && total_rect.mLeft < bottom.mRight && bottom.mRight > constraint.mRight) // floater partially within toolbar rect, toolbar bound to right side
|
||||
|| (delta_bottom_chatbar > 0 && total_rect.mLeft < chatbar.mRight && total_rect.mRight > bottom.mLeft && bottom.mLeft <= chatbar.mRight)) // floater within chatbar and toolbar rect
|
||||
)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
translate(0, delta_bottom);
|
||||
}
|
||||
// <FS:Ansariel> Fix floater relocation for vertical toolbars; Only header guarantees that floater can be dragged!
|
||||
//else if (delta_right < 0 && total_rect.mTop < right.mTop && total_rect.mBottom > right.mBottom)
|
||||
else if (delta_right < 0 && total_rect.mTop < right.mTop && (total_rect.mTop - header_height) > right.mBottom)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
translate(delta_right, 0);
|
||||
}
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
else if (delta_bottom_chatbar > 0 && ((total_rect.mLeft > chatbar.mLeft && total_rect.mRight < chatbar.mRight) // floater completely within chatbar rect
|
||||
|| (total_rect.mRight > chatbar.mLeft && total_rect.mRight < chatbar.mRight && chatbar.mLeft < constraint.mLeft) // floater partially within chatbar rect, chatbar bound to left side
|
||||
|| (delta_bottom > 0 && total_rect.mRight > bottom.mLeft && total_rect.mLeft < chatbar.mRight && bottom.mLeft <= chatbar.mRight)) // floater within chatbar and toolbar rect
|
||||
)
|
||||
{
|
||||
translate(0, delta_bottom_chatbar);
|
||||
}
|
||||
else if (delta_utility_bar > 0 && (total_rect.mLeft > utilitybar.mLeft && total_rect.mRight < utilitybar.mRight))
|
||||
{
|
||||
// Utility bar on legacy skins
|
||||
translate(0, delta_utility_bar);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
mTranslateWithDependents = false;
|
||||
}
|
||||
|
||||
BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index)
|
||||
{
|
||||
if( mButtonsEnabled[index] )
|
||||
|
|
@ -1719,6 +1823,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))
|
||||
|
|
@ -1733,12 +1838,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)
|
||||
|
|
@ -2518,7 +2631,8 @@ LLFloaterView::LLFloaterView (const Params& p)
|
|||
mSnapOffsetBottom(0),
|
||||
mSnapOffsetChatBar(0),
|
||||
mSnapOffsetLeft(0),
|
||||
mSnapOffsetRight(0)
|
||||
mSnapOffsetRight(0),
|
||||
mFrontChild(NULL)
|
||||
{
|
||||
mSnapView = getHandle();
|
||||
}
|
||||
|
|
@ -2674,16 +2788,21 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore
|
|||
if (!child)
|
||||
return;
|
||||
|
||||
if (mFrontChildHandle.get() == child)
|
||||
if (mFrontChild == child)
|
||||
{
|
||||
if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
|
||||
if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))
|
||||
{
|
||||
child->setFocus(TRUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mFrontChildHandle = child->getHandle();
|
||||
if (mFrontChild && !mFrontChild->isDead())
|
||||
{
|
||||
mFrontChild->goneFromFront();
|
||||
}
|
||||
|
||||
mFrontChild = child;
|
||||
|
||||
// *TODO: make this respect floater's mAutoFocus value, instead of
|
||||
// using parameter
|
||||
|
|
@ -3114,10 +3233,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() )
|
||||
{
|
||||
|
|
@ -3159,64 +3285,12 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
|
|||
}
|
||||
}
|
||||
|
||||
const LLRect& left_toolbar_rect = mToolbarLeftRect;
|
||||
const LLRect& bottom_toolbar_rect = mToolbarBottomRect;
|
||||
const LLRect& right_toolbar_rect = mToolbarRightRect;
|
||||
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 = left_toolbar_rect.notEmpty() ? left_toolbar_rect.mRight - floater_rect.mRight : 0;
|
||||
S32 delta_bottom = bottom_toolbar_rect.notEmpty() ? bottom_toolbar_rect.mTop - floater_rect.mTop : 0;
|
||||
S32 delta_right = right_toolbar_rect.notEmpty() ? right_toolbar_rect.mLeft - floater_rect.mLeft : 0;
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
S32 delta_bottom_chatbar = mMainChatbarRect.notEmpty() ? mMainChatbarRect.mTop - floater_rect.mTop : 0;
|
||||
S32 delta_utility_bar = mUtilityBarRect.notEmpty() ? mUtilityBarRect.mTop - floater_rect.mTop : 0;
|
||||
|
||||
// <FS:Ansariel> Fix floater relocation for vertical toolbars; Only header guarantees that floater can be dragged!
|
||||
S32 header_height = floater->getHeaderHeight();
|
||||
|
||||
// move window fully onscreen
|
||||
if (floater->translateIntoRect( snap_in_toolbars ? getSnapRect() : gFloaterView->getRect(), allow_partial_outside ? FLOATER_MIN_VISIBLE_PIXELS : S32_MAX ))
|
||||
{
|
||||
floater->clearSnapTarget();
|
||||
}
|
||||
// <FS:Ansariel> Fix floater relocation for vertical toolbars; Only header guarantees that floater can be dragged!
|
||||
//else if (delta_left > 0 && floater_rect.mTop < left_toolbar_rect.mTop && floater_rect.mBottom > left_toolbar_rect.mBottom)
|
||||
else if (delta_left > 0 && floater_rect.mTop < left_toolbar_rect.mTop && (floater_rect.mTop - header_height) > left_toolbar_rect.mBottom)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
floater->translate(delta_left, 0);
|
||||
}
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
//else if (delta_bottom > 0 && floater_rect.mLeft > bottom_toolbar_rect.mLeft && floater_rect.mRight < bottom_toolbar_rect.mRight)
|
||||
else if (delta_bottom > 0 && ((floater_rect.mLeft > bottom_toolbar_rect.mLeft && floater_rect.mRight < bottom_toolbar_rect.mRight) // floater completely within toolbar rect
|
||||
|| (floater_rect.mLeft > bottom_toolbar_rect.mLeft && floater_rect.mLeft < bottom_toolbar_rect.mRight && bottom_toolbar_rect.mRight > gFloaterView->getRect().mRight) // floater partially within toolbar rect, toolbar bound to right side
|
||||
|| (delta_bottom_chatbar > 0 && floater_rect.mLeft < mMainChatbarRect.mRight && floater_rect.mRight > bottom_toolbar_rect.mLeft && bottom_toolbar_rect.mLeft <= mMainChatbarRect.mRight)) // floater within chatbar and toolbar rect
|
||||
)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
floater->translate(0, delta_bottom);
|
||||
}
|
||||
// <FS:Ansariel> Fix floater relocation for vertical toolbars; Only header guarantees that floater can be dragged!
|
||||
//else if (delta_right < 0 && floater_rect.mTop < right_toolbar_rect.mTop && floater_rect.mBottom > right_toolbar_rect.mBottom)
|
||||
else if (delta_right < 0 && floater_rect.mTop < right_toolbar_rect.mTop && (floater_rect.mTop - header_height) > right_toolbar_rect.mBottom)
|
||||
// </FS:Ansariel>
|
||||
{
|
||||
floater->translate(delta_right, 0);
|
||||
}
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
else if (delta_bottom_chatbar > 0 && ((floater_rect.mLeft > mMainChatbarRect.mLeft && floater_rect.mRight < mMainChatbarRect.mRight) // floater completely within chatbar rect
|
||||
|| (floater_rect.mRight > mMainChatbarRect.mLeft && floater_rect.mRight < mMainChatbarRect.mRight && mMainChatbarRect.mLeft < gFloaterView->getRect().mLeft) // floater partially within chatbar rect, chatbar bound to left side
|
||||
|| (delta_bottom > 0 && floater_rect.mRight > bottom_toolbar_rect.mLeft && floater_rect.mLeft < mMainChatbarRect.mRight && bottom_toolbar_rect.mLeft <= mMainChatbarRect.mRight)) // floater within chatbar and toolbar rect
|
||||
)
|
||||
{
|
||||
floater->translate(0, delta_bottom_chatbar);
|
||||
}
|
||||
else if (delta_utility_bar > 0 && (floater_rect.mLeft > mUtilityBarRect.mLeft && floater_rect.mRight < mUtilityBarRect.mRight))
|
||||
{
|
||||
// Utility bar on legacy skins
|
||||
floater->translate(0, delta_utility_bar);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
// <FS:Ansariel> Fix floater relocation
|
||||
//floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, constraint, min_overlap_pixels);
|
||||
floater->fitWithDependentsOnScreen(mToolbarLeftRect, mToolbarBottomRect, mToolbarRightRect, mMainChatbarRect, mUtilityBarRect, constraint, min_overlap_pixels);
|
||||
}
|
||||
|
||||
void LLFloaterView::draw()
|
||||
|
|
@ -3315,6 +3389,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)
|
||||
|
|
@ -3350,7 +3427,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -3443,6 +3547,14 @@ void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LL
|
|||
}
|
||||
}
|
||||
|
||||
void LLFloaterView::onDestroyFloater(LLFloater* floater)
|
||||
{
|
||||
if (mFrontChild == floater)
|
||||
{
|
||||
mFrontChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
void LLFloaterView::setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect)
|
||||
{
|
||||
|
|
@ -3567,6 +3679,7 @@ void LLFloater::initFromParams(const LLFloater::Params& p)
|
|||
mDefaultRelativeY = p.rel_y;
|
||||
|
||||
mPositioning = p.positioning;
|
||||
mAutoClose = p.auto_close;
|
||||
|
||||
mHostedFloaterShowtitlebar = p.hosted_floater_show_titlebar; // <FS:Ansariel> MultiFloater without titlebar for hosted floater
|
||||
|
||||
|
|
|
|||
|
|
@ -113,8 +113,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>
|
||||
|
|
@ -170,7 +168,8 @@ public:
|
|||
save_visibility,
|
||||
save_dock_state,
|
||||
can_dock,
|
||||
show_title;
|
||||
show_title,
|
||||
auto_close;
|
||||
|
||||
Optional<LLFloaterEnums::EOpenPositioning> positioning;
|
||||
|
||||
|
|
@ -248,6 +247,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();
|
||||
|
|
@ -266,10 +266,14 @@ 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);
|
||||
// <FS:Ansariel> Fix floater relocation
|
||||
//void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& constraint, S32 min_overlap_pixels);
|
||||
void fitWithDependentsOnScreen(const LLRect& left, const LLRect& bottom, const LLRect& right, const LLRect& chatbar, const LLRect& utilitybar, const LLRect& constraint, S32 min_overlap_pixels);
|
||||
// </FS:Ansariel>
|
||||
BOOL isMinimized() const { return mMinimized; }
|
||||
/// isShown() differs from getVisible() in that isShown() also considers
|
||||
/// isMinimized(). isShown() is true only if visible and not minimized.
|
||||
|
|
@ -326,6 +330,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());
|
||||
|
||||
|
|
@ -405,6 +412,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; }
|
||||
|
|
@ -506,8 +514,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;
|
||||
BOOL mCanSnooze; // <FS:Ansariel> FIRE-11724: Snooze group chat
|
||||
|
||||
LLFloaterEnums::EOpenPositioning mPositioning;
|
||||
|
|
@ -528,6 +538,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;
|
||||
|
|
@ -634,6 +645,7 @@ public:
|
|||
// </FS:KC> Fix for bad edge snapping
|
||||
|
||||
void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect);
|
||||
void onDestroyFloater(LLFloater* floater);
|
||||
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
void setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect);
|
||||
|
|
@ -658,7 +670,7 @@ private:
|
|||
S32 mMinimizePositionVOffset;
|
||||
typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t;
|
||||
hidden_floaters_t mHiddenFloaters;
|
||||
LLHandle<LLFloater> mFrontChildHandle;
|
||||
LLFloater * mFrontChild;
|
||||
|
||||
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
|
||||
LLRect mMainChatbarRect;
|
||||
|
|
|
|||
|
|
@ -959,7 +959,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()
|
||||
|
|
@ -1069,7 +1069,7 @@ void LLFolderViewItem::draw()
|
|||
static const std::string locked_string = " (" + LLTrans::getString("LockedFolder") + ") ";
|
||||
font->renderUTF8(locked_string, 0, right_x, y, sProtectedColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE);
|
||||
S32_MAX, S32_MAX, &right_x, FALSE, FALSE);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
|
|
@ -1079,7 +1079,7 @@ void LLFolderViewItem::draw()
|
|||
static const std::string protected_string = " (" + LLTrans::getString("ProtectedFolder") + ") ";
|
||||
font->renderUTF8(protected_string, 0, right_x, y, sProtectedColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE);
|
||||
S32_MAX, S32_MAX, &right_x, FALSE, FALSE);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
|
|
@ -1090,7 +1090,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);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------//
|
||||
|
|
@ -1102,9 +1102,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
|
||||
{
|
||||
|
|
@ -1113,8 +1113,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;
|
||||
|
|
@ -1123,7 +1124,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),
|
||||
|
|
@ -152,6 +153,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 ),
|
||||
|
|
@ -1814,6 +1816,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;
|
||||
|
|
@ -2152,7 +2168,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,
|
||||
|
|
@ -2188,7 +2204,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,
|
||||
use_bg_color;
|
||||
|
||||
|
|
@ -121,54 +122,55 @@ protected:
|
|||
//void showContextMenu(S32 x, S32 y);
|
||||
void showContextMenu(S32 x, S32 y, bool set_cursor_pos = true);
|
||||
// </FS:Ansariel>
|
||||
|
||||
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;
|
||||
|
|
@ -176,27 +178,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;
|
||||
|
||||
//<FS:TS> FIRE-11373: Autoreplace doesn't work in nearby chat bar
|
||||
typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t;
|
||||
|
|
@ -224,7 +227,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; }
|
||||
|
|
@ -331,14 +334,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);
|
||||
|
||||
|
|
@ -415,6 +418,7 @@ protected:
|
|||
BOOL mReadOnly;
|
||||
|
||||
BOOL mShowImageFocused;
|
||||
BOOL mShowLabelFocused;
|
||||
|
||||
bool mUseBgColor;
|
||||
|
||||
|
|
|
|||
|
|
@ -594,6 +594,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 )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -236,10 +236,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);
|
||||
|
|
|
|||
|
|
@ -919,7 +919,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);
|
||||
|
|
@ -970,8 +970,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
|
||||
|
|
|
|||
|
|
@ -64,7 +64,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;
|
||||
|
|
@ -152,6 +153,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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -495,7 +495,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())
|
||||
|
|
@ -1385,7 +1385,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);
|
||||
}
|
||||
|
|
@ -3155,7 +3155,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,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);
|
||||
// <FS:Ansariel> Allow appending of comment text
|
||||
void addCommentText( const std::string& comment_text);
|
||||
// </FS:Ansariel> Allow appending of comment text
|
||||
|
|
@ -277,7 +277,7 @@ public:
|
|||
BOOL selectItemBySubstring(const LLWString& target, BOOL case_sensitive = TRUE);
|
||||
BOOL selectItemByStringMatch(const LLWString& target, bool prefix_match, BOOL case_sensitive = TRUE, S32 column = -1);
|
||||
// </FS:Ansariel>
|
||||
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();
|
||||
|
||||
|
|
@ -339,7 +339,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);
|
||||
|
|
@ -394,13 +394,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.
|
||||
|
|
@ -421,18 +421,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)
|
||||
|
|
@ -487,8 +489,6 @@ public:
|
|||
mutable U32 mLastUpdateFrame;
|
||||
|
||||
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"
|
||||
|
|
@ -180,10 +182,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),
|
||||
// <FS:Ansariel> Optional icon position
|
||||
icon_positioning("icon_positioning", LLTextBaseEnums::RIGHT),
|
||||
// </FS:Ansariel> Optional icon position
|
||||
|
|
@ -233,6 +237,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),
|
||||
|
|
@ -247,6 +252,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),
|
||||
|
|
@ -725,7 +731,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);
|
||||
|
|
@ -1045,6 +1051,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() )
|
||||
|
|
@ -1228,6 +1256,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
|
||||
|
|
@ -1282,6 +1311,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);
|
||||
|
|
@ -1301,6 +1331,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);
|
||||
|
|
@ -1312,6 +1343,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);
|
||||
|
|
@ -1323,6 +1355,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);
|
||||
|
|
@ -1334,6 +1367,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);
|
||||
|
|
@ -1345,6 +1379,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
|
||||
|
|
@ -1364,6 +1399,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);
|
||||
|
|
@ -1375,6 +1411,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);
|
||||
|
|
@ -1386,6 +1423,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);
|
||||
|
|
@ -1397,7 +1435,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)
|
||||
|
|
@ -1424,6 +1475,7 @@ void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
|
|||
}
|
||||
}
|
||||
|
||||
//virtual
|
||||
void LLTextBase::draw()
|
||||
{
|
||||
// reflow if needed, on demand
|
||||
|
|
@ -2158,21 +2210,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(); }
|
||||
|
||||
|
|
@ -2187,18 +2226,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(); }
|
||||
|
||||
|
|
@ -2431,8 +2458,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;
|
||||
|
|
@ -2738,18 +2765,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;
|
||||
|
|
@ -2757,7 +2784,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());
|
||||
}
|
||||
|
|
@ -2769,25 +2796,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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -3676,12 +3706,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;
|
||||
|
||||
|
|
@ -3695,12 +3726,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 )
|
||||
|
|
@ -3712,12 +3744,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;
|
||||
}
|
||||
|
|
@ -3961,6 +3994,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
|
||||
{
|
||||
|
|
@ -294,7 +306,7 @@ namespace LLInitParam
|
|||
/// as LLTextEditor and LLTextBox. It implements shared functionality
|
||||
/// such as Url highlighting and opening.
|
||||
///
|
||||
class LLTextBase
|
||||
class LLTextBase
|
||||
: public LLUICtrl,
|
||||
protected LLEditMenuHandler,
|
||||
public LLSpellCheckMenuHandler,
|
||||
|
|
@ -340,6 +352,7 @@ public:
|
|||
plain_text,
|
||||
wrap,
|
||||
use_ellipses,
|
||||
use_color,
|
||||
parse_urls,
|
||||
force_urls_external,
|
||||
parse_highlights,
|
||||
|
|
@ -359,6 +372,8 @@ public:
|
|||
|
||||
Optional<LLFontGL::ShadowType> font_shadow;
|
||||
|
||||
Optional<LLFontGL::VAlign> text_valign;
|
||||
|
||||
// <FS:Ansariel> Optional icon position
|
||||
Optional<LLTextBaseEnums::EIconPositioning> icon_positioning;
|
||||
|
||||
|
|
@ -366,51 +381,52 @@ public:
|
|||
};
|
||||
|
||||
// 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;
|
||||
|
|
@ -421,6 +437,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;}
|
||||
|
|
@ -443,7 +460,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();}
|
||||
|
|
@ -680,7 +697,8 @@ protected:
|
|||
S32 normalizeUri(std::string& uri);
|
||||
|
||||
protected:
|
||||
virtual std::string _getSearchText() const
|
||||
// virtual
|
||||
std::string _getSearchText() const override
|
||||
{
|
||||
return mLabel.getString() + getToolTip();
|
||||
}
|
||||
|
|
@ -745,8 +763,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;
|
||||
|
|
@ -755,6 +774,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"),
|
||||
enable_tab_remove("enable_tab_remove", true) // <FS:Ansariel> FIRE-15591: Optional tab remove
|
||||
{
|
||||
|
|
@ -259,6 +261,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),
|
||||
|
|
@ -555,6 +558,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())
|
||||
|
|
@ -719,6 +732,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;
|
||||
|
|
@ -992,6 +1027,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) )
|
||||
{
|
||||
|
|
@ -1041,7 +1082,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 ) );
|
||||
}
|
||||
|
|
@ -1065,11 +1106,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;
|
||||
|
||||
|
|
@ -1084,14 +1126,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.
|
||||
|
|
@ -1105,8 +1147,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
|
||||
{
|
||||
|
|
@ -1117,7 +1161,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()
|
||||
|
|
@ -1126,10 +1170,12 @@ void LLTextEditor::removeChar()
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCursorPos > 0)
|
||||
{
|
||||
setCursorPos(mCursorPos - 1);
|
||||
removeChar(mCursorPos);
|
||||
tryToShowEmojiHelper();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1217,6 +1263,7 @@ void LLTextEditor::addChar(llwchar wc)
|
|||
}
|
||||
|
||||
setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
|
||||
tryToShowEmojiHelper();
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
|
|
@ -1236,6 +1283,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() )
|
||||
|
|
@ -1963,6 +2041,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)
|
||||
|
|
@ -2004,6 +2087,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;
|
||||
|
|
@ -2022,7 +2111,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,
|
||||
enable_tab_remove, // <FS:Ansariel> FIRE-15591: Optional tab remove
|
||||
auto_indent;
|
||||
|
|
@ -92,6 +93,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);
|
||||
|
|
@ -212,6 +216,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:
|
||||
|
|
@ -263,6 +271,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;
|
||||
|
|
@ -333,6 +342,7 @@ private:
|
|||
|
||||
BOOL mAllowEmbeddedItems;
|
||||
bool mShowContextMenu;
|
||||
bool mShowEmojiHelper;
|
||||
bool mEnableTooltipPaste;
|
||||
bool mPassDelete;
|
||||
bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter
|
||||
|
|
|
|||
|
|
@ -798,25 +798,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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -280,7 +280,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);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,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;
|
||||
|
|
@ -570,7 +571,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);
|
||||
|
|
@ -1080,7 +1081,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1392,8 +1393,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();
|
||||
|
|
@ -1809,23 +1809,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;
|
||||
|
|
@ -1836,13 +1839,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;
|
||||
}
|
||||
|
||||
|
|
@ -2022,7 +2031,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()));
|
||||
}
|
||||
|
|
@ -2046,7 +2055,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>
|
||||
|
|
@ -373,6 +373,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);
|
||||
|
||||
|
|
@ -670,8 +671,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.
|
||||
|
|
@ -714,19 +718,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>
|
||||
|
|
|
|||
|
|
@ -743,23 +743,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
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ include(EXPAT)
|
|||
include(FMODSTUDIO)
|
||||
include(GLOD) # <FS:Beq/> restore GLOD
|
||||
include(Hunspell)
|
||||
include(ICU4C)
|
||||
include(JPEGEncoderBasic)
|
||||
include(JsonCpp)
|
||||
include(LLAppearance)
|
||||
|
|
@ -316,6 +317,7 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterdisplayname.cpp
|
||||
llfloatereditenvironmentbase.cpp
|
||||
llfloatereditextdaycycle.cpp
|
||||
llfloateremojipicker.cpp
|
||||
llfloaterenvironmentadjust.cpp
|
||||
llfloaterevent.cpp
|
||||
llfloaterexperiencepicker.cpp
|
||||
|
|
@ -532,6 +534,7 @@ set(viewer_SOURCE_FILES
|
|||
llpaneleditsky.cpp
|
||||
llpaneleditwater.cpp
|
||||
llpaneleditwearable.cpp
|
||||
llpanelemojicomplete.cpp
|
||||
llpanelenvironment.cpp
|
||||
llpanelexperiencelisteditor.cpp
|
||||
llpanelexperiencelog.cpp
|
||||
|
|
@ -1109,6 +1112,7 @@ set(viewer_HEADER_FILES
|
|||
llfloaterdisplayname.h
|
||||
llfloatereditenvironmentbase.h
|
||||
llfloatereditextdaycycle.h
|
||||
llfloateremojipicker.h
|
||||
llfloaterenvironmentadjust.h
|
||||
llfloaterevent.h
|
||||
llfloaterexperiencepicker.h
|
||||
|
|
@ -1317,6 +1321,7 @@ set(viewer_HEADER_FILES
|
|||
llpaneleditsky.h
|
||||
llpaneleditwater.h
|
||||
llpaneleditwearable.h
|
||||
llpanelemojicomplete.h
|
||||
llpanelenvironment.h
|
||||
llpanelexperiencelisteditor.h
|
||||
llpanelexperiencelog.h
|
||||
|
|
@ -2410,6 +2415,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
|||
${LLPHYSICSEXTENSIONS_LIBRARIES}
|
||||
ll::bugsplat
|
||||
ll::tracy
|
||||
ll::icu4c
|
||||
fs::glod # <FS:Beq/> restore GLOD dependencies
|
||||
fs::discord # <FS:Ansariel> Discord support
|
||||
)
|
||||
|
|
@ -2448,6 +2454,32 @@ endif (LINUX)
|
|||
set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
|
||||
"Path to artwork files.")
|
||||
|
||||
# <FS:Ansariel> Don't copy fonts into the source folder!
|
||||
#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")
|
||||
# </FS:Ansariel>
|
||||
|
||||
# <FS:Ansariel> Don't copy emoji characters into source folder
|
||||
# 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()
|
||||
# </FS:Ansariel>
|
||||
|
||||
if (LINUX)
|
||||
set(product Firestorm-${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>
|
||||
|
|
@ -26803,6 +26803,17 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSShowEmojiButton</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Show or hide the emoji selection button in chat/IM windows</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FSAnimationPreviewExpanded</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -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.
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DejaVuSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>DejaVuSans-BoldOblique.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>CascadiaCode-Light.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>CascadiaCode-Light.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>CascadiaCode-Light.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>CelestiaMediumRedux1.55.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>CelestiaMediumRedux1.55.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DejaVuSansAllCaps.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -74,6 +75,11 @@
|
|||
<file>DejaVuSansAllCaps-BoldOblique.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansAllCapsMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DroidSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>DroidSerif-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DroidSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>MobiSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>opendyslexic-bolditalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>SourceCodePro-Regular.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>LiberationSans-Regular.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>LiberationSans-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>LiberationMono-Regular.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>MobiSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>MobiSans-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>MobiSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>NotoSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>NotoSans-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>NotoMono-Regular.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DroidSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>Roboto-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>MobiSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>Ubuntu-R.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>Ubuntu-MI.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>UbuntuMono-R.ttf</file>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ LLAssetType::EType S32toAssetType(S32 assetindex)
|
|||
return type;
|
||||
}
|
||||
|
||||
void FSAssetBlacklist::init()
|
||||
void FSAssetBlacklist::initSingleton()
|
||||
{
|
||||
mBlacklistFileName = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "asset_blacklist.xml");
|
||||
loadBlacklist();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class FSAssetBlacklist : public LLSingleton<FSAssetBlacklist>
|
|||
LLSINGLETON_EMPTY_CTOR(FSAssetBlacklist);
|
||||
|
||||
public:
|
||||
void init();
|
||||
void initSingleton() override;
|
||||
bool isBlacklisted(const LLUUID& id, LLAssetType::EType type);
|
||||
void addNewItemToBlacklist(const LLUUID& id, const std::string& name, const std::string& region, LLAssetType::EType type, bool permanent = true, bool save = true);
|
||||
void addNewItemToBlacklistData(const LLUUID& id, const LLSD& data, bool save = true);
|
||||
|
|
|
|||
|
|
@ -1259,6 +1259,8 @@ FSChatHistory::FSChatHistory(const FSChatHistory::Params& p)
|
|||
mUnreadChatSources(0)
|
||||
{
|
||||
mLineSpacingPixels = llclamp(gSavedSettings.getS32("FSFontChatLineSpacingPixels"), 0, 36);
|
||||
mTextVAlign = LLFontGL::VAlign::VCENTER;
|
||||
mUseColor = true;
|
||||
|
||||
setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
#include "llagentbenefits.h"
|
||||
#include "llavataractions.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llemojidictionary.h"
|
||||
#include "llfloateremojipicker.h"
|
||||
#include "llfloaterperms.h"
|
||||
#include "llgroupactions.h"
|
||||
#include "llgroupmgr.h"
|
||||
|
|
@ -520,3 +522,23 @@ LLUUID FSCommon::getGroupForRezzing()
|
|||
|
||||
return group_id;
|
||||
}
|
||||
|
||||
void FSCommon::updateUsedEmojis(LLWString text)
|
||||
{
|
||||
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
|
||||
|
||||
bool emojiSent = false;
|
||||
for (llwchar& c : text)
|
||||
{
|
||||
if (dictionary->isEmoji(c))
|
||||
{
|
||||
LLFloaterEmojiPicker::onEmojiUsed(c);
|
||||
emojiSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emojiSent)
|
||||
return;
|
||||
|
||||
LLFloaterEmojiPicker::saveState();
|
||||
}
|
||||
|
|
@ -93,6 +93,8 @@ namespace FSCommon
|
|||
bool isFilterEditorKeyCombo(KEY key, MASK mask);
|
||||
|
||||
LLUUID getGroupForRezzing();
|
||||
|
||||
void updateUsedEmojis(LLWString text);
|
||||
};
|
||||
|
||||
#endif // FS_COMMON_H
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
#include "llconsole.h"
|
||||
#include "llfloaterabout.h" // for sysinfo button -Zi
|
||||
#include "llfloateravatarpicker.h"
|
||||
#include "llfloateremojipicker.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersearchreplace.h"
|
||||
#include "llgroupactions.h"
|
||||
|
|
@ -63,6 +64,7 @@
|
|||
#include "llnotifications.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llnotificationtemplate.h" // <FS:Zi> Viewer version popup
|
||||
#include "llpanelemojicomplete.h"
|
||||
#include "llrootview.h"
|
||||
#include "llscreenchannel.h"
|
||||
#include "llspeakers.h"
|
||||
|
|
@ -375,6 +377,8 @@ void FSFloaterIM::sendMsgFromInputEditor(EChatType type)
|
|||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if (!text.empty())
|
||||
{
|
||||
FSCommon::updateUsedEmojis(text);
|
||||
|
||||
if (type == CHAT_TYPE_OOC)
|
||||
{
|
||||
std::string tempText = wstring_to_utf8str( text );
|
||||
|
|
@ -599,6 +603,11 @@ FSFloaterIM::~FSFloaterIM()
|
|||
{
|
||||
mAvatarNameCacheConnection.disconnect();
|
||||
}
|
||||
|
||||
if (mRecentEmojisUpdatedCallbackConnection.connected())
|
||||
{
|
||||
mRecentEmojisUpdatedCallbackConnection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterIM::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state)
|
||||
|
|
@ -949,8 +958,27 @@ BOOL FSFloaterIM::postBuild()
|
|||
mInputEditor->enableSingleLineMode(gSavedSettings.getBOOL("FSUseSingleLineChatEntry"));
|
||||
mInputEditor->setCommitCallback(boost::bind(&FSFloaterIM::sendMsgFromInputEditor, this, CHAT_TYPE_NORMAL));
|
||||
|
||||
getChild<LLButton>("send_chat")->setCommitCallback(boost::bind(&FSFloaterIM::sendMsgFromInputEditor, this, CHAT_TYPE_NORMAL));
|
||||
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);
|
||||
|
||||
mEmojiPickerToggleBtn = getChild<LLButton>("emoji_picker_toggle_btn");
|
||||
mEmojiPickerToggleBtn->setLabel(LLUIString(LLWString(1, 128512)));
|
||||
mEmojiPickerToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerToggleBtnClicked(); });
|
||||
|
||||
mRecentEmojisUpdatedCallbackConnection = LLFloaterEmojiPicker::setRecentEmojisUpdatedCallback([this](const std::list<llwchar>& recent_emojis_list) { initEmojiRecentPanel(); });
|
||||
|
||||
getChild<LLButton>("send_chat")->setCommitCallback(boost::bind(&FSFloaterIM::sendMsgFromInputEditor, this, CHAT_TYPE_NORMAL));
|
||||
getChild<LLButton>("chat_search_btn")->setCommitCallback(boost::bind(&FSFloaterIM::onChatSearchButtonClicked, this));
|
||||
|
||||
bool isFSSupportGroup = FSData::getInstance()->isFirestormGroup(mSessionID);
|
||||
|
|
@ -2443,3 +2471,56 @@ bool FSFloaterIM::applyRectControl()
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
void FSFloaterIM::onEmojiRecentPanelToggleBtnClicked()
|
||||
{
|
||||
BOOL show = mEmojiRecentPanel->getVisible() ? FALSE : TRUE;
|
||||
if (show)
|
||||
{
|
||||
initEmojiRecentPanel();
|
||||
}
|
||||
|
||||
mEmojiRecentPanel->setVisible(show);
|
||||
mInputEditor->setFocus(TRUE);
|
||||
}
|
||||
|
||||
void FSFloaterIM::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 FSFloaterIM::onRecentEmojiPicked(const LLSD& value)
|
||||
{
|
||||
LLSD::String str = value.asString();
|
||||
if (str.size())
|
||||
{
|
||||
LLWString wstr = utf8string_to_wstring(str);
|
||||
if (wstr.size())
|
||||
{
|
||||
llwchar emoji = wstr[0];
|
||||
mInputEditor->insertEmoji(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterIM::onEmojiPickerToggleBtnClicked()
|
||||
{
|
||||
mInputEditor->setFocus(TRUE);
|
||||
mInputEditor->showEmojiHelper();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,10 +47,10 @@ class LLInventoryCategory;
|
|||
class LLInventoryItem;
|
||||
class LLLayoutPanel;
|
||||
class LLLayoutStack;
|
||||
class LLPanelEmojiComplete;
|
||||
class LLTextBox;
|
||||
class LLTextEditor;
|
||||
|
||||
|
||||
typedef boost::signals2::signal<void(const LLUUID& session_id)> floater_showed_signal_t;
|
||||
|
||||
/**
|
||||
|
|
@ -161,6 +161,8 @@ public:
|
|||
|
||||
void timedUpdate();
|
||||
|
||||
void onEmojiPickerToggleBtnClicked();
|
||||
|
||||
protected:
|
||||
/* virtual */
|
||||
void onClickCloseBtn(bool app_quitting = false);
|
||||
|
|
@ -234,10 +236,14 @@ private:
|
|||
void addSessionParticipants(const uuid_vec_t& uuids);
|
||||
void addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids);
|
||||
|
||||
void onChatOptionsContextMenuItemClicked(const LLSD& userdata);
|
||||
bool onChatOptionsCheckContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsVisibleContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsEnableContextMenuItem(const LLSD& userdata);
|
||||
void onChatOptionsContextMenuItemClicked(const LLSD& userdata);
|
||||
bool onChatOptionsCheckContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsVisibleContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsEnableContextMenuItem(const LLSD& userdata);
|
||||
|
||||
void onEmojiRecentPanelToggleBtnClicked();
|
||||
void initEmojiRecentPanel();
|
||||
void onRecentEmojiPicked(const LLSD& value);
|
||||
|
||||
FSPanelChatControlPanel* mControlPanel;
|
||||
LLUUID mSessionID;
|
||||
|
|
@ -252,6 +258,11 @@ private:
|
|||
LLLayoutStack* mInputPanels;
|
||||
LLLayoutPanel* mUnreadMessagesNotificationPanel;
|
||||
LLTextBox* mUnreadMessagesNotificationTextBox;
|
||||
LLButton* mEmojiRecentPanelToggleBtn;
|
||||
LLButton* mEmojiPickerToggleBtn;
|
||||
LLLayoutPanel* mEmojiRecentPanel;
|
||||
LLTextBox* mEmojiRecentEmptyText;
|
||||
LLPanelEmojiComplete* mEmojiRecentIconsCtrl;
|
||||
|
||||
std::string mSavedTitle;
|
||||
LLUIString mTypingStart;
|
||||
|
|
@ -283,6 +294,8 @@ private:
|
|||
bool mApplyRect;
|
||||
|
||||
FSFloaterIMTimer* mIMFloaterTimer;
|
||||
|
||||
boost::signals2::connection mRecentEmojisUpdatedCallbackConnection{};
|
||||
};
|
||||
|
||||
class FSFloaterIMTimer : public LLEventTimer
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "llfloaterreg.h"
|
||||
#include "llchiclet.h"
|
||||
#include "llchicletbar.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "lltoolbarview.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
||||
|
|
@ -580,4 +581,8 @@ void FSFloaterIMContainer::sessionIDUpdated(const LLUUID& old_session_id, const
|
|||
}
|
||||
}
|
||||
|
||||
void FSFloaterIMContainer::tabOpen(LLFloater* opened_floater, bool from_click)
|
||||
{
|
||||
LLEmojiHelper::instance().hideHelper(nullptr, true);
|
||||
}
|
||||
// EOF
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ public:
|
|||
|
||||
void addFlashingSession(const LLUUID& session_id);
|
||||
|
||||
void tabOpen(LLFloater* opened_floater, bool from_click);
|
||||
|
||||
private:
|
||||
enum eVoiceState
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include "llcommandhandler.h"
|
||||
#include "llconsole.h"
|
||||
#include "lldraghandle.h"
|
||||
#include "llfloateremojipicker.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatersearchreplace.h"
|
||||
#include "llfocusmgr.h"
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
#include "lllogchat.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llmultigesture.h"
|
||||
#include "llpanelemojicomplete.h"
|
||||
#include "llresizebar.h"
|
||||
#include "llresizehandle.h"
|
||||
#include "llrootview.h"
|
||||
|
|
@ -102,6 +104,10 @@ FSFloaterNearbyChat::FSFloaterNearbyChat(const LLSD& key)
|
|||
|
||||
FSFloaterNearbyChat::~FSFloaterNearbyChat()
|
||||
{
|
||||
if (mRecentEmojisUpdatedCallbackConnection.connected())
|
||||
{
|
||||
mRecentEmojisUpdatedCallbackConnection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::updateFSUseNearbyChatConsole(const LLSD &data)
|
||||
|
|
@ -141,8 +147,27 @@ BOOL FSFloaterNearbyChat::postBuild()
|
|||
mChatLayoutPanelHeight = mChatLayoutPanel->getRect().getHeight();
|
||||
mInputEditorPad = mChatLayoutPanelHeight - mInputEditor->getRect().getHeight();
|
||||
|
||||
getChild<LLButton>("chat_history_btn")->setCommitCallback(boost::bind(&FSFloaterNearbyChat::onHistoryButtonClicked, 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);
|
||||
|
||||
mEmojiPickerToggleBtn = getChild<LLButton>("emoji_picker_toggle_btn");
|
||||
mEmojiPickerToggleBtn->setLabel(LLUIString(LLWString(1, 128512)));
|
||||
mEmojiPickerToggleBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerToggleBtnClicked(); });
|
||||
|
||||
mRecentEmojisUpdatedCallbackConnection = LLFloaterEmojiPicker::setRecentEmojisUpdatedCallback([this](const std::list<llwchar>& recent_emojis_list) { initEmojiRecentPanel(); });
|
||||
|
||||
getChild<LLButton>("chat_history_btn")->setCommitCallback(boost::bind(&FSFloaterNearbyChat::onHistoryButtonClicked, this));
|
||||
getChild<LLButton>("chat_search_btn")->setCommitCallback(boost::bind(&FSFloaterNearbyChat::onSearchButtonClicked, this));
|
||||
|
||||
// chat type selector and send chat button
|
||||
|
|
@ -762,6 +787,8 @@ void FSFloaterNearbyChat::sendChat( EChatType type )
|
|||
LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
|
||||
if (!text.empty())
|
||||
{
|
||||
FSCommon::updateUsedEmojis(text);
|
||||
|
||||
if(type == CHAT_TYPE_OOC)
|
||||
{
|
||||
std::string tempText = wstring_to_utf8str( text );
|
||||
|
|
@ -942,3 +969,56 @@ void FSFloaterNearbyChat::handleMinimized(bool minimized)
|
|||
gConsole->addSession(LLUUID::null);
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onEmojiRecentPanelToggleBtnClicked()
|
||||
{
|
||||
BOOL show = mEmojiRecentPanel->getVisible() ? FALSE : TRUE;
|
||||
if (show)
|
||||
{
|
||||
initEmojiRecentPanel();
|
||||
}
|
||||
|
||||
mEmojiRecentPanel->setVisible(show);
|
||||
mInputEditor->setFocus(TRUE);
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::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 FSFloaterNearbyChat::onRecentEmojiPicked(const LLSD& value)
|
||||
{
|
||||
LLSD::String str = value.asString();
|
||||
if (str.size())
|
||||
{
|
||||
LLWString wstr = utf8string_to_wstring(str);
|
||||
if (wstr.size())
|
||||
{
|
||||
llwchar emoji = wstr[0];
|
||||
mInputEditor->insertEmoji(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSFloaterNearbyChat::onEmojiPickerToggleBtnClicked()
|
||||
{
|
||||
mInputEditor->setFocus(TRUE);
|
||||
mInputEditor->showEmojiHelper();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class LLChatEntry;
|
|||
class LLComboBox;
|
||||
class LLLayoutStack;
|
||||
class LLLayoutPanel;
|
||||
class LLPanelEmojiComplete;
|
||||
class LLResizeBar;
|
||||
class LLTextBox;
|
||||
|
||||
|
|
@ -93,7 +94,6 @@ public:
|
|||
|
||||
virtual BOOL handleKeyHere( KEY key, MASK mask );
|
||||
|
||||
static void startChat(const char* line);
|
||||
static void stopChat();
|
||||
|
||||
void updateUnreadMessageNotification(S32 unread_messages, bool muted_history);
|
||||
|
|
@ -101,6 +101,8 @@ public:
|
|||
|
||||
void handleMinimized(bool minimized);
|
||||
|
||||
void onEmojiPickerToggleBtnClicked();
|
||||
|
||||
protected:
|
||||
void onChatBoxKeystroke();
|
||||
void onChatBoxFocusLost();
|
||||
|
|
@ -111,22 +113,30 @@ protected:
|
|||
void onChatBoxCommit();
|
||||
void onChatTypeChanged();
|
||||
|
||||
void reshapeFloater(bool collapse);
|
||||
void reshapeChatLayoutPanel();
|
||||
|
||||
static S32 sLastSpecialChatChannel;
|
||||
|
||||
private:
|
||||
void onChatOptionsContextMenuItemClicked(const LLSD& userdata);
|
||||
bool onChatOptionsCheckContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsVisibleContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsEnableContextMenuItem(const LLSD& userdata);
|
||||
void onChatOptionsContextMenuItemClicked(const LLSD& userdata);
|
||||
bool onChatOptionsCheckContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsVisibleContextMenuItem(const LLSD& userdata);
|
||||
bool onChatOptionsEnableContextMenuItem(const LLSD& userdata);
|
||||
|
||||
void onEmojiRecentPanelToggleBtnClicked();
|
||||
void initEmojiRecentPanel();
|
||||
void onRecentEmojiPicked(const LLSD& value);
|
||||
|
||||
FSChatHistory* mChatHistory;
|
||||
FSChatHistory* mChatHistoryMuted;
|
||||
LLChatEntry* mInputEditor;
|
||||
|
||||
// chat type selector and send chat buttons
|
||||
LLButton* mEmojiRecentPanelToggleBtn;
|
||||
LLButton* mEmojiPickerToggleBtn;
|
||||
LLLayoutPanel* mEmojiRecentPanel;
|
||||
LLTextBox* mEmojiRecentEmptyText;
|
||||
LLPanelEmojiComplete* mEmojiRecentIconsCtrl;
|
||||
LLButton* mSendChatButton;
|
||||
LLComboBox* mChatTypeCombo;
|
||||
|
||||
|
|
@ -145,6 +155,8 @@ private:
|
|||
std::vector<LLChat> mMessageArchive;
|
||||
|
||||
BOOL FSUseNearbyChatConsole;
|
||||
|
||||
boost::signals2::connection mRecentEmojisUpdatedCallbackConnection{};
|
||||
};
|
||||
|
||||
#endif // FS_FLOATERNEARBYCHAT_H
|
||||
|
|
|
|||
|
|
@ -253,6 +253,8 @@ void FSNearbyChat::sendChat(LLWString text, EChatType type)
|
|||
|
||||
if (!text.empty())
|
||||
{
|
||||
FSCommon::updateUsedEmojis(text);
|
||||
|
||||
if (type == CHAT_TYPE_OOC)
|
||||
{
|
||||
text = utf8string_to_wstring(gSavedSettings.getString("FSOOCPrefix") + " ") + text + utf8string_to_wstring(" " + gSavedSettings.getString("FSOOCPostfix"));
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue