Compare commits

..

14 Commits

Author SHA1 Message Date
Kartik K. Agaram 21bd8281a7 all pending manual tests done! 2022-06-14 22:47:49 -07:00
Kartik K. Agaram b8d7774138 test: undo moving point 2022-06-14 22:43:59 -07:00
Kartik K. Agaram 1aa2590236 test: undo naming a point
Also ensure we autosave.
2022-06-14 22:39:05 -07:00
Kartik K. Agaram ab6eff4f2f test: autosave after name/move/delete of point 2022-06-14 22:17:42 -07:00
Kartik K. Agaram 15acc38da9 test: autosave after any shape 2022-06-14 22:06:08 -07:00
Kartik K. Agaram d077ce7f42 tests: deleting points/shapes 2022-06-14 21:23:39 -07:00
Kartik K. Agaram 93a9dfd364 test: moving a point
I found some code in the process that seems unreachable. Some chance of
a regression here..
2022-06-14 21:08:07 -07:00
Kartik K. Agaram 4f9789db41 test: naming a point 2022-06-14 21:07:04 -07:00
Kartik K. Agaram 0114cd1e78 a little more prose describing manual_tests 2022-06-14 15:14:08 -07:00
Kartik K. Agaram 63269f7af3 one less manual test
Still a few more we can write.
2022-06-14 15:11:00 -07:00
Kartik K. Agaram 0c57f6bbdc drop non-existent feature from comment 2022-06-14 14:59:51 -07:00
Kartik K. Agaram 2b4e14189b tests for drawing polygons 2022-06-14 14:59:09 -07:00
Kartik K. Agaram 6894acc2bb more drawing tests 2022-06-14 11:19:38 -07:00
Kartik K. Agaram dc3b18eb6c start writing some tests for drawings 2022-06-14 10:50:14 -07:00
7 changed files with 731 additions and 44 deletions

18
Manual_tests.md Normal file
View File

@ -0,0 +1,18 @@
I care a lot about being able to automatically check _any_ property about my
program before it ever runs. However, some things don't have tests yet, either
because I don't know how to test them or because I've been lazy. I'll at least
record those here.
### Compromises
Lua is dynamically typed. Tests can't patch over lack of type-checking.
* All strings are UTF-8. Bytes within them are not characters. I try to label
byte offsets as _offset, and character positions as _pos. For example,
string.sub should never use a _pos to substring, only an _offset.
### Todo list
resize:
create a file containing a long line of characters without spaces. try
resizing the window vertically and horizontally, as far as possible.

18
app.lua
View File

