-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ca20663
Showing
19 changed files
with
585 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.DS_Store | ||
.vscode | ||
out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
This project is based on the Twemoji project, Copywrite 2019 Twitter Inc, | ||
to the brightscript language and scenegraph user interface. You can | ||
find the origional project here: https://github.com/twitter/twemoji. | ||
Special thanks to Twitter and all contributors to the Twemoji project | ||
for making this possible. | ||
|
||
Twemoji is licensed under the MIT License, | ||
https://github.com/twitter/twemoji/blob/master/LICENSE. | ||
|
||
Specific uses: The code to generate file names from emoji raw text | ||
was used and adapted for brightscript, and can be found in origional | ||
form here: https://github.com/twitter/twemoji/blob/master/scripts/build.js. | ||
|
||
The Regular Expression for detecting Emojis is derived from the | ||
emoji-regex project by Mathias Bynens, Copywrite Mathias Bynens. You can | ||
find the emoji-regex project here: | ||
https://github.com/mathiasbynens/emoji-regex. | ||
Special thanks to @mathiasbynens and all contributors to the emoji-regex | ||
project for making this possible. | ||
|
||
emoji-regex is licensed under the MIT License, | ||
https://github.com/mathiasbynens/emoji-regex/blob/master/LICENSE. | ||
|
||
Specific uses: The regex found here: | ||
https://github.com/mathiasbynens/emoji-regex/blob/master/es2015/RGI_Emoji.js | ||
was modified to fit the schema of PCRE to be accepted by Roku's regex | ||
component. PCRE documentation can be found here: http://www.pcre.org/. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
Copyright (c) 2020 Kasper Gammeltoft and other contributors | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Emoji On Roku | ||
This project is a port of the Twitter Emoji Project, [Twemoji](https://twemoji.twitter.com/). | ||
The aim of this project is to provide Emoji support on Roku using scenegraph and brightscript. | ||
|
||
## Installation | ||
|
||
Download the zip containing the source, and unzip the source files. | ||
Place the source and components directories inside your project, in the same | ||
folder. | ||
|
||
Alternativly, use component libraries to install the EmojiOnRoku project. | ||
See the component library documentation here: | ||
https://developer.roku.com/docs/references/scenegraph/control-nodes/componentlibrary.md. | ||
|
||
Also check the releases page on this Github repository for the correct url for the component | ||
library. Checkout the demo project for a working example. | ||
|
||
## Usage | ||
|
||
To use emoji in your project, create an `EmojiLabel` and set its `text` property to a string | ||
containing emojis: | ||
**Code:** | ||
```brightscript | ||
myEmojiLabel = createObject("roSGNode", "EmojiLabel") | ||
myEmojiLabel.text = "Hello 👨🏻🦰! I am happy 😊 to see you. See emoji 👩🏽🦱 chars!" | ||
myEmojilabel.translation=[200, 500] | ||
m.top.appendChild(myEmojiLabel) | ||
``` | ||
|
||
**Result**: | ||
|
||
![example](docs/simpleExample.jpg) | ||
|
||
You can also set the color, font, height, and other properties like you would on an ordinary | ||
Scenegraph `Label` node. The emojis are shown at | ||
72x72 size unless you specify the height or emojiSize | ||
properties: | ||
**Code:** | ||
```brightscript | ||
myEmojiLabel.height = 24 | ||
myEmojiLabel.color = &h00AAEEFF | ||
``` | ||
**Result:** | ||
|
||
![heightexample](docs/heightExample.jpg) | ||
|
||
Finally, aligment can also be used, just as for normal Scenegraph `Label` nodes as well. | ||
Here are all `horizAlign` and `vertAlign` combinations for the same `EmojiLabel`, who | ||
has a width and height set to the fullscreen size. | ||
|
||
Note that it is recommended to use `center` for `vertAlign` (the defualt), since this will align the emojis | ||
relative to the text labels as well. | ||
**Code:** | ||
```brightscript | ||
myEmojiLabel.width = 1920 | ||
myEmojiLabel.height = 1080 | ||
myEmojiLabel.horizAlign = "left" ' or "center" or "right" | ||
myEmojiLabel.vertAlign = "top" ' or "center" or "bottom" | ||
myEmojiLabel.color = &h00AAEEFF | ||
``` | ||
**Result:** | ||
|
||
![alignexample](/docs/alignments.jpg) | ||
|
||
Note that it is recommended to set an explicit width on labels before using `"center"` or `"right"` for `horizAlign`. | ||
|
||
When setting an explicit width, if the width of the label/emojis go over that width, the labels will use an ellipsis. | ||
If the cutoff is in the middle of an emoji, however, the emoji will not be replaced by an ellipsis. | ||
|
||
## License | ||
Copyright 2020 Kasper Gammeltoft | ||
Code licensed under the MIT License: http://opensource.org/licenses/MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
' Copyright Kasper Gammeltoft and other contributors. Licensed under MIT | ||
' https://github.com/KasperGam/emojionroku/blob/master/LICENSE | ||
sub init() | ||
m.components = m.top.findNode("layout") | ||
m.top.observeField("text", "setText") | ||
|
||
m.top.observeField("color", "updateComponents") | ||
m.top.observeField("font", "updateComponents") | ||
m.top.observeField("horizAlign", "updateComponents") | ||
m.top.observeField("vertAlign", "updateComponents") | ||
m.top.observeField("width", "updateComponents") | ||
m.top.observeField("height", "updateComponents") | ||
m.top.observeField("emojiSize", "updateComponents") | ||
|
||
setText() | ||
end sub | ||
|
||
' Will update the components if an interface field has changed. | ||
function updateComponents() | ||
' Only update components if we are actually rendering text | ||
if m.top.text <> "" | ||
width = m.top.width | ||
height = m.top.height | ||
hAlign = m.top.horizAlign | ||
vAlign = m.top.vertAlign | ||
|
||
' Set the layout group properties to reflect the horiz and vert | ||
' aligments | ||
m.components.horizAlignment = hAlign | ||
m.components.vertAlignment = vAlign | ||
|
||
' Set component properties | ||
comps = getAllComponents() | ||
for each comp in comps | ||
comp.visible = true | ||
if comp.subtype() = "Label" | ||
comp.width = 0 | ||
comp.height = height | ||
comp.vertAlign = vAlign | ||
comp.color = m.top.color | ||
if m.top.font <> Invalid | ||
comp.font = m.top.font | ||
end if | ||
else | ||
' For posters, use emojiSize first if set | ||
if m.top.emojiSize > 0 | ||
comp.width = m.top.emojiSize | ||
comp.height = m.top.emojiSize | ||
' Then use height if set | ||
else if height > 0 | ||
comp.width = height | ||
comp.height = height | ||
else | ||
comp.width = 0 | ||
comp.height = 0 | ||
end if | ||
end if | ||
end for | ||
|
||
' Check if we need to use ellipsis for this label | ||
checkBoundingWidth() | ||
|
||
boundingWidth = m.components.boundingRect().width | ||
if width = 0 or boundingWidth > width | ||
width = boundingWidth | ||
end if | ||
|
||
if m.top.emojiSize > height | ||
height = m.top.emojiSize | ||
end if | ||
' Set proper translation for horizontal alignment | ||
xTranslation = 0 | ||
yTranslation = 0 | ||
' For center, that is in the middle of the node | ||
if hAlign = "center" | ||
xTranslation = width / 2 | ||
' For right, that is the right edge of the node | ||
else if hAlign = "right" | ||
xTranslation = width | ||
end if | ||
|
||
' Set proper translation for vertical alignment | ||
' For center, use the middle of the node | ||
if vAlign = "center" | ||
yTranslation = height / 2 | ||
' For bottom, use bottom edge of node | ||
else if vAlign = "bottom" | ||
yTranslation = height | ||
end if | ||
|
||
m.components.translation = [xTranslation, yTranslation] | ||
end if | ||
end function | ||
|
||
' Convenience function to check if we need to truncate the label | ||
function checkBoundingWidth() | ||
curWidth = 0 | ||
width = m.top.width | ||
' Reset previous ellipsis if present | ||
existingEllipsis = m.components.findNode("ellipsis") | ||
if existingEllipsis <> Invalid | ||
m.components.removeChild(existingEllipsis) | ||
end if | ||
|
||
comps = getAllComponents() | ||
|
||
for index = 0 to comps.count() - 1 | ||
comp = comps[index] | ||
' If we are already over the width, then don't display any other components | ||
if curWidth >= width | ||
comp.visible = false | ||
else | ||
' See if this component extends beyond the available width | ||
compWidth = comp.boundingRect().width | ||
curWidth += compWidth | ||
|
||
if curWidth > width and width > 0 | ||
diff = curWidth - width | ||
|
||
' For labels, we might be able to have the label use proper ellipsis by itself | ||
if comp.subType() = "Label" | ||
newCompWidth = compWidth - diff | ||
ellipsis = createLabel("…") | ||
minWidth = ellipsis.boundingRect().width | ||
' If the label is too short to have an ellipsis itself, insert one here | ||
if newCompWidth <= minWidth | ||
comp.visible = false | ||
ellipsis.id = "ellipsis" | ||
m.components.insertChild(ellipsis, index) | ||
else | ||
' Label will use ellipsis with explicit width set | ||
comp.width = newCompWidth | ||
end if | ||
else | ||
' Replace with ellipsis | ||
comp.visible = false | ||
ellipsis = createLabel("…") | ||
ellipsis.id = "ellipsis" | ||
m.components.insertChild(ellipsis, index) | ||
end if | ||
end if | ||
end if | ||
end for | ||
end function | ||
|
||
' Updates the entire label components with new text. | ||
function setText() | ||
labelText = m.top.text | ||
|
||
resetComponents() | ||
if labelText <> "" | ||
' Check for emojis in this text | ||
emojiRegex = createObject("roRegex", regex(), "m") | ||
matches = emojiRegex.matchAll(labelText) | ||
|
||
for each match in matches | ||
matchText = match[0] | ||
' Create the label representing all text before this match, | ||
' if there is any | ||
loc = labelText.instr(matchText) | ||
if loc > 0 | ||
leftText = labelText.left(loc) | ||
m.components.appendChild(createLabel(leftText)) | ||
end if | ||
|
||
' Get the URI for this emoji and create the poster | ||
pointURI = emojiPointName(matchText) | ||
m.components.appendChild(createPoster(pointURI)) | ||
|
||
' Update the remaining text. Set to be text after this emoji. | ||
labelText = labelText.mid(loc + matchText.len()) | ||
end for | ||
|
||
' If we have text at the end after the last emoji match, create | ||
' a label for that text. | ||
if labelText <> "" | ||
m.components.appendChild(createLabel(labelText)) | ||
end if | ||
end if | ||
|
||
' Update the components. | ||
updateComponents() | ||
end function | ||
|
||
' Create a new label to display non-emoji text in the label. | ||
function createLabel(withText as String) | ||
label = createObject("roSGNode", "Label") | ||
label.text = withText | ||
label.color = m.top.color | ||
label.vertAlign = m.top.vertAlign | ||
label.height = m.top.height | ||
if m.top.font <> Invalid | ||
label.font = m.top.font | ||
end if | ||
|
||
return label | ||
end function | ||
|
||
' Create a new poster to show an emoji with. | ||
function createPoster(uri as String) | ||
poster = CreateObject("roSGNode", "Poster") | ||
poster.uri = uri | ||
|
||
' Use emoji size first if set | ||
if m.top.emojiSize > 0 | ||
poster.width = m.top.emojiSize | ||
poster.height = m.top.emojiSize | ||
' Then use height if set | ||
else if m.top.height > 0 | ||
poster.width = m.top.height | ||
poster.height = m.top.height | ||
end if | ||
|
||
return poster | ||
end function | ||
|
||
' Returns all components for the current emoji label. | ||
function getAllComponents() | ||
components = [] | ||
for i = 0 to m.components.getChildCount() - 1 | ||
components.push(m.components.getChild(i)) | ||
end for | ||
|
||
return components | ||
end function | ||
|
||
' Removes all child components to reset the layout group. | ||
function resetComponents() | ||
while m.components.getChildCount() > 0 | ||
m.components.removeChildIndex(0) | ||
end while | ||
end function |
Oops, something went wrong.