ASCII art and UTF8 emojis explorer

Godot Version

3.x

Question

Why is Label trimming more than 3 consecutive' ' spaces? (godot3.6,4.3)
Why can't see emojies in my UTF8-xplorer'? (godot3.6)

Hello there.

Deving a complex ascii art game and been struggling to put the actual contents of some well crafted text files with ASCII art on Label objects. As you might expect from title, ascii art txt files are getting their lovely white spaces removed, and is hard to input certain characters at center locations. I understand this can be desired behavior for most users, but breaks ascii art. If any experienced dev could point me to the Label trimming white spaces code, or an easy way to bypass this would be great. Using a single Label object with the full string from an ascii art .txt file on resources and you will notice above 3 spaces next characters are shifted and breaks art alignment. even using unicode space with no breaks still gets eaten/trimmed.

Also extending support to emojies, so i devved a nice UTF8-xplorer attached here for you to try it out, having a hard time to find the actual ranges for specific emojies (you can use the slider or the arrow keys, i can see some chars and occasionally some emojies, but never the expected emoji map i need to make to make this game happen). I tried the emoji addon which works, but in need of rawer access to emoji gen. Also you need an emoji font, tried a couple already, still not there yet.

Would be great to hear some input, if you can chyme in please do.

See you around ~
&c

→ scene with root control node, emoji font, attach the script and run

extends Control

var utf8_label
var utf8_slider
var utf8_value_label
var utf8_byte_label
var utf8_output_label
var utf8_text_edit

const MARGIN_PERCENT = 0.2
const MIN_CHAR_CODE = 32
const MAX_CHAR_CODE = 0x10FFFF  # Full Unicode range
const MAX_TEXT_LENGTH = 1000  # Maximum number of characters in the text field

var emoji_font: DynamicFont = DynamicFont.new()

func _ready():
	
	# Load a font that supports emojis
	emoji_font.font_data = load("res://NotoEmoji-Regular.ttf")
	if not emoji_font:
		print("Warning: Emoji font not loaded. Emojis may not display correctly.")
	
	setup_ui()
	
	utf8_slider.connect("value_changed", self, "_on_slider_value_changed")
	utf8_text_edit.connect("text_changed", self, "_on_text_edit_changed")
	
	utf8_slider.min_value = MIN_CHAR_CODE
	utf8_slider.max_value = MAX_CHAR_CODE
	utf8_slider.step = 1
	
	utf8_slider.value = MIN_CHAR_CODE

func setup_ui():
	var viewport_size = get_viewport().size
	var margin_size = Vector2(viewport_size.x * MARGIN_PERCENT, viewport_size.y * MARGIN_PERCENT)

	# Create and set up the ui's
	utf8_label = Label.new()
	utf8_label.text = "Drag the slider or use arrow keys to select a UTF-8 character:"
	add_child(utf8_label)
	utf8_label.set_position(margin_size)
	utf8_label.set_size(Vector2(viewport_size.x - 2 * margin_size.x, utf8_label.get_minimum_size().y), false)

	utf8_slider = HSlider.new()
	add_child(utf8_slider)
	utf8_slider.set_size(Vector2(viewport_size.x - 2 * margin_size.x, 0))
	utf8_slider.set_position(margin_size + Vector2(0, utf8_label.get_minimum_size().y + 10))

	utf8_value_label = Label.new()
	add_child(utf8_value_label)
	utf8_value_label.set_position(utf8_slider.rect_position + Vector2(0, utf8_slider.get_minimum_size().y + 10))
	utf8_value_label.set_size(Vector2(viewport_size.x - 2 * margin_size.x, utf8_value_label.get_minimum_size().y))

	utf8_byte_label = Label.new()
	add_child(utf8_byte_label)
	utf8_byte_label.set_position(utf8_value_label.rect_position + Vector2(0, utf8_value_label.get_minimum_size().y + 10))
	utf8_byte_label.set_size(Vector2(viewport_size.x - 2 * margin_size.x, utf8_byte_label.get_minimum_size().y))

	utf8_output_label = Label.new()
	add_child(utf8_output_label)
	utf8_output_label.set_position(utf8_byte_label.rect_position + Vector2(0, utf8_byte_label.get_minimum_size().y + 10))
	utf8_output_label.set_size(Vector2(viewport_size.x - 2 * margin_size.x, utf8_output_label.get_minimum_size().y))

	# Create and set up the TextEdit for manual entry of UTF-8 characters
	utf8_text_edit = TextEdit.new()
	add_child(utf8_text_edit)
	utf8_text_edit.set_size(Vector2(viewport_size.x - 2 * margin_size.x, viewport_size.y * 0.3))
	utf8_text_edit.set_position(utf8_output_label.rect_position + Vector2(0, utf8_output_label.get_minimum_size().y + 10))