@ -276,8 +276,21 @@ end
function App.open_for_writing(filename)
App.filesystem[filename] = ''
return {
write = function(self, s)
App.filesystem[filename] = App.filesystem[filename]..s
write = function(self, ...)
local args = {...}
for i,s in ipairs(args) do
App.filesystem[filename] = App.filesystem[filename]..s
end
end,
close = function(self)
end
}
end
function App.open_for_reading(filename)
return {
lines = function(self)
return App.filesystem[filename]:gmatch('[^\n]+')
end,
close = function(self)
end
@ -331,6 +344,7 @@ function App.disable_tests()
App.newText = love.graphics.newText
App.screen.draw = love.graphics.draw
App.width = function(text) return text:getWidth() end
App.open_for_reading = function(filename) return io.open(filename, 'r') end
App.open_for_writing = function(filename) return io.open(filename, 'w') end
App.getClipboardText = love.system.getClipboardText
App.setClipboardText = love.system.setClipboardText

View File

@ -2,6 +2,8 @@
Drawing = {}
geom = require 'geom'
require 'drawing_tests'
-- All drawings span 100% of some conceptual 'page width' and divide it up
-- into 256 parts.
function Drawing.draw(line)
@ -202,7 +204,7 @@ end
function Drawing.in_drawing(drawing, x,y)
if drawing.y == nil then return false end -- outside current page
return y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= 16 and x < 16+Line_width
return y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= Margin_left and x < Margin_left+Line_width
end
function Drawing.mouse_pressed(drawing, x,y, button)
@ -258,6 +260,10 @@ function Drawing.mouse_released(x,y, button)
if Current_drawing_mode == 'move' then
Current_drawing_mode = Previous_drawing_mode
Previous_drawing_mode = nil
if Lines.current_drawing then
Lines.current_drawing.pending = {}
Lines.current_drawing = nil
end
elseif Lines.current_drawing then
local drawing = Lines.current_drawing
if drawing.pending then
@ -334,8 +340,6 @@ function Drawing.mouse_released(x,y, button)
drawing.pending.end_angle = geom.angle_with_hint(center.x,center.y, mx,my, drawing.pending.end_angle)
table.insert(drawing.shapes, drawing.pending)
end
elseif drawing.pending.mode == 'move' then
-- drop it
elseif drawing.pending.mode == 'name' then
-- drop it
else
@ -406,11 +410,19 @@ function Drawing.keychord_pressed(chord)
end
end
drawing.pending.mode = 'square'
elseif App.mouse_down(1) and chord == 'p' and (Current_drawing_mode == 'polygon' or Current_drawing_mode == 'rectangle' or Current_drawing_mode == 'square') then
elseif App.mouse_down(1) and chord == 'p' and Current_drawing_mode == 'polygon' then
local _,drawing = Drawing.current_drawing()
local mx,my = Drawing.coord(App.mouse_x()-Margin_left), Drawing.coord(App.mouse_y()-drawing.y)
local j = Drawing.insert_point(drawing.points, mx,my)
table.insert(drawing.pending.vertices, j)
elseif App.mouse_down(1) and chord == 'p' and (Current_drawing_mode == 'rectangle' or Current_drawing_mode == 'square') then
local _,drawing = Drawing.current_drawing()
local mx,my = Drawing.coord(App.mouse_x()-Margin_left), Drawing.coord(App.mouse_y()-drawing.y)
local j = Drawing.insert_point(drawing.points, mx,my)
while #drawing.pending.vertices >= 2 do
table.remove(drawing.pending.vertices)
end
table.insert(drawing.pending.vertices, j)
elseif chord == 'C-o' and not App.mouse_down(1) then
Current_drawing_mode = 'circle'
elseif App.mouse_down(1) and chord == 'a' and Current_drawing_mode == 'circle' then
@ -476,17 +488,6 @@ function Drawing.keychord_pressed(chord)
Lines.current_drawing_index = drawing_index
Lines.current_drawing = drawing
end
elseif App.mouse_down(1) and chord == 'v' then
local drawing_index,drawing,_,p = Drawing.select_point_at_mouse()
if drawing then
if Previous_drawing_mode == nil then
Previous_drawing_mode = Current_drawing_mode
end
Current_drawing_mode = 'move'
drawing.pending = {mode=Current_drawing_mode, target_point=p}
Lines.current_drawing_index = drawing_index
Lines.current_drawing = drawing
end
elseif chord == 'C-n' and not App.mouse_down(1) then
local drawing_index,drawing,point_index,p = Drawing.select_point_at_mouse()
if drawing then

674
drawing_tests.lua Normal file
View File

@ -0,0 +1,674 @@
-- major tests for drawings
-- We minimize assumptions about specific pixels, and try to test at the level
-- of specific shapes. In particular, no tests of freehand drawings.
function test_creating_drawing_saves()
io.write('\ntest_creating_drawing_saves')
App.screen.init{width=120, height=60}
Filename = 'foo'
Lines = load_array{}
App.draw()
-- click on button to create drawing
App.run_after_mouse_click(8,Margin_top+8, 1)
-- filesystem contains drawing and an empty line of text
check_eq(App.filesystem['foo'], '```lines\n```\n\n', 'F - test_creating_drawing_saves')
end
function test_draw_line()
io.write('\ntest_draw_line')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
check_eq(#Lines, 2, 'F - test_draw_line/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_line/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_line/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_line/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_line/baseline/#shapes')
-- draw a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_line/#shapes')
check_eq(#drawing.points, 2, 'F - test_draw_line/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/shape:1')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_draw_line/p1:x')
check_eq(p1.y, 6, 'F - test_draw_line/p1:y')
check_eq(p2.x, 35, 'F - test_draw_line/p2:x')
check_eq(p2.y, 36, 'F - test_draw_line/p2:y')
-- The format on disk isn't perfectly stable. Table fields can be reordered.
-- So just reload from disk to verify.
Lines = load_from_disk(Filename)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_line/save/#shapes')
check_eq(#drawing.points, 2, 'F - test_draw_line/save/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/save/shape:1')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_draw_line/save/p1:x')
check_eq(p1.y, 6, 'F - test_draw_line/save/p1:y')
check_eq(p2.x, 35, 'F - test_draw_line/save/p2:x')
check_eq(p2.y, 36, 'F - test_draw_line/save/p2:y')
end
function test_draw_horizontal_line()
io.write('\ntest_draw_horizontal_line')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'manhattan'
App.draw()
check_eq(#Lines, 2, 'F - test_draw_horizontal_line/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_horizontal_line/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_horizontal_line/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_horizontal_line/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_horizontal_line/baseline/#shapes')
-- draw a line that is more horizontal than vertical
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_horizontal_line/#shapes')
check_eq(#drawing.points, 2, 'F - test_draw_horizontal_line/#points')
check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_draw_horizontal_line/shape_mode')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_draw_horizontal_line/p1:x')
check_eq(p1.y, 6, 'F - test_draw_horizontal_line/p1:y')
check_eq(p2.x, 35, 'F - test_draw_horizontal_line/p2:x')
check_eq(p2.y, p1.y, 'F - test_draw_horizontal_line/p2:y')
end
function test_draw_circle()
io.write('\ntest_draw_circle')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
check_eq(#Lines, 2, 'F - test_draw_circle/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_circle/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_circle/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_circle/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_circle/baseline/#shapes')
-- draw a circle
App.mouse_move(Margin_left+4, Margin_top+Drawing_padding_top+4) -- hover on drawing
App.run_after_keychord('C-o')
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+35+30, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_circle/#shapes')
check_eq(#drawing.points, 1, 'F - test_draw_circle/#points')
check_eq(drawing.shapes[1].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
check_eq(drawing.shapes[1].radius, 30, 'F - test_draw_circle/radius')
local center = drawing.points[drawing.shapes[1].center]
check_eq(center.x, 35, 'F - test_draw_circle/center:x')
check_eq(center.y, 36, 'F - test_draw_circle/center:y')
end
function test_keys_do_not_affect_shape_when_mouse_up()
io.write('\ntest_keys_do_not_affect_shape_when_mouse_up')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
-- hover over drawing and press 'o' without holding mouse
App.mouse_move(Margin_left+4, Margin_top+Drawing_padding_top+4) -- hover on drawing
App.run_after_keychord('o')
-- no change to drawing mode
check_eq(Current_drawing_mode, 'line', 'F - test_keys_do_not_affect_shape_when_mouse_up/drawing_mode')
-- no change to text either because we didn't run the textinput event
end
function test_draw_circle_mid_stroke()
io.write('\ntest_draw_circle_mid_stroke')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
check_eq(#Lines, 2, 'F - test_draw_circle_mid_stroke/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_circle_mid_stroke/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_circle_mid_stroke/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_circle_mid_stroke/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_circle_mid_stroke/baseline/#shapes')
-- draw a circle
App.mouse_move(Margin_left+4, Margin_top+Drawing_padding_top+4) -- hover on drawing
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_keychord('o')
App.run_after_mouse_release(Margin_left+35+30, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_circle_mid_stroke/#shapes')
check_eq(#drawing.points, 1, 'F - test_draw_circle_mid_stroke/#points')
check_eq(drawing.shapes[1].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
check_eq(drawing.shapes[1].radius, 30, 'F - test_draw_circle_mid_stroke/radius')
local center = drawing.points[drawing.shapes[1].center]
check_eq(center.x, 35, 'F - test_draw_circle_mid_stroke/center:x')
check_eq(center.y, 36, 'F - test_draw_circle_mid_stroke/center:y')
end
function test_draw_arc()
io.write('\ntest_draw_arc')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'circle'
App.draw()
check_eq(#Lines, 2, 'F - test_draw_arc/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_arc/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_arc/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_arc/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_arc/baseline/#shapes')
-- draw an arc
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.mouse_move(Margin_left+35+30, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('a') -- arc mode
App.run_after_mouse_release(Margin_left+35+50, Margin_top+Drawing_padding_top+36+50, 1) -- 45°
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_arc/#shapes')
check_eq(#drawing.points, 2, 'F - test_draw_arc/#points')
check_eq(drawing.shapes[1].mode, 'arc', 'F - test_draw_horizontal_line/shape_mode')
local arc = drawing.shapes[1]
check_eq(arc.radius, 30, 'F - test_draw_arc/radius')
local center = drawing.points[arc.center]
check_eq(center.x, 35, 'F - test_draw_arc/center:x')
check_eq(center.y, 36, 'F - test_draw_arc/center:y')
check_eq(arc.start_angle, 0, 'F - test_draw_arc/start:angle')
check_eq(arc.end_angle, math.pi/4, 'F - test_draw_arc/end:angle')
end
function test_draw_polygon()
io.write('\ntest_draw_polygon')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
App.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_polygon/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_polygon/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_polygon/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_polygon/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_polygon/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_polygon/baseline/#shapes')
-- first point
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_keychord('g') -- polygon mode
-- second point
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('p') -- add point
-- final point
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_polygon/#shapes')
check_eq(#drawing.points, 3, 'F - test_draw_polygon/vertices')
local shape = drawing.shapes[1]
check_eq(shape.mode, 'polygon', 'F - test_draw_polygon/shape_mode')
check_eq(#shape.vertices, 3, 'F - test_draw_polygon/vertices')
local p = drawing.points[shape.vertices[1]]
check_eq(p.x, 5, 'F - test_draw_polygon/p1:x')
check_eq(p.y, 6, 'F - test_draw_polygon/p1:y')
local p = drawing.points[shape.vertices[2]]
check_eq(p.x, 65, 'F - test_draw_polygon/p2:x')
check_eq(p.y, 36, 'F - test_draw_polygon/p2:y')
local p = drawing.points[shape.vertices[3]]
check_eq(p.x, 35, 'F - test_draw_polygon/p3:x')
check_eq(p.y, 26, 'F - test_draw_polygon/p3:y')
end
function test_draw_rectangle()
io.write('\ntest_draw_rectangle')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
App.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_rectangle/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_rectangle/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_rectangle/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_rectangle/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_rectangle/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_rectangle/baseline/#shapes')
-- first point
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_keychord('r') -- rectangle mode
-- second point/first edge
App.mouse_move(Margin_left+42, Margin_top+Drawing_padding_top+45)
App.run_after_keychord('p')
-- override second point/first edge
App.mouse_move(Margin_left+75, Margin_top+Drawing_padding_top+76)
App.run_after_keychord('p')
-- release (decides 'thickness' of rectangle perpendicular to first edge)
App.run_after_mouse_release(Margin_left+15, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_rectangle/#shapes')
check_eq(#drawing.points, 5, 'F - test_draw_rectangle/#points') -- currently includes every point added
local shape = drawing.shapes[1]
check_eq(shape.mode, 'rectangle', 'F - test_draw_rectangle/shape_mode')
check_eq(#shape.vertices, 4, 'F - test_draw_rectangle/vertices')
local p = drawing.points[shape.vertices[1]]
check_eq(p.x, 35, 'F - test_draw_rectangle/p1:x')
check_eq(p.y, 36, 'F - test_draw_rectangle/p1:y')
local p = drawing.points[shape.vertices[2]]
check_eq(p.x, 75, 'F - test_draw_rectangle/p2:x')
check_eq(p.y, 76, 'F - test_draw_rectangle/p2:y')
local p = drawing.points[shape.vertices[3]]
check_eq(p.x, 70, 'F - test_draw_rectangle/p3:x')
check_eq(p.y, 81, 'F - test_draw_rectangle/p3:y')
local p = drawing.points[shape.vertices[4]]
check_eq(p.x, 30, 'F - test_draw_rectangle/p4:x')
check_eq(p.y, 41, 'F - test_draw_rectangle/p4:y')
end
function test_draw_rectangle_intermediate()
io.write('\ntest_draw_rectangle_intermediate')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
App.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_rectangle_intermediate/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_rectangle_intermediate/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_rectangle_intermediate/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_rectangle_intermediate/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_rectangle_intermediate/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_rectangle_intermediate/baseline/#shapes')
-- first point
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_keychord('r') -- rectangle mode
-- second point/first edge
App.mouse_move(Margin_left+42, Margin_top+Drawing_padding_top+45)
App.run_after_keychord('p')
-- override second point/first edge
App.mouse_move(Margin_left+75, Margin_top+Drawing_padding_top+76)
App.run_after_keychord('p')
local drawing = Lines[1]
check_eq(#drawing.points, 3, 'F - test_draw_rectangle_intermediate/#points') -- currently includes every point added
local pending = drawing.pending
check_eq(pending.mode, 'rectangle', 'F - test_draw_rectangle_intermediate/shape_mode')
check_eq(#pending.vertices, 2, 'F - test_draw_rectangle_intermediate/vertices')
local p = drawing.points[pending.vertices[1]]
check_eq(p.x, 35, 'F - test_draw_rectangle_intermediate/p1:x')
check_eq(p.y, 36, 'F - test_draw_rectangle_intermediate/p1:y')
local p = drawing.points[pending.vertices[2]]
check_eq(p.x, 75, 'F - test_draw_rectangle_intermediate/p2:x')
check_eq(p.y, 76, 'F - test_draw_rectangle_intermediate/p2:y')
-- outline of rectangle is drawn based on where the mouse is, but we can't check that so far
end
function test_draw_square()
io.write('\ntest_draw_square')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
App.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_square/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_square/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_square/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_draw_square/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_square/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_square/baseline/#shapes')
-- first point
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_keychord('s') -- square mode
-- second point/first edge
App.mouse_move(Margin_left+42, Margin_top+Drawing_padding_top+45)
App.run_after_keychord('p')
-- override second point/first edge
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+66)
App.run_after_keychord('p')
-- release (decides which side of first edge to draw square on)
App.run_after_mouse_release(Margin_left+15, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_square/#shapes')
check_eq(#drawing.points, 5, 'F - test_draw_square/#points') -- currently includes every point added
check_eq(drawing.shapes[1].mode, 'square', 'F - test_draw_square/shape_mode')
check_eq(#drawing.shapes[1].vertices, 4, 'F - test_draw_square/vertices')
local p = drawing.points[drawing.shapes[1].vertices[1]]
check_eq(p.x, 35, 'F - test_draw_square/p1:x')
check_eq(p.y, 36, 'F - test_draw_square/p1:y')
local p = drawing.points[drawing.shapes[1].vertices[2]]
check_eq(p.x, 65, 'F - test_draw_square/p2:x')
check_eq(p.y, 66, 'F - test_draw_square/p2:y')
local p = drawing.points[drawing.shapes[1].vertices[3]]
check_eq(p.x, 35, 'F - test_draw_square/p3:x')
check_eq(p.y, 96, 'F - test_draw_square/p3:y')
local p = drawing.points[drawing.shapes[1].vertices[4]]
check_eq(p.x, 5, 'F - test_draw_square/p4:x')
check_eq(p.y, 66, 'F - test_draw_square/p4:y')
end
function test_name_point()
io.write('\ntest_name_point')
-- create a drawing with a line
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
-- draw a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_name_point/baseline/#shapes')
check_eq(#drawing.points, 2, 'F - test_name_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_name_point/baseline/shape:1')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_name_point/baseline/p1:x')
check_eq(p1.y, 6, 'F - test_name_point/baseline/p1:y')
check_eq(p2.x, 35, 'F - test_name_point/baseline/p2:x')
check_eq(p2.y, 36, 'F - test_name_point/baseline/p2:y')
check_nil(p2.name, 'F - test_name_point/baseline/p2:name')
-- enter 'name' mode without moving the mouse
App.run_after_keychord('C-n')
check_eq(Current_drawing_mode, 'name', 'F - test_name_point/mode:1')
App.run_after_textinput('A')
check_eq(p2.name, 'A', 'F - test_name_point')
-- still in 'name' mode
check_eq(Current_drawing_mode, 'name', 'F - test_name_point/mode:2')
-- exit 'name' mode
App.run_after_keychord('return')
check_eq(Current_drawing_mode, 'line', 'F - test_name_point/mode:3')
check_eq(p2.name, 'A', 'F - test_name_point')
-- change is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
check_eq(p2.name, 'A', 'F - test_name_point/save')
end
function test_move_point()
io.write('\ntest_move_point')
-- create a drawing with a line
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_move_point/baseline/#shapes')
check_eq(#drawing.points, 2, 'F - test_move_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point/baseline/shape:1')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_move_point/baseline/p1:x')
check_eq(p1.y, 6, 'F - test_move_point/baseline/p1:y')
check_eq(p2.x, 35, 'F - test_move_point/baseline/p2:x')
check_eq(p2.y, 36, 'F - test_move_point/baseline/p2:y')
check_nil(p2.name, 'F - test_move_point/baseline/p2:name')
-- line is saved to disk
Lines = load_from_disk(Filename)
local drawing = Lines[1]
local p2 = Lines[1].points[drawing.shapes[1].p2]
check_eq(p2.x, 35, 'F - test_move_point/save/x')
check_eq(p2.y, 36, 'F - test_move_point/save/y')
App.draw()
-- enter 'move' mode without moving the mouse
App.run_after_keychord('C-u')
check_eq(Current_drawing_mode, 'move', 'F - test_move_point/mode:1')
-- point is lifted
check_eq(drawing.pending.mode, 'move', 'F - test_move_point/mode:2')
check_eq(drawing.pending.target_point, p2, 'F - test_move_point/target')
-- move point
App.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44)
App.update(0.05)
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p2.x, 26, 'F - test_move_point/x')
check_eq(p2.y, 44, 'F - test_move_point/y')
-- exit 'move' mode
App.run_after_mouse_click(Margin_left+26, Margin_top+Drawing_padding_top+44, 1)
check_eq(Current_drawing_mode, 'line', 'F - test_move_point/mode:3')
check_eq(drawing.pending, {}, 'F - test_move_point/pending')
-- change is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
check_eq(p2.x, 26, 'F - test_move_point/save/x')
check_eq(p2.y, 44, 'F - test_move_point/save/y')
end
function test_delete_lines_at_point()
io.write('\ntest_delete_lines_at_point')
-- create a drawing with two lines connected at a point
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+55, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 2, 'F - test_delete_lines_at_point/baseline/#shapes')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:1')
check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:2')
-- hover on the common point and delete
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('C-d')
check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_lines_at_point/shape:1')
check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_delete_lines_at_point/shape:2')
-- deleted points disappear after file is reloaded
Lines = load_from_disk(Filename)
check_eq(#Lines[1].shapes, 0, 'F - test_delete_lines_at_point/save')
end
function test_delete_line_under_mouse_pointer()
io.write('\ntest_delete_line_under_mouse_pointer')
-- create a drawing with two lines connected at a point
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+55, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 2, 'F - test_delete_line_under_mouse_pointer/baseline/#shapes')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_delete_line_under_mouse_pointer/baseline/shape:1')
check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_line_under_mouse_pointer/baseline/shape:2')
-- hover on one of the lines and delete
App.mouse_move(Margin_left+25, Margin_top+Drawing_padding_top+26)
App.run_after_keychord('C-d')
-- only that line is deleted
check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_line_under_mouse_pointer/shape:1')
check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_line_under_mouse_pointer/shape:2')
end
function test_delete_point_from_polygon()
io.write('\ntest_delete_point_from_polygon')
-- create a drawing with two lines connected at a point
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
-- first point
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_keychord('g') -- polygon mode
-- second point
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('p') -- add point
-- third point
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+26)
App.run_after_keychord('p') -- add point
-- fourth point
App.run_after_mouse_release(Margin_left+14, Margin_top+Drawing_padding_top+16, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes')
check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/baseline/mode')
check_eq(#drawing.shapes[1].vertices, 4, 'F - test_delete_point_from_polygon/baseline/vertices')
-- hover on a point and delete
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+26)
App.run_after_keychord('C-d')
-- just the one point is deleted
check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/shape')
check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/vertices')
end
function test_delete_point_from_polygon()
io.write('\ntest_delete_point_from_polygon')
-- create a drawing with two lines connected at a point
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
-- first point
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_keychord('g') -- polygon mode
-- second point
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('p') -- add point
-- third point
App.run_after_mouse_release(Margin_left+14, Margin_top+Drawing_padding_top+16, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes')
check_eq(drawing.shapes[1].mode, 'polygon', 'F - test_delete_point_from_polygon/baseline/mode')
check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/baseline/vertices')
-- hover on a point and delete
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('C-d')
-- there's < 3 points left, so the whole polygon is deleted
check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_point_from_polygon')
end
function test_undo_name_point()
io.write('\ntest_undo_name_point')
-- create a drawing with a line
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
-- draw a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_undo_name_point/baseline/#shapes')
check_eq(#drawing.points, 2, 'F - test_undo_name_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_name_point/baseline/shape:1')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_undo_name_point/baseline/p1:x')
check_eq(p1.y, 6, 'F - test_undo_name_point/baseline/p1:y')
check_eq(p2.x, 35, 'F - test_undo_name_point/baseline/p2:x')
check_eq(p2.y, 36, 'F - test_undo_name_point/baseline/p2:y')
check_nil(p2.name, 'F - test_undo_name_point/baseline/p2:name')
check_eq(#History, 1, 'F - test_undo_name_point/baseline/history:1')
-- enter 'name' mode without moving the mouse
App.run_after_keychord('C-n')
App.run_after_textinput('A')
App.run_after_keychord('return')
check_eq(p2.name, 'A', 'F - test_undo_name_point/baseline')
check_eq(#History, 3, 'F - test_undo_name_point/baseline/history:2')
check_eq(Next_history, 4, 'F - test_undo_name_point/baseline/next_history')
-- undo
App.run_after_keychord('C-z')
local drawing = Lines[1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(Next_history, 3, 'F - test_undo_name_point/next_history')
check_eq(p2.name, '', 'F - test_undo_name_point') -- not quite what it was before, but close enough
-- undo is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
check_eq(p2.name, '', 'F - test_undo_name_point/save')
end
function test_undo_move_point()
io.write('\ntest_undo_move_point')
-- create a drawing with a line
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 1, 'F - test_undo_move_point/baseline/#shapes')
check_eq(#drawing.points, 2, 'F - test_undo_move_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_move_point/baseline/shape:1')
local p1 = drawing.points[drawing.shapes[1].p1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p1.x, 5, 'F - test_undo_move_point/baseline/p1:x')
check_eq(p1.y, 6, 'F - test_undo_move_point/baseline/p1:y')
check_eq(p2.x, 35, 'F - test_undo_move_point/baseline/p2:x')
check_eq(p2.y, 36, 'F - test_undo_move_point/baseline/p2:y')
check_nil(p2.name, 'F - test_undo_move_point/baseline/p2:name')
-- move p2
App.run_after_keychord('C-u')
App.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44)
App.update(0.05)
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p2.x, 26, 'F - test_undo_move_point/x')
check_eq(p2.y, 44, 'F - test_undo_move_point/y')
-- exit 'move' mode
App.run_after_mouse_click(Margin_left+26, Margin_top+Drawing_padding_top+44, 1)
check_eq(Next_history, 4, 'F - test_undo_move_point/next_history')
-- undo
App.run_after_keychord('C-z')
App.run_after_keychord('C-z') -- bug: need to undo twice
local drawing = Lines[1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(Next_history, 2, 'F - test_undo_move_point/next_history')
check_eq(p2.x, 35, 'F - test_undo_move_point/x')
check_eq(p2.y, 36, 'F - test_undo_move_point/y')
-- undo is saved
Lines = load_from_disk(Filename)
local p2 = Lines[1].points[drawing.shapes[1].p2]
check_eq(p2.x, 35, 'F - test_undo_move_point/save/x')
check_eq(p2.y, 36, 'F - test_undo_move_point/save/y')
end
function test_undo_delete_point()
io.write('\ntest_undo_delete_point')
-- create a drawing with two lines connected at a point
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_drawing_mode = 'line'
App.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+55, Margin_top+Drawing_padding_top+26, 1)
local drawing = Lines[1]
check_eq(#drawing.shapes, 2, 'F - test_undo_delete_point/baseline/#shapes')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_delete_point/baseline/shape:1')
check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/baseline/shape:2')
-- hover on the common point and delete
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+36)
App.run_after_keychord('C-d')
check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_undo_delete_point/shape:1')
check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_undo_delete_point/shape:2')
-- undo
App.run_after_keychord('C-z')
local drawing = Lines[1]
local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(Next_history, 3, 'F - test_undo_move_point/next_history')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_delete_point/shape:1')
check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/shape:2')
-- undo is saved
Lines = load_from_disk(Filename)
check_eq(#Lines[1].shapes, 2, 'F - test_undo_delete_point/save')
end

View File

@ -2,7 +2,7 @@
Drawing = require 'drawing'
function load_from_disk(filename)
local infile = io.open(filename)
local infile = App.open_for_reading(filename)
local result = load_from_file(infile)
if infile then infile:close() end
return result

View File

@ -33,7 +33,6 @@ function App.initialize_globals()
-- an array points for mode 'freehand' (raw x,y coords; freehand drawings don't pollute the points array of a drawing)
-- an array vertices for mode 'polygon', 'rectangle', 'square'
-- p1, p2 for mode 'line'
-- p1, p2, arrow-mode for mode 'arrow-line'
-- center, radius for mode 'circle'
-- center, radius, start_angle, end_angle for mode 'arc'
-- Unless otherwise specified, coord fields are normalized; a drawing is always 256 units wide
@ -66,6 +65,8 @@ Previous_drawing_mode = nil
-- values for tests
Font_height = 14
Line_height = 15
-- widest possible character width
Em = App.newText(love.graphics.getFont(), 'm')
Margin_top = 15
Margin_left = 25
@ -175,8 +176,9 @@ function initialize_font_settings(font_height)
love.graphics.setFont(love.graphics.newFont(Font_height))
Line_height = math.floor(font_height*1.3)
-- maximum width available to either text or drawings, in pixels
Em = App.newText(love.graphics.getFont(), 'm')
-- maximum width available to either text or drawings, in pixels
-- readable text width is 50-75 chars
Line_width = math.min(40*App.width(Em), App.screen.width-50)
end
@ -407,6 +409,7 @@ function App.keychord_pressed(chord)
Selection1 = deepcopy(src.selection)
patch(Lines, event.after, event.before)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
save_to_disk(Lines, Filename)
end
elseif chord == 'C-y' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll
@ -418,6 +421,7 @@ function App.keychord_pressed(chord)
Selection1 = deepcopy(src.selection)
patch(Lines, event.before, event.after)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
save_to_disk(Lines, Filename)
end
-- clipboard
elseif chord == 'C-c' then

View File

@ -1,24 +0,0 @@
-- static properties of the code
All strings are UTF-8. Bytes within them are not characters.
I try to label byte offsets as _offset, and character positions as _pos.
For example, string.sub should never use a _pos to substring, only an _offset.
Wish I had some static typing here. We're not going to try to write tests to catch issues like this.
-- manual tests
drawing
draw a line, circle, rectangle, square, polygon
select a point and move it
select a point and name it
persistence:
draw a line, circle, rectangle, square, polygon, quit, restart. All the shapes you drew should still be visible.
select a point and name it, quit, restart. Name is still visible.
undo:
naming points
deleting points
moving points
resize:
create a file containing a long line of characters without spaces. try
resizing the window vertically and horizontally, as far as possible.