The experiment below (updated for Codea version 1.5.1), for exploring pages of Unicode characters, was created around the same time that I was experimenting with emoji. (Update: now also allows for an emoji-friendly font to be chosen, when required.)
--
-- Unicode Viewer
--
supportedOrientations(LANDSCAPE_ANY)
function setup()
PageLow, PageHigh, Plane = 0, 0, 0
page = (Plane * 0x100 + PageHigh * 0x10 + PageLow) * 0x100
img = image(WIDTH, HEIGHT)
parameter.integer("PageLow", 0, 15, PageLow, changed)
parameter.integer("PageHigh", 0, 15, PageHigh, changed)
parameter.integer("Plane", 0, 2, Plane, changed)
parameter.boolean("isEmojiFriendly", true, efChanged)
fill(255)
stroke(0, 255, 0)
strokeWidth(2.5)
spriteMode(CENTER)
textMode(CENTER)
rectMode(CENTER)
isZoomed = false
pickedCharUnicode = nil
pickedChar = nil
print("Tap to zoom in")
print("Tap to zoom out.")
print()
print("A white box means no character is defined for that code.")
end
function changed()
page = (Plane * 0x100 + PageHigh * 0x10 + PageLow) * 0x100
latency = ElapsedTime + 0.08
redraw = true
isZoomed = false
end
function efChanged()
if isEmojiFriendly then
f = "AppleColorEmoji"
else
f = "ArialMT"
end
drawPage(img, page)
end
function drawPage(img, base)
setContext(img)
background(0)
fill(255)
font(f)
fontSize(40)
for j = 0, 15 do
for i = 0, 15 do
local u = base + i * 0x10 + j
local char = unicode2UTF8(u)
local x = WIDTH/16 * (i + 1/2)
local y = HEIGHT/16 * (15 - j + 1/2)
text(char, x, y)
end
end
setContext()
end
function draw()
background(0)
if redraw and ElapsedTime > latency then
drawPage(img, page)
redraw = false
end
if isZoomed then
line(0, HEIGHT/2, WIDTH, HEIGHT/2)
line(WIDTH/2, 0, WIDTH/2, HEIGHT)
font(f)
fontSize(512)
local w, h = textSize(pickedChar)
local fm = fontMetrics()
noFill()
rect(WIDTH/2, HEIGHT/2, w, h)
fill(255)
text(pickedChar, WIDTH/2, HEIGHT/2)
fontSize(64)
fill(0)
text(pickedChar, WIDTH/2 + 1, 149)
fill(255)
text(pickedChar, WIDTH/2, 150)
font("Inconsolata")
fontSize(64)
local title = string.format("U+%4X", pickedCharUnicode)..
" (= "..pickedCharUnicode..")"
text(title, WIDTH/2, 50)
else
sprite(img, WIDTH/2, HEIGHT/2)
end
end
function touched(touch)
if touch.state == BEGAN then
if isZoomed then
isZoomed = false
else
isZoomed = true
local i = math.floor(touch.x/WIDTH * 16)
local j = 15 - math.floor(touch.y/HEIGHT * 16)
pickedCharUnicode = page + i * 0x10 + j
pickedChar = unicode2UTF8(pickedCharUnicode)
end
end
end
-- Unicode code point to UTF-8 format string of bytes
--
-- Bit Last point Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
-- 7 U+007F 0xxxxxxx
-- 11 U+07FF 110xxxxx 10xxxxxx
-- 16 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
-- 21 U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-- 26 U+3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
-- 31 U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
--
-- However, largest integer in Codea's Lua is 0x7FFFFF (23 bit)
-- With acknowledgement also to Andrew Stacey's UTF-8 library
function unicode2UTF8(u)
u = math.max(0, math.floor(u)) -- A positive integer
local UTF8
if u < 0x80 then -- less than 8 bits
UTF8 = string.char(u)
elseif u < 0x800 then -- less than 12 bits
local b2 = u % 0x40 + 0x80
local b1 = math.floor(u/0x40) + 0xC0
UTF8 = string.char(b1, b2)
elseif u < 0x10000 then -- less than 16 bits
local b3 = u % 0x40 + 0x80
local b2 = math.floor(u/0x40) % 0x40 + 0x80
local b1 = math.floor(u/0x1000) + 0xE0
UTF8 = string.char(b1, b2, b3)
elseif u < 0x200000 then -- less than 22 bits
local b4 = u % 0x40 + 0x80
local b3 = math.floor(u/0x40) % 0x40 + 0x80
local b2 = math.floor(u/0x1000) % 0x40 + 0x80
local b1 = math.floor(u/0x40000) + 0xF0
UTF8 = string.char(b1, b2, b3, b4)
elseif u < 0x800000 then -- less than 24 bits
local b5 = u % 0x40 + 0x80
local b4 = math.floor(u/0x40) % 0x40 + 0x80
local b3 = math.floor(u/0x1000) % 0x40 + 0x80
local b2 = math.floor(u/0x40000) % 0x40 + 0x80
local b1 = math.floor(u/0x1000000) + 0xF8
UTF8 = string.char(b1, b2, b3, b4, b5)
else
print("Error: Code point too large for Codea's Lua.")
end
return UTF8
end
```
Drawing a page of 256 characters with `text()` takes a little time. To reduce the effects of latency on the parameter sliders, and when zooming in or out, I use an image (`img`) to hold the current page of characters and introduce a 0.08 second delay between the last change of the parameter sliders and the redrawing of the page (by `drawPage()`).