#	utf8_text_edit.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY  # Enable word wrap
	
	# Set emoji font if loaded
	if emoji_font:
		utf8_text_edit.add_font_override("font", emoji_font)
		utf8_output_label.add_font_override("font", emoji_font)


func _on_slider_value_changed(value):
	update_utf8_display(value)

func _input(event):
	if event is InputEventKey and event.pressed:
		if event.scancode == KEY_LEFT:
			utf8_slider.value -= 1
		elif event.scancode == KEY_RIGHT:
			utf8_slider.value += 1

func _on_text_edit_changed():
	var text = utf8_text_edit.text
	# If the text is too long, remove characters from the beginning
	if text.length() > MAX_TEXT_LENGTH:
		text = text.substr(text.length() - MAX_TEXT_LENGTH)
		utf8_text_edit.text = text
#		utf8_text_edit.set_caret_line(utf8_text_edit.get_line_count() - 1)
#		utf8_text_edit.set_caret_column(utf8_text_edit.get_line(utf8_text_edit.get_line_count() - 1).length())


func update_utf8_display(value):
	utf8_value_label.text = "Character Code: U+%X" % value
	# Convert the value to UTF-8 bytes
	var utf8_bytes = char(value).to_utf8()
	# Create a string representation of the byte sequence
	var byte_sequence = "Byte Sequence: "
	for byte in utf8_bytes:
		byte_sequence += "0x%02X " % byte
	utf8_byte_label.text = byte_sequence.strip_edges()
	# Convert the value to a UTF-8 character
	var c = char(value)
	utf8_output_label.text = "Character: " + c
	utf8_text_edit.insert_text_at_cursor(c)



# new stuff to put in

# Emoji ranges
const EMOJI_RANGES = [
	[0x1F300, 0x1F5FF],
	[0x1F600, 0x1F64F],
	[0x1F680, 0x1F6FF],
	[0x2600, 0x26FF],
	[0x2700, 0x27BF],
	[0x1F900, 0x1F9FF]
]



not sure need to fully test but glancing at Label source code, where does tr(string) function comes from? apparently can utf8_output_label.clip_text = false need to test further if does not trim white spaces…

as a workaround, i’ve been using:
labelobject.text = text.replace("_"," ") #works
but removes ‘_’ as a possible character in the ascii art, while it sort of works since keeps all spaces and newlines when needed, there should be an option not to trim multiple white spaces from lines.

as for emojis, would be really great to support it out of the box in label.text. only gremlins appear if you do something like:

