change data model; text can now have metadata
This commit is contained in:
parent
9a54403aa3
commit
3af32571a5
114
main.lua
114
main.lua
|
@ -2,12 +2,13 @@ require 'keychord'
|
||||||
require 'button'
|
require 'button'
|
||||||
local utf8 = require 'utf8'
|
local utf8 = require 'utf8'
|
||||||
|
|
||||||
-- lines is an array of lines
|
-- a line is either text or a drawing
|
||||||
-- a line is either:
|
-- a text is a table with:
|
||||||
-- a string containing text
|
-- mode = 'text'
|
||||||
-- or a drawing
|
-- string data
|
||||||
-- a drawing is a table with:
|
-- a drawing is a table with:
|
||||||
-- a (y) coord in pixels,
|
-- mode = 'drawing'
|
||||||
|
-- a (y) coord in pixels (updated while painting screen),
|
||||||
-- a (h)eight,
|
-- a (h)eight,
|
||||||
-- an array of points, and
|
-- an array of points, and
|
||||||
-- an array of shapes
|
-- an array of shapes
|
||||||
|
@ -28,14 +29,14 @@ local utf8 = require 'utf8'
|
||||||
-- We'll continue to persist them just to keep the option open to continue
|
-- We'll continue to persist them just to keep the option open to continue
|
||||||
-- solving for them. But for now, this is a program to create static drawings
|
-- solving for them. But for now, this is a program to create static drawings
|
||||||
-- once, and read them passively thereafter.
|
-- once, and read them passively thereafter.
|
||||||
lines = {''}
|
lines = {{mode='text', data=''}}
|
||||||
cursor_line = 1
|
cursor_line = 1
|
||||||
-- this is a line
|
-- this is a line
|
||||||
-- ^cursor_pos = 1
|
-- ^cursor_pos = 1
|
||||||
-- ^cursor_pos = 2
|
-- ^cursor_pos = 2
|
||||||
-- ...
|
-- ...
|
||||||
-- ^cursor_pos past end of line is 15
|
-- ^cursor_pos past end of line is 15
|
||||||
cursor_pos = #lines[cursor_line]+1
|
cursor_pos = #lines[cursor_line].data+1
|
||||||
|
|
||||||
screenw, screenh, screenflags = 0, 0, nil
|
screenw, screenh, screenflags = 0, 0, nil
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ function love.draw()
|
||||||
local y = 0
|
local y = 0
|
||||||
for i,line in ipairs(lines) do
|
for i,line in ipairs(lines) do
|
||||||
y = y+25
|
y = y+25
|
||||||
if line == '' then
|
if line.mode == 'text' and line.data == '' then
|
||||||
button('draw', {x=4,y=y+4, w=12,h=12, color={1,1,0},
|
button('draw', {x=4,y=y+4, w=12,h=12, color={1,1,0},
|
||||||
icon = function(x,y)
|
icon = function(x,y)
|
||||||
love.graphics.setColor(0.7,0.7,0.7)
|
love.graphics.setColor(0.7,0.7,0.7)
|
||||||
|
@ -98,13 +99,13 @@ function love.draw()
|
||||||
love.graphics.setColor(0, 0, 0)
|
love.graphics.setColor(0, 0, 0)
|
||||||
end,
|
end,
|
||||||
onpress1 = function()
|
onpress1 = function()
|
||||||
table.insert(lines, i, {y=y, h=256/2, points={}, shapes={}, pending={}})
|
table.insert(lines, i, {mode='drawing', y=y, h=256/2, points={}, shapes={}, pending={}})
|
||||||
end})
|
end})
|
||||||
if i == cursor_line then
|
if i == cursor_line then
|
||||||
love.graphics.setColor(0,0,0)
|
love.graphics.setColor(0,0,0)
|
||||||
love.graphics.print('_', 25, y+6) -- drop the cursor down a bit to account for the increased font size
|
love.graphics.print('_', 25, y+6) -- drop the cursor down a bit to account for the increased font size
|
||||||
end
|
end
|
||||||
elseif type(line) == 'table' then
|
elseif line.mode == 'drawing' then
|
||||||
-- line drawing
|
-- line drawing
|
||||||
line.y = y
|
line.y = y
|
||||||
y = y+pixels(line.h)
|
y = y+pixels(line.h)
|
||||||
|
@ -155,11 +156,11 @@ function love.draw()
|
||||||
draw_pending_shape(16,line.y, line)
|
draw_pending_shape(16,line.y, line)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(0,0,0)
|
love.graphics.setColor(0,0,0)
|
||||||
local text = love.graphics.newText(love.graphics.getFont(), line)
|
local text = love.graphics.newText(love.graphics.getFont(), line.data)
|
||||||
love.graphics.draw(text, 25,y, 0, 1.5)
|
love.graphics.draw(text, 25,y, 0, 1.5)
|
||||||
if i == cursor_line then
|
if i == cursor_line then
|
||||||
-- cursor
|
-- cursor
|
||||||
love.graphics.print('_', 25+cursor_x(lines[cursor_line], cursor_pos)*1.5, y+6) -- drop the cursor down a bit to account for the increased font size
|
love.graphics.print('_', 25+cursor_x(line.data, cursor_pos)*1.5, y+6) -- drop the cursor down a bit to account for the increased font size
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -168,8 +169,8 @@ end
|
||||||
function love.update(dt)
|
function love.update(dt)
|
||||||
if love.mouse.isDown('1') then
|
if love.mouse.isDown('1') then
|
||||||
if lines.current then
|
if lines.current then
|
||||||
local drawing = lines.current
|
if lines.current.mode == 'drawing' then
|
||||||
if type(drawing) == 'table' then
|
local drawing = lines.current
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
if drawing.pending.mode == 'freehand' then
|
if drawing.pending.mode == 'freehand' then
|
||||||
|
@ -262,7 +263,7 @@ end
|
||||||
|
|
||||||
function propagate_to_drawings(x,y, button)
|
function propagate_to_drawings(x,y, button)
|
||||||
for i,drawing in ipairs(lines) do
|
for i,drawing in ipairs(lines) do
|
||||||
if type(drawing) == 'table' then
|
if drawing.mode == 'drawing' then
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
if current_mode == 'freehand' then
|
if current_mode == 'freehand' then
|
||||||
|
@ -474,7 +475,6 @@ end
|
||||||
|
|
||||||
function angle_between(x1,y1, x2,y2, s,e)
|
function angle_between(x1,y1, x2,y2, s,e)
|
||||||
local angle = math.angle(x1,y1, x2,y2)
|
local angle = math.angle(x1,y1, x2,y2)
|
||||||
--? print(s,e, angle-math.pi*2, angle, angle+math.pi*2)
|
|
||||||
if s > e then
|
if s > e then
|
||||||
s,e = e,s
|
s,e = e,s
|
||||||
end
|
end
|
||||||
|
@ -494,14 +494,14 @@ end
|
||||||
function love.textinput(t)
|
function love.textinput(t)
|
||||||
if love.mouse.isDown('1') then return end
|
if love.mouse.isDown('1') then return end
|
||||||
if mouse_in_drawing() then return end
|
if mouse_in_drawing() then return end
|
||||||
if type(lines[cursor_line]) == 'table' then return end
|
if lines[cursor_line].mode == 'drawing' then return end
|
||||||
local byteoffset
|
local byteoffset
|
||||||
if cursor_pos > 1 then
|
if cursor_pos > 1 then
|
||||||
byteoffset = utf8.offset(lines[cursor_line], cursor_pos-1)
|
byteoffset = utf8.offset(lines[cursor_line].data, cursor_pos-1)
|
||||||
else
|
else
|
||||||
byteoffset = 0
|
byteoffset = 0
|
||||||
end
|
end
|
||||||
lines[cursor_line] = string.sub(lines[cursor_line], 1, byteoffset)..t..string.sub(lines[cursor_line], byteoffset+1)
|
lines[cursor_line].data = string.sub(lines[cursor_line].data, 1, byteoffset)..t..string.sub(lines[cursor_line].data, byteoffset+1)
|
||||||
cursor_pos = cursor_pos+1
|
cursor_pos = cursor_pos+1
|
||||||
if filename then
|
if filename then
|
||||||
save_to_disk(lines, filename)
|
save_to_disk(lines, filename)
|
||||||
|
@ -511,23 +511,35 @@ end
|
||||||
function keychord_pressed(chord)
|
function keychord_pressed(chord)
|
||||||
-- Don't handle any keys here that would trigger love.textinput above.
|
-- Don't handle any keys here that would trigger love.textinput above.
|
||||||
if chord == 'return' then
|
if chord == 'return' then
|
||||||
table.insert(lines, cursor_line+1, '')
|
table.insert(lines, cursor_line+1, {mode='text', data=''})
|
||||||
cursor_line = cursor_line+1
|
cursor_line = cursor_line+1
|
||||||
cursor_pos = 1
|
cursor_pos = 1
|
||||||
elseif chord == 'backspace' then
|
elseif chord == 'backspace' then
|
||||||
if #lines > 1 and lines[#lines] == '' then
|
if cursor_line > 1 and lines[cursor_line].data == '' then
|
||||||
table.remove(lines)
|
table.remove(lines, cursor_line)
|
||||||
elseif type(lines[#lines]) == 'table' then
|
cursor_line = cursor_line-1
|
||||||
table.remove(lines) -- we'll add undo soon
|
if lines[cursor_line].mode == 'text' then
|
||||||
|
cursor_pos = #lines[cursor_line].data+1
|
||||||
|
else
|
||||||
|
cursor_pos = 1
|
||||||
|
end
|
||||||
|
elseif lines[cursor_line].mode == 'drawing' then
|
||||||
|
table.remove(lines, cursor_line) -- we'll add undo soon
|
||||||
|
cursor_line = cursor_line-1
|
||||||
|
if lines[cursor_line].mode == 'text' then
|
||||||
|
cursor_pos = #lines[cursor_line].data+1
|
||||||
|
else
|
||||||
|
cursor_pos = 1
|
||||||
|
end
|
||||||
else
|
else
|
||||||
if cursor_pos > 1 then
|
if cursor_pos > 1 then
|
||||||
local byte_start = utf8.offset(lines[cursor_line], cursor_pos-1)
|
local byte_start = utf8.offset(lines[cursor_line].data, cursor_pos-1)
|
||||||
local byte_end = utf8.offset(lines[cursor_line], cursor_pos)
|
local byte_end = utf8.offset(lines[cursor_line].data, cursor_pos)
|
||||||
if byte_start then
|
if byte_start then
|
||||||
if byte_end then
|
if byte_end then
|
||||||
lines[cursor_line] = string.sub(lines[cursor_line], 1, byte_start-1)..string.sub(lines[cursor_line], byte_end)
|
lines[cursor_line].data = string.sub(lines[cursor_line].data, 1, byte_start-1)..string.sub(lines[cursor_line].data, byte_end)
|
||||||
else
|
else
|
||||||
lines[cursor_line] = string.sub(lines[cursor_line], 1, byte_start-1)
|
lines[cursor_line].data = string.sub(lines[cursor_line].data, 1, byte_start-1)
|
||||||
end
|
end
|
||||||
cursor_pos = cursor_pos-1
|
cursor_pos = cursor_pos-1
|
||||||
end
|
end
|
||||||
|
@ -538,34 +550,34 @@ function keychord_pressed(chord)
|
||||||
cursor_pos = cursor_pos - 1
|
cursor_pos = cursor_pos - 1
|
||||||
end
|
end
|
||||||
elseif chord == 'right' then
|
elseif chord == 'right' then
|
||||||
if cursor_pos <= #lines[cursor_line] then
|
if cursor_pos <= #lines[cursor_line].data then
|
||||||
cursor_pos = cursor_pos + 1
|
cursor_pos = cursor_pos + 1
|
||||||
end
|
end
|
||||||
elseif chord == 'home' then
|
elseif chord == 'home' then
|
||||||
cursor_pos = 1
|
cursor_pos = 1
|
||||||
elseif chord == 'end' then
|
elseif chord == 'end' then
|
||||||
cursor_pos = #lines[cursor_line]+1
|
cursor_pos = #lines[cursor_line].data+1
|
||||||
elseif chord == 'up' then
|
elseif chord == 'up' then
|
||||||
if cursor_line > 1 then
|
if cursor_line > 1 then
|
||||||
local old_x = cursor_x(lines[cursor_line], cursor_pos)
|
local old_x = cursor_x(lines[cursor_line].data, cursor_pos)
|
||||||
cursor_line = cursor_line-1
|
cursor_line = cursor_line-1
|
||||||
cursor_pos = nearest_cursor_pos(lines[cursor_line], old_x, cursor_pos)
|
cursor_pos = nearest_cursor_pos(lines[cursor_line].data, old_x, cursor_pos)
|
||||||
end
|
end
|
||||||
elseif chord == 'down' then
|
elseif chord == 'down' then
|
||||||
if cursor_line < #lines then
|
if cursor_line < #lines then
|
||||||
local old_x = cursor_x(lines[cursor_line], cursor_pos)
|
local old_x = cursor_x(lines[cursor_line].data, cursor_pos)
|
||||||
cursor_line = cursor_line+1
|
cursor_line = cursor_line+1
|
||||||
cursor_pos = nearest_cursor_pos(lines[cursor_line], old_x, cursor_pos)
|
cursor_pos = nearest_cursor_pos(lines[cursor_line].data, old_x, cursor_pos)
|
||||||
end
|
end
|
||||||
elseif chord == 'delete' then
|
elseif chord == 'delete' then
|
||||||
if cursor_pos <= #lines[cursor_line] then
|
if cursor_pos <= #lines[cursor_line].data then
|
||||||
local byte_start = utf8.offset(lines[cursor_line], cursor_pos)
|
local byte_start = utf8.offset(lines[cursor_line].data, cursor_pos)
|
||||||
local byte_end = utf8.offset(lines[cursor_line], cursor_pos+1)
|
local byte_end = utf8.offset(lines[cursor_line].data, cursor_pos+1)
|
||||||
if byte_start then
|
if byte_start then
|
||||||
if byte_end then
|
if byte_end then
|
||||||
lines[cursor_line] = string.sub(lines[cursor_line], 1, byte_start-1)..string.sub(lines[cursor_line], byte_end)
|
lines[cursor_line].data = string.sub(lines[cursor_line].data, 1, byte_start-1)..string.sub(lines[cursor_line].data, byte_end)
|
||||||
else
|
else
|
||||||
lines[cursor_line] = string.sub(lines[cursor_line], 1, byte_start-1)
|
lines[cursor_line].data = string.sub(lines[cursor_line].data, 1, byte_start-1)
|
||||||
end
|
end
|
||||||
-- no change to cursor_pos
|
-- no change to cursor_pos
|
||||||
end
|
end
|
||||||
|
@ -710,14 +722,14 @@ function keychord_pressed(chord)
|
||||||
end
|
end
|
||||||
|
|
||||||
function cursor_x(line, cursor_pos)
|
function cursor_x(line, cursor_pos)
|
||||||
if type(line) == 'table' then return 0 end
|
if line.mode == 'drawing' then return 0 end
|
||||||
local line_before_cursor = line:sub(1, cursor_pos-1)
|
local line_before_cursor = line:sub(1, cursor_pos-1)
|
||||||
local text_before_cursor = love.graphics.newText(love.graphics.getFont(), line_before_cursor)
|
local text_before_cursor = love.graphics.newText(love.graphics.getFont(), line_before_cursor)
|
||||||
return text_before_cursor:getWidth()
|
return text_before_cursor:getWidth()
|
||||||
end
|
end
|
||||||
|
|
||||||
function nearest_cursor_pos(line, x, hint)
|
function nearest_cursor_pos(line, x, hint)
|
||||||
if type(line) == 'table' then return hint end
|
if line.mode == 'drawing' then return hint end
|
||||||
if x == 0 then
|
if x == 0 then
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
@ -753,7 +765,7 @@ end
|
||||||
function mouse_in_drawing()
|
function mouse_in_drawing()
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
for _,drawing in ipairs(lines) do
|
for _,drawing in ipairs(lines) do
|
||||||
if type(drawing) == 'table' then
|
if drawing.mode == 'drawing' then
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -765,7 +777,7 @@ end
|
||||||
function current_drawing()
|
function current_drawing()
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
for _,drawing in ipairs(lines) do
|
for _,drawing in ipairs(lines) do
|
||||||
if type(drawing) == 'table' then
|
if drawing.mode == 'drawing' then
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
return drawing
|
return drawing
|
||||||
end
|
end
|
||||||
|
@ -776,7 +788,7 @@ end
|
||||||
|
|
||||||
function select_shape_at_mouse()
|
function select_shape_at_mouse()
|
||||||
for _,drawing in ipairs(lines) do
|
for _,drawing in ipairs(lines) do
|
||||||
if type(drawing) == 'table' then
|
if drawing.mode == 'drawing' then
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
|
local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
|
||||||
|
@ -793,7 +805,7 @@ end
|
||||||
|
|
||||||
function select_point_at_mouse()
|
function select_point_at_mouse()
|
||||||
for _,drawing in ipairs(lines) do
|
for _,drawing in ipairs(lines) do
|
||||||
if type(drawing) == 'table' then
|
if drawing.mode == 'drawing' then
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
|
local mx,my = coord(love.mouse.getX()-16), coord(love.mouse.getY()-drawing.y)
|
||||||
|
@ -810,7 +822,7 @@ end
|
||||||
|
|
||||||
function select_drawing_at_mouse()
|
function select_drawing_at_mouse()
|
||||||
for _,drawing in ipairs(lines) do
|
for _,drawing in ipairs(lines) do
|
||||||
if type(drawing) == 'table' then
|
if drawing.mode == 'drawing' then
|
||||||
local x, y = love.mouse.getX(), love.mouse.getY()
|
local x, y = love.mouse.getX(), love.mouse.getY()
|
||||||
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
if y >= drawing.y and y < drawing.y + pixels(drawing.h) and x >= 16 and x < 16+drawingw then
|
||||||
return drawing
|
return drawing
|
||||||
|
@ -934,12 +946,12 @@ function load_from_file(infile)
|
||||||
if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
|
if line == '```lines' then -- inflexible with whitespace since these files are always autogenerated
|
||||||
table.insert(result, load_drawing(infile_next_line))
|
table.insert(result, load_drawing(infile_next_line))
|
||||||
else
|
else
|
||||||
table.insert(result, line)
|
table.insert(result, {mode='text', data=line})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if #result == 0 then
|
if #result == 0 then
|
||||||
table.insert(result, '')
|
table.insert(result, {mode='text', data=''})
|
||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
@ -947,10 +959,10 @@ end
|
||||||
function save_to_disk(lines, filename)
|
function save_to_disk(lines, filename)
|
||||||
local outfile = io.open(filename, 'w')
|
local outfile = io.open(filename, 'w')
|
||||||
for _,line in ipairs(lines) do
|
for _,line in ipairs(lines) do
|
||||||
if type(line) == 'table' then
|
if line.mode == 'drawing' then
|
||||||
store_drawing(outfile, line)
|
store_drawing(outfile, line)
|
||||||
else
|
else
|
||||||
outfile:write(line..'\n')
|
outfile:write(line.data..'\n')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
outfile:close()
|
outfile:close()
|
||||||
|
@ -958,7 +970,7 @@ end
|
||||||
|
|
||||||
json = require 'json'
|
json = require 'json'
|
||||||
function load_drawing(infile_next_line)
|
function load_drawing(infile_next_line)
|
||||||
local drawing = {h=256/2, points={}, shapes={}, pending={}}
|
local drawing = {mode='drawing', h=256/2, points={}, shapes={}, pending={}}
|
||||||
while true do
|
while true do
|
||||||
local line = infile_next_line()
|
local line = infile_next_line()
|
||||||
assert(line)
|
assert(line)
|
||||||
|
|
Loading…
Reference in New Issue