mirror of
https://github.com/airstruck/luigi.git
synced 2025-11-18 12:25:06 +00:00
word wrap
This commit is contained in:
@@ -29,6 +29,7 @@ local style = {
|
||||
padding = 8,
|
||||
background = { 255, 255, 255 },
|
||||
icon = 'icon/32px/Box.png',
|
||||
multiline = true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -71,8 +72,8 @@ local mainForm = { id = 'mainWindow', type = 'panel',
|
||||
{ id = 'leftSideBox', width = 200, minwidth = 64,
|
||||
{ text = 'Hi, I\'m centered middle. ', style = 'listThing',
|
||||
align = 'middle center' },
|
||||
{ text = 'Hi, I\'m centered bottom. ', style = 'listThing',
|
||||
align = 'bottom center', slices = 'luigi/theme/light/button.png' },
|
||||
{ text = 'Hi, I\'m right bottom.\nAlso two lines, woopdy woop.Hi, I\'m right bottom.\nAlso two lines, woopdy woop.Hi, I\'m right bottom.\nAlso two lines, woopdy woop.', style = 'listThing',
|
||||
align = 'bottom right', slices = 'luigi/theme/light/button.png' },
|
||||
{ text = 'Hi, I\'m centered top. ', style = 'listThing',
|
||||
align = 'top center' },
|
||||
{ text = 'A man, a plan, a canal: Panama!', style = 'listThing' },
|
||||
@@ -154,13 +155,30 @@ end)
|
||||
|
||||
layout.mainCanvas.font = 'font/liberation/LiberationMono-Regular.ttf'
|
||||
|
||||
layout.mainCanvas.text = [[Abedede sdfsdf asfdsdfdsfs sdfsdfsdf
|
||||
sfsdfdfbv db er erg rth tryj ty j fgh dfgv
|
||||
wefwef rgh erh rth e rgs dvg eh tyj rt h erg
|
||||
erge rg eg erg er ergs erg er ge rh erh rth]]
|
||||
layout.mainCanvas.text = [[
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
|
||||
|
||||
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
|
||||
One
|
||||
two
|
||||
Three
|
||||
four
|
||||
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
]]
|
||||
|
||||
layout.mainCanvas.align = 'top'
|
||||
|
||||
layout.mainCanvas.multiline = true
|
||||
|
||||
local Backend = require 'luigi.backend'
|
||||
|
||||
layout.menuQuit:onPress(function (event) Backend.quit() end)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
local ROOT = (...):gsub('[^.]*$', '')
|
||||
|
||||
local Backend
|
||||
|
||||
if _G.love and _G.love._version_minor > 8 then
|
||||
return require(ROOT .. 'backend.love')
|
||||
else
|
||||
|
||||
@@ -4,16 +4,18 @@ local Hooker = require(ROOT .. 'hooker')
|
||||
|
||||
local ffi = require 'ffi'
|
||||
local sdl = require((...) .. '.sdl')
|
||||
|
||||
local Image = require((...) .. '.image')
|
||||
local Font = require((...) .. '.font')
|
||||
local Keyboard = require((...) .. '.keyboard')
|
||||
local Text = require((...) .. '.text')
|
||||
|
||||
local IntOut = ffi.typeof 'int[1]'
|
||||
|
||||
-- create window and renderer
|
||||
|
||||
local window = sdl.createWindow('', 0, 0, 800, 600,
|
||||
sdl.WINDOW_SHOWN)
|
||||
sdl.WINDOW_SHOWN + sdl.WINDOW_RESIZABLE)
|
||||
|
||||
if window == nil then
|
||||
io.stderr:write(ffi.string(sdl.getError()))
|
||||
@@ -58,13 +60,17 @@ Backend.run = function ()
|
||||
return
|
||||
elseif event.type == sdl.WINDOWEVENT
|
||||
and event.window.event == sdl.WINDOWEVENT_RESIZED then
|
||||
callback.resize(event.window.data1, event.window.data2)
|
||||
local window = event.window
|
||||
callback.resize(window.data1, window.data2)
|
||||
elseif event.type == sdl.MOUSEBUTTONDOWN then
|
||||
callback.mousepressed(event.button.x, event.button.y, event.button.button)
|
||||
local button = event.button
|
||||
callback.mousepressed(button.x, button.y, button.button)
|
||||
elseif event.type == sdl.MOUSEBUTTONUP then
|
||||
callback.mousereleased(event.button.x, event.button.y, event.button.button)
|
||||
local button = event.button
|
||||
callback.mousereleased(button.x, button.y, button.button)
|
||||
elseif event.type == sdl.MOUSEMOTION then
|
||||
callback.mousemoved(event.motion.x, event.motion.y)
|
||||
local motion = event.motion
|
||||
callback.mousemoved(motion.x, motion.y)
|
||||
elseif event.type == sdl.KEYDOWN then
|
||||
local key = Keyboard.stringByKeycode[event.key.keysym.sym]
|
||||
callback.keypressed(key, event.key['repeat'])
|
||||
@@ -94,6 +100,10 @@ Backend.Image = function (path)
|
||||
return Image(renderer, path)
|
||||
end
|
||||
|
||||
Backend.Text = function (...)
|
||||
return Text(renderer, ...)
|
||||
end
|
||||
|
||||
Backend.Quad = function (x, y, w, h)
|
||||
return { x, y, w, h }
|
||||
end
|
||||
@@ -101,7 +111,28 @@ end
|
||||
Backend.SpriteBatch = require((...) .. '.spritebatch')
|
||||
|
||||
Backend.draw = function (drawable, x, y, sx, sy)
|
||||
return drawable:draw(x, y, sx, sy)
|
||||
if drawable.draw then
|
||||
return drawable:draw(x, y, sx, sy)
|
||||
end
|
||||
|
||||
if drawable.sdlTexture == nil
|
||||
or drawable.sdlRenderer == nil
|
||||
or drawable.getWidth == nil
|
||||
or drawable.getHeight == nil
|
||||
then return
|
||||
end
|
||||
|
||||
local w = drawable:getWidth() * (sx or 1)
|
||||
local h = drawable:getHeight() * (sy or 1)
|
||||
|
||||
-- HACK. Somehow drawing something first prevents renderCopy from
|
||||
-- incorrectly scaling up in some cases (after rendering slices).
|
||||
-- For example http://stackoverflow.com/questions/28218906
|
||||
sdl.renderDrawPoint(drawable.sdlRenderer, -1, -1)
|
||||
|
||||
-- Draw the image.
|
||||
sdl.renderCopy(drawable.sdlRenderer, drawable.sdlTexture,
|
||||
nil, sdl.Rect(x, y, w, h))
|
||||
end
|
||||
|
||||
Backend.drawRectangle = function (mode, x, y, w, h)
|
||||
@@ -118,7 +149,7 @@ local currentFont = Font()
|
||||
Backend.print = function (text, x, y)
|
||||
if not text or text == '' then return end
|
||||
local font = currentFont.sdlFont
|
||||
local color = sdl.Color(currentFont.color)
|
||||
local color = sdl.Color(currentFont.color or { 0, 0, 0, 255 })
|
||||
local write = Font.SDL2_ttf.TTF_RenderUTF8_Blended
|
||||
|
||||
local surface = write(font, text, color)
|
||||
@@ -130,7 +161,9 @@ end
|
||||
|
||||
Backend.printf = Backend.print
|
||||
|
||||
Backend.getClipboardText = sdl.getClipboardText
|
||||
Backend.getClipboardText = function ()
|
||||
return ffi.string(sdl.getClipboardText())
|
||||
end
|
||||
|
||||
Backend.setClipboardText = sdl.setClipboardText
|
||||
|
||||
|
||||
@@ -197,13 +197,10 @@ Font.SDL2_ttf = SDL2_ttf
|
||||
|
||||
local fontCache = {}
|
||||
|
||||
function Font:constructor (path, size, color)
|
||||
function Font:constructor (path, size)
|
||||
if not size then
|
||||
size = 12
|
||||
end
|
||||
if not color then
|
||||
color = { 0, 0, 0, 255 }
|
||||
end
|
||||
if not path then
|
||||
path = REL:gsub('%.', '/') .. 'resource/DejaVuSans.ttf'
|
||||
end
|
||||
@@ -222,7 +219,6 @@ function Font:constructor (path, size, color)
|
||||
end
|
||||
|
||||
self.sdlFont = fontCache[key]
|
||||
self.color = color
|
||||
end
|
||||
|
||||
function Font:setAlignment (align)
|
||||
|
||||
@@ -14,10 +14,12 @@ end })
|
||||
|
||||
function Image:constructor (renderer, path)
|
||||
self.sdlRenderer = renderer
|
||||
self.sdlSurface = SDL2_image.IMG_Load(path)
|
||||
ffi.gc(self.sdlSurface, sdl.freeSurface)
|
||||
self.sdlTexture = sdl.createTextureFromSurface(renderer, self.sdlSurface)
|
||||
ffi.gc(self.sdlTexture, sdl.destroyTexture)
|
||||
self.sdlSurface = ffi.gc(
|
||||
SDL2_image.IMG_Load(path),
|
||||
sdl.freeSurface)
|
||||
self.sdlTexture = ffi.gc(
|
||||
sdl.createTextureFromSurface(renderer, self.sdlSurface),
|
||||
sdl.destroyTexture)
|
||||
self.width = self.sdlSurface.w
|
||||
self.height = self.sdlSurface.h
|
||||
end
|
||||
@@ -30,17 +32,4 @@ function Image:getHeight ()
|
||||
return self.height
|
||||
end
|
||||
|
||||
function Image:draw (x, y, sx, sy)
|
||||
local w = self.width * (sx or 1)
|
||||
local h = self.height * (sy or 1)
|
||||
|
||||
-- HACK. Somehow drawing something first prevents renderCopy from
|
||||
-- incorrectly scaling up in some cases (after rendering slices).
|
||||
-- For example http://stackoverflow.com/questions/28218906
|
||||
sdl.renderDrawPoint(self.sdlRenderer, -1, -1)
|
||||
|
||||
-- Draw the image.
|
||||
sdl.renderCopy(self.sdlRenderer, self.sdlTexture, nil, sdl.Rect(x, y, w, h))
|
||||
end
|
||||
|
||||
return Image
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
local ROOT = (...):gsub('[^.]*$', '')
|
||||
local REL = (...):gsub('[^.]*$', '')
|
||||
|
||||
local ffi = require 'ffi'
|
||||
local sdl = require(ROOT .. 'sdl2.init')
|
||||
local sdl = require(REL .. 'sdl2.init')
|
||||
|
||||
sdl.AudioCVT = ffi.typeof 'SDL_AudioCVT'
|
||||
-- sdl.AudioDeviceEvent = ffi.typeof 'SDL_AudioDeviceEvent'
|
||||
|
||||
106
luigi/backend/ffisdl/text.lua
Normal file
106
luigi/backend/ffisdl/text.lua
Normal file
@@ -0,0 +1,106 @@
|
||||
local ROOT = (...):gsub('[^.]*.[^.]*.[^.]*$', '')
|
||||
local REL = (...):gsub('[^.]*$', '')
|
||||
|
||||
local ffi = require 'ffi'
|
||||
local sdl = require(REL .. 'sdl')
|
||||
local Font = require(REL .. 'font')
|
||||
local ttf = Font.SDL2_ttf
|
||||
|
||||
local Multiline = require(ROOT .. 'multiline')
|
||||
|
||||
local Text = setmetatable({}, { __call = function (self, ...)
|
||||
local object = setmetatable({}, { __index = self })
|
||||
return object, self.constructor(object, ...)
|
||||
end })
|
||||
|
||||
local function renderSingle (self, font, text, color)
|
||||
local alphaMod = color and color[4]
|
||||
color = sdl.Color(color or 0)
|
||||
local surface = ffi.gc(
|
||||
ttf.TTF_RenderUTF8_Blended(font.sdlFont, text, color),
|
||||
sdl.freeSurface)
|
||||
self.sdlSurface = surface
|
||||
self.sdlTexture = ffi.gc(
|
||||
sdl.createTextureFromSurface(self.sdlRenderer, surface),
|
||||
sdl.destroyTexture)
|
||||
if alphaMod then
|
||||
sdl.setTextureAlphaMod(self.sdlTexture, alphaMod)
|
||||
end
|
||||
self.width, self.height = surface.w, surface.h
|
||||
end
|
||||
|
||||
local function renderMulti (self, font, text, color, align, limit)
|
||||
local alphaMod = color and color[4]
|
||||
local lines = Multiline.wrap(font, text, limit)
|
||||
local lineHeight = font:getLineHeight()
|
||||
local height = #lines * lineHeight
|
||||
color = sdl.Color(color or 0)
|
||||
|
||||
local r, g, b, a
|
||||
|
||||
if sdl.BYTEORDER == sdl.BIG_ENDIAN then
|
||||
r, g, b, a = 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
|
||||
else
|
||||
r, g, b, a = 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
|
||||
end
|
||||
|
||||
local surface = ffi.gc(
|
||||
sdl.createRGBSurface(0, limit, height, 32, r, g, b, a),
|
||||
sdl.freeSurface)
|
||||
self.sdlSurface = surface
|
||||
|
||||
for index, line in ipairs(lines) do
|
||||
local text = table.concat(line)
|
||||
local lineSurface = ffi.gc(
|
||||
ttf.TTF_RenderUTF8_Blended(font.sdlFont, text, color),
|
||||
sdl.freeSurface)
|
||||
if lineSurface ~= nil then
|
||||
local w, h = lineSurface.w, lineSurface.h
|
||||
local top = (index - 1) * lineHeight
|
||||
|
||||
if align == 'left' then
|
||||
sdl.blitSurface(lineSurface, nil, surface,
|
||||
sdl.Rect(0, top, w, h))
|
||||
elseif align == 'right' then
|
||||
sdl.blitSurface(lineSurface, nil, surface,
|
||||
sdl.Rect(limit - line.width, top, w, h))
|
||||
elseif align == 'center' then
|
||||
sdl.blitSurface(lineSurface, nil, surface,
|
||||
sdl.Rect((limit - line.width) / 2, top, w, h))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.sdlTexture = ffi.gc(
|
||||
sdl.createTextureFromSurface(self.sdlRenderer, surface),
|
||||
sdl.destroyTexture)
|
||||
|
||||
if alphaMod then
|
||||
sdl.setTextureAlphaMod(self.sdlTexture, alphaMod)
|
||||
end
|
||||
|
||||
self.width, self.height = surface.w, surface.h
|
||||
end
|
||||
|
||||
function Text:constructor (renderer, font, text, color, align, limit)
|
||||
self.width, self.height = 0, 0
|
||||
if not text or text == '' then return end
|
||||
|
||||
self.sdlRenderer = renderer
|
||||
|
||||
if limit then
|
||||
renderMulti(self, font, text, color, align, limit)
|
||||
else
|
||||
renderSingle(self, font, text, color)
|
||||
end
|
||||
end
|
||||
|
||||
function Text:getWidth ()
|
||||
return self.width
|
||||
end
|
||||
|
||||
function Text:getHeight ()
|
||||
return self.height
|
||||
end
|
||||
|
||||
return Text
|
||||
@@ -11,13 +11,21 @@ Backend.Cursor = love.mouse.newCursor
|
||||
|
||||
Backend.Font = require(ROOT .. 'backend.love.font')
|
||||
|
||||
Backend.Text = require(ROOT .. 'backend.love.text')
|
||||
|
||||
Backend.Image = love.graphics.newImage
|
||||
|
||||
Backend.Quad = love.graphics.newQuad
|
||||
|
||||
Backend.SpriteBatch = love.graphics.newSpriteBatch
|
||||
|
||||
Backend.draw = love.graphics.draw
|
||||
-- love.graphics.draw( drawable, x, y, r, sx, sy, ox, oy, kx, ky )
|
||||
Backend.draw = function (drawable, ...)
|
||||
if drawable.typeOf and drawable:typeOf 'Drawable' then
|
||||
return love.graphics.draw(drawable, ...)
|
||||
end
|
||||
return drawable:draw(...)
|
||||
end
|
||||
|
||||
Backend.drawRectangle = love.graphics.rectangle
|
||||
|
||||
|
||||
72
luigi/backend/love/text.lua
Normal file
72
luigi/backend/love/text.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
local ROOT = (...):gsub('[^.]*.[^.]*.[^.]*$', '')
|
||||
local REL = (...):gsub('[^.]*$', '')
|
||||
|
||||
local Multiline = require(ROOT .. 'multiline')
|
||||
|
||||
local Text = setmetatable({}, { __call = function (self, ...)
|
||||
local object = setmetatable({}, { __index = self })
|
||||
return object, self.constructor(object, ...)
|
||||
end })
|
||||
|
||||
local function renderSingle (self, x, y, font, text, color)
|
||||
love.graphics.push('all')
|
||||
love.graphics.setColor(color or { 0, 0, 0 })
|
||||
love.graphics.setFont(font.loveFont)
|
||||
love.graphics.print(text, x, y)
|
||||
love.graphics.pop()
|
||||
|
||||
self.height = font:getLineHeight()
|
||||
self.width = font:getAdvance(text)
|
||||
end
|
||||
|
||||
local function renderMulti (self, x, y, font, text, color, align, limit)
|
||||
local lines = Multiline.wrap(font, text, limit)
|
||||
local lineHeight = font:getLineHeight()
|
||||
local height = #lines * lineHeight
|
||||
|
||||
love.graphics.push('all')
|
||||
love.graphics.setColor(color or { 0, 0, 0 })
|
||||
love.graphics.setFont(font.loveFont)
|
||||
|
||||
for index, line in ipairs(lines) do
|
||||
local text = table.concat(line)
|
||||
local top = (index - 1) * lineHeight
|
||||
local w = line.width
|
||||
|
||||
if align == 'left' then
|
||||
love.graphics.print(text, x, top + y)
|
||||
elseif align == 'right' then
|
||||
love.graphics.print(text, limit - w + x, top + y)
|
||||
elseif align == 'center' then
|
||||
love.graphics.print(text, (limit - w) / 2 + x, top + y)
|
||||
end
|
||||
end
|
||||
|
||||
love.graphics.pop()
|
||||
|
||||
self.height = height
|
||||
self.width = limit
|
||||
end
|
||||
|
||||
function Text:constructor (font, text, color, align, limit)
|
||||
if limit then
|
||||
function self:draw (x, y)
|
||||
return renderMulti(self, x, y, font, text, color, align, limit)
|
||||
end
|
||||
else
|
||||
function self:draw (x, y)
|
||||
return renderSingle(self, x, y, font, text, color)
|
||||
end
|
||||
end
|
||||
self:draw(-1000000, -1000000)
|
||||
end
|
||||
|
||||
function Text:getWidth ()
|
||||
return self.width
|
||||
end
|
||||
|
||||
function Text:getHeight ()
|
||||
return self.height
|
||||
end
|
||||
|
||||
return Text
|
||||
@@ -1,5 +0,0 @@
|
||||
local ROOT = (...):gsub('[^.]*$', '')
|
||||
|
||||
local Backend = require(ROOT .. 'backend')
|
||||
|
||||
return Backend.Font
|
||||
@@ -34,8 +34,7 @@ function Input:handleKeyPress (layout, key, x, y)
|
||||
local result = widget:bubbleEvent('KeyPress', {
|
||||
key = key,
|
||||
modifierFlags = self:getModifierFlags(),
|
||||
x = x,
|
||||
y = y
|
||||
x = x, y = y
|
||||
})
|
||||
if result ~= nil then return result end
|
||||
end
|
||||
@@ -45,8 +44,7 @@ function Input:handleKeyRelease (layout, key, x, y)
|
||||
local result = widget:bubbleEvent('KeyRelease', {
|
||||
key = key,
|
||||
modifierFlags = self:getModifierFlags(),
|
||||
x = x,
|
||||
y = y
|
||||
x = x, y = y
|
||||
})
|
||||
if result ~= nil then return result end
|
||||
end
|
||||
@@ -55,7 +53,8 @@ function Input:handleTextInput (layout, text, x, y)
|
||||
local widget = layout.focusedWidget or layout.root
|
||||
local result = widget:bubbleEvent('TextInput', {
|
||||
hit = hit,
|
||||
text = text, x = x, y = y
|
||||
text = text,
|
||||
x = x, y = y
|
||||
})
|
||||
if result ~= nil then return result end
|
||||
end
|
||||
@@ -193,7 +192,8 @@ function Input:handlePressEnd (layout, button, x, y, widget, accelerator)
|
||||
hit = hit,
|
||||
origin = originWidget,
|
||||
accelerator = accelerator,
|
||||
button = button, x = x, y = y
|
||||
button = button,
|
||||
x = x, y = y
|
||||
})
|
||||
if (widget == originWidget) then
|
||||
widget:bubbleEvent('Press', {
|
||||
|
||||
@@ -140,7 +140,7 @@ function Layout:show ()
|
||||
Backend.hide(self)
|
||||
self.isShown = nil
|
||||
end
|
||||
|
||||
|
||||
self.isShown = true
|
||||
|
||||
if not self.input then
|
||||
|
||||
54
luigi/multiline.lua
Normal file
54
luigi/multiline.lua
Normal file
@@ -0,0 +1,54 @@
|
||||
local Multiline = {}
|
||||
|
||||
function Multiline.wrap (font, text, limit)
|
||||
local lines = {{ width = 0 }}
|
||||
local advance = 0
|
||||
|
||||
local function append (word, space)
|
||||
local wordAdvance = font:getAdvance(word)
|
||||
local spaceAdvance = font:getAdvance(space)
|
||||
local words = lines[#lines]
|
||||
if advance + wordAdvance > limit then
|
||||
advance = wordAdvance + spaceAdvance
|
||||
lines[#lines + 1] = { width = advance, word, space }
|
||||
else
|
||||
advance = advance + wordAdvance + spaceAdvance
|
||||
words.width = advance
|
||||
words[#words + 1] = word
|
||||
words[#words + 1] = space
|
||||
end
|
||||
end
|
||||
|
||||
local function appendFrag (frag, isFirst)
|
||||
if isFirst then
|
||||
append(frag, '')
|
||||
else
|
||||
local wordAdvance = font:getAdvance(frag)
|
||||
lines[#lines + 1] = { width = wordAdvance, frag }
|
||||
advance = wordAdvance
|
||||
end
|
||||
end
|
||||
|
||||
local leadSpace = text:match '^ +'
|
||||
|
||||
if leadSpace then
|
||||
append('', leadSpace)
|
||||
end
|
||||
|
||||
for word, space in text:gmatch '([^ ]+)( *)' do
|
||||
if word:match '\n' then
|
||||
local isFirst = true
|
||||
for frag in (word .. '\n'):gmatch '([^\n]*)\n' do
|
||||
appendFrag(frag, isFirst)
|
||||
isFirst = false
|
||||
end
|
||||
append('', space)
|
||||
else
|
||||
append(word, space)
|
||||
end
|
||||
end
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
return Multiline
|
||||
@@ -3,7 +3,8 @@ local ROOT = (...):gsub('[^.]*$', '')
|
||||
local Backend = require(ROOT .. 'backend')
|
||||
local Base = require(ROOT .. 'base')
|
||||
local Event = require(ROOT .. 'event')
|
||||
local Font = require(ROOT .. 'font')
|
||||
local Font = Backend.Font
|
||||
local Text = Backend.Text
|
||||
|
||||
local Renderer = Base:extend()
|
||||
|
||||
@@ -18,6 +19,8 @@ function Renderer:loadImage (path)
|
||||
return imageCache[path]
|
||||
end
|
||||
|
||||
-- TODO: make slices a seperate drawable
|
||||
|
||||
function Renderer:loadSlices (path)
|
||||
local slices = sliceCache[path]
|
||||
|
||||
@@ -141,39 +144,40 @@ end
|
||||
|
||||
-- returns text coordinates
|
||||
function Renderer:positionText (widget, x1, y1, x2, y2)
|
||||
if not widget.text then
|
||||
if not widget.text or x1 >= x2 then
|
||||
return nil, nil, x1, y1, x2, y2
|
||||
end
|
||||
|
||||
if not widget.fontData then
|
||||
widget.fontData = Font(widget.font, widget.fontSize, widget.textColor)
|
||||
widget.fontData = Font(widget.font, widget.fontSize)
|
||||
end
|
||||
|
||||
local font = widget.fontData
|
||||
local align = widget.align or ''
|
||||
local padding = widget.padding or 0
|
||||
|
||||
font:setWidth(x2 - x1)
|
||||
local horizontal = 'left'
|
||||
|
||||
-- horizontal alignment
|
||||
if align:find('right') then
|
||||
font:setAlignment('right')
|
||||
elseif align:find('center') then
|
||||
font:setAlignment('center')
|
||||
elseif align:find('justify') then
|
||||
font:setAlignment('justify')
|
||||
else -- if align:find('left') then
|
||||
font:setAlignment('left')
|
||||
if align:find 'right' then
|
||||
horizontal = 'right'
|
||||
elseif align:find 'center' then
|
||||
horizontal = 'center'
|
||||
elseif align:find 'justify' then
|
||||
horizontal = 'justify'
|
||||
end
|
||||
|
||||
if not widget.textData then
|
||||
local limit = widget.multiline and x2 - x1 or nil
|
||||
widget.textData = Text(
|
||||
font, widget.text, widget.textColor, horizontal, limit)
|
||||
end
|
||||
|
||||
local textHeight = widget.textData:getHeight()
|
||||
local y
|
||||
|
||||
-- vertical alignment
|
||||
if align:find('bottom') then
|
||||
local textHeight = font:getWrappedHeight(widget.text)
|
||||
y = y2 - textHeight
|
||||
elseif align:find('middle') then
|
||||
local textHeight = font:getWrappedHeight(widget.text)
|
||||
y = y2 - (y2 - y1) / 2 - textHeight / 2
|
||||
else -- if align:find('top') then
|
||||
y = y1
|
||||
@@ -210,22 +214,32 @@ function Renderer:renderIconAndText (widget)
|
||||
if icon and text and align:find('center') then
|
||||
local iconHeight = icon:getHeight()
|
||||
|
||||
if align:find('middle') then
|
||||
local textHeight = font:getWrappedHeight(text)
|
||||
if align:find 'middle' then
|
||||
local textHeight = widget.textData:getHeight()
|
||||
local contentHeight = textHeight + padding + iconHeight
|
||||
local offset = ((y2 - y1) - contentHeight) / 2
|
||||
iconY = y1 + offset
|
||||
textY = y1 + offset + padding + iconHeight
|
||||
elseif align:find('top') then
|
||||
elseif align:find 'top' then
|
||||
iconY = y1
|
||||
textY = y1 + padding + iconHeight
|
||||
else -- if align:find('bottom')
|
||||
local textHeight = font:getWrappedHeight(text)
|
||||
else -- if align:find 'bottom'
|
||||
local textHeight = widget.textData:getHeight()
|
||||
textY = y2 - textHeight
|
||||
iconY = textY - padding - iconHeight
|
||||
end
|
||||
end
|
||||
|
||||
-- horizontal alignment for non-multiline
|
||||
-- TODO: handle this in Backend.Text
|
||||
if text and not widget.multiline then
|
||||
if align:find 'right' then
|
||||
textX = textX + ((x2 - x1) - widget.textData:getWidth())
|
||||
elseif align:find 'center' then
|
||||
textX = textX + ((x2 - x1) - widget.textData:getWidth()) / 2
|
||||
end
|
||||
end
|
||||
|
||||
-- draw the icon
|
||||
if icon then
|
||||
iconX, iconY = math.floor(iconX), math.floor(iconY)
|
||||
@@ -238,9 +252,7 @@ function Renderer:renderIconAndText (widget)
|
||||
-- draw the text
|
||||
if text and x2 > x1 then
|
||||
textX, textY = math.floor(textX), math.floor(textY)
|
||||
Backend.setFont(font)
|
||||
Backend.setColor(font.color)
|
||||
Backend.printf(text, textX, textY, x2 - x1, font.align)
|
||||
Backend.draw(widget.textData, textX, textY)
|
||||
end
|
||||
|
||||
Backend.pop()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
-- modified for partial compatibility with Lua 5.3
|
||||
|
||||
--utf8 module (Cosmin Apreutesei, public domain).
|
||||
--byte indices are i's, char (codepoint) indices are ci's.
|
||||
--invalid characters are counted as 1-byte chars so they don't get lost. validate/sanitize beforehand as needed.
|
||||
@@ -56,11 +58,12 @@ function utf8.byte_index(s, target_ci)
|
||||
end
|
||||
end
|
||||
assert(target_ci > ci, 'invalid index')
|
||||
return #s + 1
|
||||
end
|
||||
|
||||
--char index given byte index. nil if the index is outside the string.
|
||||
function utf8.char_index(s, target_i)
|
||||
if target_i < 1 or target_i > #s then return end
|
||||
if target_i < 1 or target_i > #s + 1 then return end
|
||||
local ci = 0
|
||||
for i in utf8.byte_indices(s) do
|
||||
ci = ci + 1
|
||||
@@ -68,7 +71,8 @@ function utf8.char_index(s, target_i)
|
||||
return ci
|
||||
end
|
||||
end
|
||||
error'invalid index'
|
||||
return ci + 1
|
||||
-- error'invalid index'
|
||||
end
|
||||
|
||||
--byte index of the prev. char before the char at byte index i, which defaults to #s + 1.
|
||||
@@ -306,11 +310,28 @@ function utf8.sanitize(s, repl_char)
|
||||
return utf8.replace(s, replace_invalid, repl_char)
|
||||
end
|
||||
|
||||
-- added for partial compatibility with lua 5.3
|
||||
-- Returns the position (in bytes) where the encoding of the n-th character
|
||||
-- of s (counting from position i) starts.
|
||||
function utf8.offset(s, n, i)
|
||||
|
||||
function utf8.offset(s, char_offset, byte_index)
|
||||
local ci = utf8.char_index(s, byte_index)
|
||||
return utf8.byte_index(s, ci + char_offset)
|
||||
-- The default for i is 1 when n is non-negative and #s + 1 otherwise
|
||||
if not i then
|
||||
i = n < 0 and #s + 1 or 1
|
||||
end
|
||||
|
||||
local ci = utf8.char_index(s, i)
|
||||
|
||||
-- As a special case, when n is 0 the function returns the start of
|
||||
-- the encoding of the character that contains the i-th byte of s.
|
||||
if n == 0 then
|
||||
return ci
|
||||
end
|
||||
|
||||
if n > 0 then
|
||||
n = n - 1
|
||||
end
|
||||
|
||||
return utf8.byte_index(s, ci + n)
|
||||
end
|
||||
|
||||
utf8.codes = utf8.byte_indices
|
||||
|
||||
@@ -8,7 +8,7 @@ local ROOT = (...):gsub('[^.]*$', '')
|
||||
|
||||
local Backend = require(ROOT .. 'backend')
|
||||
local Event = require(ROOT .. 'event')
|
||||
local Font = require(ROOT .. 'font')
|
||||
local Font = Backend.Font
|
||||
|
||||
local Widget = {}
|
||||
|
||||
@@ -50,17 +50,25 @@ end
|
||||
|
||||
-- setting shadow properties causes special behavior
|
||||
local function metaNewIndex (self, property, value)
|
||||
if property == 'font'
|
||||
or property == 'fontSize'
|
||||
or property == 'textColor' then
|
||||
if property == 'font' or property == 'fontSize' then
|
||||
self.shadowProperties[property] = value
|
||||
self.fontData = Font(self.font, self.fontSize, self.textColor)
|
||||
self.fontData = nil
|
||||
self.textData = nil
|
||||
end
|
||||
|
||||
if property == 'text' or property == 'textColor'
|
||||
or property == 'align' or property == 'multiline' then
|
||||
self.shadowProperties[property] = value
|
||||
self.textData = nil
|
||||
return
|
||||
end
|
||||
|
||||
if property == 'width' then
|
||||
value = value and math.max(value, self.minwidth or 0)
|
||||
self.shadowProperties[property] = value
|
||||
if self.multiline then
|
||||
self.textData = nil
|
||||
end
|
||||
Widget.reshape(self.parent or self)
|
||||
return
|
||||
end
|
||||
@@ -114,8 +122,13 @@ local function metaNewIndex (self, property, value)
|
||||
end
|
||||
|
||||
local shadowKeys = {
|
||||
'font', 'fontSize', 'textColor', 'width', 'height', 'value', 'key', 'id'
|
||||
'id', 'key', 'value',
|
||||
'width', 'height',
|
||||
'font', 'fontSize',
|
||||
'text', 'textColor',
|
||||
'align', 'multiline',
|
||||
}
|
||||
|
||||
--[[--
|
||||
Widget pseudo-constructor.
|
||||
|
||||
@@ -603,6 +616,7 @@ function Widget:reshape ()
|
||||
if self.isReshaping then return end
|
||||
self.isReshaping = true
|
||||
self.needsReshape = true
|
||||
self.textData = nil
|
||||
Event.Reshape:emit(self, {
|
||||
target = self
|
||||
})
|
||||
|
||||
@@ -125,7 +125,7 @@ local function initialize (self)
|
||||
local textWidth = self.fontData:getAdvance(text) + pad * 2
|
||||
|
||||
if isSubmenu then
|
||||
local tc = self.textColor or { 0, 0, 0 }
|
||||
local tc = self.textColor or { 0, 0, 0, 255 }
|
||||
local keyColor = { tc[1], tc[2], tc[3], 0x90 }
|
||||
local edgeType
|
||||
if #self.items > 0 then
|
||||
|
||||
@@ -230,7 +230,7 @@ return function (self)
|
||||
local x1, y1, x2, y2 = self:getRectangle(true, true)
|
||||
local width, height = endX - startX, y2 - y1
|
||||
local font = self.fontData
|
||||
local textColor = font.color
|
||||
local textColor = self.textColor or { 0, 0, 0, 255 }
|
||||
local textTop = math.floor(y1 + ((y2 - y1) - font:getLineHeight()) / 2)
|
||||
|
||||
Backend.push()
|
||||
|
||||
Reference in New Issue
Block a user