label.text = " #*0123456789©®‍‼⁉⃣™ℹ↔↕↖↗↘↙↩↪⌚⌛⌨⏏⏩⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳⏸⏹⏺Ⓜ▪▫▶◀◻◼◽◾☀☁☂☃☄☎☑☔☕☘☝☠☢☣ ☦☪☮☯☸☹☺♀♂♈♉♊♋♌♍♎♏♐♑♒♓♟♠♣♥♦♨♻♾♿⚒⚓⚔⚕⚖⚗⚙⚛⚜⚠⚡⚧⚪⚫⚰⚱⚽⚾⛄⛅⛈⛎⛏⛑⛓⛔⛩⛪⛰⛱⛲⛳⛴⛵⛷⛸⛹⛺⛽✂ ✅✈✉✊✋✌✍✏✒✔✖✝✡✨✳✴❄❇❌❎❓❔❕❗❣❤➕➖➗➡➰➿⤴⤵⬅⬆⬇⬛⬜⭐⭕〰〽㊗㊙🀄🃏🅰🅱🅾🅿🆎🆑🆒🆓🆔🆕🆖🆗🆘🆙🆚🇦🇧🇨🇩🇪🇫🇬🇭 🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿🈁🈂🈚🈯🈲🈳🈴🈵🈶🈷🈸🈹🈺🉐🉑🌀🌁🌂🌃🌄🌅🌆🌇🌈🌉🌊🌋🌌🌍🌎🌏🌐🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌝🌞🌟🌠🌡🌤🌥🌦 🌧🌨🌩🌪🌫🌬🌭🌮🌯🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬 🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼🍽🍾🍿🎀🎁🎂🎃🎄🎅🎆🎇🎈🎉🎊🎋🎌🎍🎎🎏🎐🎑🎒🎓🎖🎗🎙🎚🎛🎞🎟🎠🎡🎢🎣🎤🎥🎦🎧🎨🎩🎪🎫🎬🎭🎮🎯🎰🎱🎲🎳🎴🎵🎶🎷 🎸🎹🎺🎻🎼🎽🎾🎿🏀🏁🏂🏃🏄🏅🏆🏇🏈🏉🏊🏋🏌🏍🏎🏏🏐🏑🏒🏓🏔🏕🏖🏗🏘🏙🏚🏛🏜🏝🏞🏟🏠🏡🏢🏣🏤🏥🏦🏧🏨🏩🏪🏫🏬🏭🏮🏯🏰🏳🏴🏵🏷🏸🏹🏺🏻🏼🏽🏾🏿🐀 🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿👀👁👂👃👄👅👆 👇👈👉👊👋👌👍👎👏👐👑👒👓👔👕👖👗👘👙👚👛👜👝👞👟👠👡👢👣👤👥👦👧👨👩👪👫👬👭👮👯👰👱👲👳👴👵👶👷👸👹👺👻👼👽👾👿💀💁💂💃💄💅💆💇💈💉💊💋💌 💍💎💏💐💑💒💓💔💕💖💗💘💙💚💛💜💝💞💟💠💡💢💣💤💥💦💧💨💩💪💫💬💭💮💯💰💱💲💳💴💵💶💷💸💹💺💻💼💽💾💿📀📁📂📃📄📅📆📇📈📉📊📋📌📍📎📏📐📑📒 📓📔📕📖📗📘📙📚📛📜📝📞📟📠📡📢📣📤📥📦📧📨📩📪📫📬📭📮📯📰📱📲📳📴📵📶📷📸📹📺📻📼📽📿🔀🔁🔂🔃🔄🔅🔆🔇🔈🔉🔊🔋🔌🔍🔎🔏🔐🔑🔒🔓🔔🔕🔖🔗🔘🔙 🔚🔛🔜🔝🔞🔟🔠🔡🔢🔣🔤🔥🔦🔧🔨🔩🔪🔫🔬🔭🔮🔯🔰🔱🔲🔳🔴🔵🔶🔷🔸🔹🔺🔻🔼🔽🕉🕊🕋🕌🕍🕎🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧🕯🕰🕳🕴 🕵🕶🕷🕸🕹🕺🖇🖊🖋🖌🖍🖐🖕🖖🖤🖥🖨🖱🖲🖼🗂🗃🗄🗑🗒🗓🗜🗝🗞🗡🗣🗨🗯🗳🗺🗻🗼🗽🗾🗿😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝 😞😟😠😡😢😣😤😥😦😧😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏🚀🚁🚂🚃🚄🚅🚆🚇🚈🚉🚊🚋🚌🚍🚎🚏🚐🚑🚒🚓 🚔🚕🚖🚗🚘🚙🚚🚛🚜🚝🚞🚟🚠🚡🚢🚣🚤🚥🚦🚧🚨🚩🚪🚫🚬🚭🚮🚯🚰🚱🚲🚳🚴🚵🚶🚷🚸🚹🚺🚻🚼🚽🚾🚿🛀🛁🛂🛃🛄🛅🛋🛌🛍🛎🛏🛐🛑🛒🛕🛖🛗🛜🛝🛞🛟🛠🛡🛢🛣🛤 🛥🛩🛫🛬🛰🛳🛴🛵🛶🛷🛸🛹🛺🛻🛼🟠🟡🟢🟣🟤🟥🟦🟧🟨🟩🟪🟫🟰🤌🤍🤎🤏🤐🤑🤒🤓🤔🤕🤖🤗🤘🤙🤚🤛🤜🤝🤞🤟🤠🤡🤢🤣🤤🤥🤦🤧🤨🤩🤪🤫🤬🤭🤮🤯🤰🤱🤲🤳🤴🤵 🤶🤷🤸🤹🤺🤼🤽🤾🤿🥀🥁🥂🥃🥄🥅🥇🥈🥉🥊🥋🥌🥍🥎🥏🥐🥑🥒🥓🥔🥕🥖🥗🥘🥙🥚🥛🥜🥝🥞🥟🥠🥡🥢🥣🥤🥥🥦🥧🥨🥩🥪🥫🥬🥭🥮🥯🥰🥱🥲🥳🥴🥵🥶🥷🥸🥹🥺🥻🥼🥽 🥾🥿🦀🦁🦂🦃🦄🦅🦆🦇🦈🦉🦊🦋🦌🦍🦎🦏🦐🦑🦒🦓🦔🦕🦖🦗🦘🦙🦚🦛🦜🦝🦞🦟🦠🦡🦢🦣🦤🦥🦦🦧🦨🦩🦪🦫🦬🦭🦮🦯🦰🦱🦲🦳🦴🦵🦶🦷🦸🦹🦺🦻🦼🦽🦾🦿🧀🧁🧂🧃 🧄🧅🧆🧇🧈🧉🧊🧋🧌🧍🧎🧏🧐🧑🧒🧓🧔🧕🧖🧗🧘🧙🧚🧛🧜🧝🧞🧟🧠🧡🧢🧣🧤🧥🧦🧧🧨🧩🧪🧫🧬🧭🧮🧯🧰🧱🧲🧳🧴🧵🧶🧷🧸🧹🧺🧻🧼🧽🧾🧿🩰🩱🩲🩳🩴🩵🩶🩷🩸🩹 🩺🩻🩼🪀🪁🪂🪃🪄🪅🪆🪇🪈🪐🪑🪒🪓🪔🪕🪖🪗🪘🪙🪚🪛🪜🪝🪞🪟🪠🪡🪢🪣🪤🪥🪦🪧🪨🪩🪪🪫🪬🪭🪮🪯🪰🪱🪲🪳🪴🪵🪶🪷🪸🪹🪺🪻🪼🪽🪿🫀🫁🫂🫃🫄🫅🫎🫏🫐🫑🫒 🫓🫔🫕🫖🫗🫘🫙🫚🫛🫠🫡🫢🫣🫤🫥🫦🫧🫨🫰🫱🫲🫳🫴🫵🫶🫷🫸󠀰󠀱󠀲󠀳󠀴󠀵󠀶󠀷󠀸󠀹󾓥󾓦󾓧󾓨󾓩󾓪 (emoji list from notocoloremoji.ttf, works fine here on the web too, just not in Godot Labels)

Full emoji support is available out of the box in Godot 4, although the web platform still needs a custom emoji font loaded as the web platform can’t use system-provided fonts. Emoji fonts are pretty large in size, which is why a system font fallback is used by default to support them.

Great to hear that “Full emoji support” is available, but in my Godot 4.3 copy on linux64, in a RichTextLabel object, try to copy the above string from Noto Emoji into the inspectors text field. I get very dim support, take a look at this screenshot.

Would be great to hear your thoughts on the utf8 explorer above, how to call emojis from a font file:)

Also would be great this support could extend to Godot 3. (Low end devices single core netbooks at 1ghz cpu, or like the raspberry pi, which is our main target platform)

Also if you could pitch in about Label trimming spaces would be great. Not nice extra step of having to replace all spaces with underscores, them on gdscript rplace underscores with spaces, but works

Is it trimming the spaces or is it font kerning?
Would switching to a monospaced font fix the issue?

It’s trimming the spaces, more than 3 consecutive spaces.

Using a couple of monospace fonts on Label’s font override same thing. Though, of course it should work on any font file. I’ve tracked it down to the tr function on Label.cpp. Have to test if bypassing it solves the issue

Example that should work Label.text, Godot3,4="
`
*

                 *                       *

                                                                     *

                             *

        *



            Hi

                           This  is         t  e   x       t fi   l  es  

`
"

You see the confusion I am having is that if you give a label the text of 10 spaces and then print out the text of the label you will get 10 spaces printed.
So is the trimming occurring on the label drawing only?
And then if you give one label the text ">>(10 spaces)<<" and another label the text ">>(9 spaces)<<" you will see that the first label (10 spaces) is slightly bigger than the second label (9 spaces).
So I don’t understand where you are seeing trimming.
Ironically, this message board does in fact trim consecutive spaces and I couldn’t get around that.

Hey, thanks. Got down to this spacing issues. No trimming going on. Was using tabs instead of spaces, from loading text files onto strings, tab’s the culprit, tabs are not properly converted to 4/8 spaces. Also found out about triple quoting multiline strings, gonna ease a lot:). Cowsay is trimming, not Godot Labels;)

Come on, lets bring full emojis in Godot3. And official raspbian support ;). Already some nice binaries running on some PI’s here.

Good day and happy coding

Godot 3.x can’t have full emoji support due to how text is rendered internally (surrogate pairs are not handled correctly). Fixing this requires a compatibility-breaking change, which was only done in Godot 4.0.

Godot 3.6 has official Linux ARM binaries available for ARMv7 and AArch64, but they aren’t listed on the website yet.

You can download them here for now:

https://downloads.tuxfamily.org/godotengine/3.6/

You guys just made my day :wink: So so so nice!

That’s ok. Thanks for considering it. Probably there’s a way with simple fonts with drawings that works enough for these purposes