group all editor globals

We're still accessing them through a global. But we'll change that next.
This commit is contained in:
Kartik K. Agaram 2022-07-12 14:18:50 -07:00
parent a5f725ab3b
commit 8bbc1ffe34
11 changed files with 1952 additions and 1942 deletions

View File

@ -6,13 +6,13 @@ require 'drawing_tests'
-- into 256 parts. -- into 256 parts.
function Drawing.draw(line) function Drawing.draw(line)
local pmx,pmy = App.mouse_x(), App.mouse_y() local pmx,pmy = App.mouse_x(), App.mouse_y()
if pmx < App.screen.width-Margin_right and pmy > line.y and pmy < line.y+Drawing.pixels(line.h) then if pmx < App.screen.width-Editor_state.margin_right and pmy > line.y and pmy < line.y+Drawing.pixels(line.h) then
App.color(Icon_color) App.color(Icon_color)
love.graphics.rectangle('line', Margin_left,line.y, App.screen.width-Margin_width,Drawing.pixels(line.h)) love.graphics.rectangle('line', Editor_state.margin_left,line.y, App.screen.width-Editor_state.margin_width,Drawing.pixels(line.h))
if icon[Current_drawing_mode] then if icon[Editor_state.current_drawing_mode] then
icon[Current_drawing_mode](App.screen.width-Margin_right-22, line.y+4) icon[Editor_state.current_drawing_mode](App.screen.width-Editor_state.margin_right-22, line.y+4)
else else
icon[Previous_drawing_mode](App.screen.width-Margin_right-22, line.y+4) icon[Editor_state.previous_drawing_mode](App.screen.width-Editor_state.margin_right-22, line.y+4)
end end
if App.mouse_down(1) and love.keyboard.isDown('h') then if App.mouse_down(1) and love.keyboard.isDown('h') then
@ -26,7 +26,7 @@ function Drawing.draw(line)
return return
end end
local mx,my = Drawing.coord(pmx-Margin_left), Drawing.coord(pmy-line.y) local mx,my = Drawing.coord(pmx-Editor_state.margin_left), Drawing.coord(pmy-line.y)
for _,shape in ipairs(line.shapes) do for _,shape in ipairs(line.shapes) do
assert(shape) assert(shape)
@ -35,38 +35,38 @@ function Drawing.draw(line)
else else
App.color(Stroke_color) App.color(Stroke_color)
end end
Drawing.draw_shape(Margin_left,line.y, line, shape) Drawing.draw_shape(Editor_state.margin_left,line.y, line, shape)
end end
for i,p in ipairs(line.points) do for i,p in ipairs(line.points) do
if p.deleted == nil then if p.deleted == nil then
if Drawing.near(p, mx,my) then if Drawing.near(p, mx,my) then
App.color(Focus_stroke_color) App.color(Focus_stroke_color)
love.graphics.circle('line', Drawing.pixels(p.x)+Margin_left,Drawing.pixels(p.y)+line.y, 4) love.graphics.circle('line', Drawing.pixels(p.x)+Editor_state.margin_left,Drawing.pixels(p.y)+line.y, 4)
else else
App.color(Stroke_color) App.color(Stroke_color)
love.graphics.circle('fill', Drawing.pixels(p.x)+Margin_left,Drawing.pixels(p.y)+line.y, 2) love.graphics.circle('fill', Drawing.pixels(p.x)+Editor_state.margin_left,Drawing.pixels(p.y)+line.y, 2)
end end
if p.name then if p.name then
-- TODO: clip -- TODO: clip
local x,y = Drawing.pixels(p.x)+Margin_left+5, Drawing.pixels(p.y)+line.y+5 local x,y = Drawing.pixels(p.x)+Editor_state.margin_left+5, Drawing.pixels(p.y)+line.y+5
love.graphics.print(p.name, x,y) love.graphics.print(p.name, x,y)
if Current_drawing_mode == 'name' and i == line.pending.target_point then if Editor_state.current_drawing_mode == 'name' and i == line.pending.target_point then
-- create a faint red box for the name -- create a faint red box for the name
App.color(Current_name_background_color) App.color(Current_name_background_color)
local name_text local name_text
-- TODO: avoid computing name width on every repaint -- TODO: avoid computing name width on every repaint
if p.name == '' then if p.name == '' then
name_text = Em name_text = Editor_state.em
else else
name_text = App.newText(love.graphics.getFont(), p.name) name_text = App.newText(love.graphics.getFont(), p.name)
end end
love.graphics.rectangle('fill', x,y, App.width(name_text), Line_height) love.graphics.rectangle('fill', x,y, App.width(name_text), Editor_state.line_height)
end end
end end
end end
end end
App.color(Current_stroke_color) App.color(Current_stroke_color)
Drawing.draw_pending_shape(Margin_left,line.y, line) Drawing.draw_pending_shape(Editor_state.margin_left,line.y, line)
end end
function Drawing.draw_shape(left,top, drawing, shape) function Drawing.draw_shape(left,top, drawing, shape)
@ -204,51 +204,51 @@ end
function Drawing.in_drawing(drawing, x,y) function Drawing.in_drawing(drawing, x,y)
if drawing.y == nil then return false end -- outside current page 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 >= Margin_left and x < App.screen.width-Margin_right return y >= drawing.y and y < drawing.y + Drawing.pixels(drawing.h) and x >= Editor_state.margin_left and x < App.screen.width-Editor_state.margin_right
end end
function Drawing.mouse_pressed(drawing, x,y, button) function Drawing.mouse_pressed(drawing, x,y, button)
if Current_drawing_mode == 'freehand' then if Editor_state.current_drawing_mode == 'freehand' then
drawing.pending = {mode=Current_drawing_mode, points={{x=Drawing.coord(x-Margin_left), y=Drawing.coord(y-drawing.y)}}} drawing.pending = {mode=Editor_state.current_drawing_mode, points={{x=Drawing.coord(x-Editor_state.margin_left), y=Drawing.coord(y-drawing.y)}}}
elseif Current_drawing_mode == 'line' or Current_drawing_mode == 'manhattan' then elseif Editor_state.current_drawing_mode == 'line' or Editor_state.current_drawing_mode == 'manhattan' then
local j = Drawing.insert_point(drawing.points, Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y)) local j = Drawing.insert_point(drawing.points, Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y))
drawing.pending = {mode=Current_drawing_mode, p1=j} drawing.pending = {mode=Editor_state.current_drawing_mode, p1=j}
elseif Current_drawing_mode == 'polygon' or Current_drawing_mode == 'rectangle' or Current_drawing_mode == 'square' then elseif Editor_state.current_drawing_mode == 'polygon' or Editor_state.current_drawing_mode == 'rectangle' or Editor_state.current_drawing_mode == 'square' then
local j = Drawing.insert_point(drawing.points, Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y)) local j = Drawing.insert_point(drawing.points, Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y))
drawing.pending = {mode=Current_drawing_mode, vertices={j}} drawing.pending = {mode=Editor_state.current_drawing_mode, vertices={j}}
elseif Current_drawing_mode == 'circle' then elseif Editor_state.current_drawing_mode == 'circle' then
local j = Drawing.insert_point(drawing.points, Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y)) local j = Drawing.insert_point(drawing.points, Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y))
drawing.pending = {mode=Current_drawing_mode, center=j} drawing.pending = {mode=Editor_state.current_drawing_mode, center=j}
elseif Current_drawing_mode == 'move' then elseif Editor_state.current_drawing_mode == 'move' then
-- all the action is in mouse_released -- all the action is in mouse_released
elseif Current_drawing_mode == 'name' then elseif Editor_state.current_drawing_mode == 'name' then
-- nothing -- nothing
else else
print(Current_drawing_mode) print(Editor_state.current_drawing_mode)
assert(false) assert(false)
end end
end end
-- a couple of operations on drawings need to constantly check the state of the mouse -- a couple of operations on drawings need to constantly check the state of the mouse
function Drawing.update() function Drawing.update()
if Lines.current_drawing == nil then return end if Editor_state.lines.current_drawing == nil then return end
local drawing = Lines.current_drawing local drawing = Editor_state.lines.current_drawing
assert(drawing.mode == 'drawing') assert(drawing.mode == 'drawing')
local x, y = App.mouse_x(), App.mouse_y() local x, y = App.mouse_x(), App.mouse_y()
if App.mouse_down(1) then if App.mouse_down(1) then
if Drawing.in_drawing(drawing, x,y) then if Drawing.in_drawing(drawing, x,y) then
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
table.insert(drawing.pending.points, {x=Drawing.coord(App.mouse_x()-Margin_left), y=Drawing.coord(App.mouse_y()-drawing.y)}) table.insert(drawing.pending.points, {x=Drawing.coord(App.mouse_x()-Editor_state.margin_left), y=Drawing.coord(App.mouse_y()-drawing.y)})
elseif drawing.pending.mode == 'move' then elseif drawing.pending.mode == 'move' then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
drawing.pending.target_point.x = mx drawing.pending.target_point.x = mx
drawing.pending.target_point.y = my drawing.pending.target_point.y = my
Drawing.relax_constraints(drawing, drawing.pending.target_point_index) Drawing.relax_constraints(drawing, drawing.pending.target_point_index)
end end
end end
elseif Current_drawing_mode == 'move' then elseif Editor_state.current_drawing_mode == 'move' then
if Drawing.in_drawing(drawing, x, y) then if Drawing.in_drawing(drawing, x, y) then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
drawing.pending.target_point.x = mx drawing.pending.target_point.x = mx
drawing.pending.target_point.y = my drawing.pending.target_point.y = my
Drawing.relax_constraints(drawing, drawing.pending.target_point_index) Drawing.relax_constraints(drawing, drawing.pending.target_point_index)
@ -277,15 +277,15 @@ function Drawing.relax_constraints(drawing, p)
end end
function Drawing.mouse_released(x,y, button) function Drawing.mouse_released(x,y, button)
if Current_drawing_mode == 'move' then if Editor_state.current_drawing_mode == 'move' then
Current_drawing_mode = Previous_drawing_mode Editor_state.current_drawing_mode = Editor_state.previous_drawing_mode
Previous_drawing_mode = nil Editor_state.previous_drawing_mode = nil
if Lines.current_drawing then if Editor_state.lines.current_drawing then
Lines.current_drawing.pending = {} Editor_state.lines.current_drawing.pending = {}
Lines.current_drawing = nil Editor_state.lines.current_drawing = nil
end end
elseif Lines.current_drawing then elseif Editor_state.lines.current_drawing then
local drawing = Lines.current_drawing local drawing = Editor_state.lines.current_drawing
if drawing.pending then if drawing.pending then
if drawing.pending.mode == nil then if drawing.pending.mode == nil then
-- nothing pending -- nothing pending
@ -294,14 +294,14 @@ function Drawing.mouse_released(x,y, button)
Drawing.smoothen(drawing.pending) Drawing.smoothen(drawing.pending)
table.insert(drawing.shapes, drawing.pending) table.insert(drawing.shapes, drawing.pending)
elseif drawing.pending.mode == 'line' then elseif drawing.pending.mode == 'line' then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
drawing.pending.p2 = Drawing.insert_point(drawing.points, mx,my) drawing.pending.p2 = Drawing.insert_point(drawing.points, mx,my)
table.insert(drawing.shapes, drawing.pending) table.insert(drawing.shapes, drawing.pending)
end end
elseif drawing.pending.mode == 'manhattan' then elseif drawing.pending.mode == 'manhattan' then
local p1 = drawing.points[drawing.pending.p1] local p1 = drawing.points[drawing.pending.p1]
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
if math.abs(mx-p1.x) > math.abs(my-p1.y) then if math.abs(mx-p1.x) > math.abs(my-p1.y) then
drawing.pending.p2 = Drawing.insert_point(drawing.points, mx, p1.y) drawing.pending.p2 = Drawing.insert_point(drawing.points, mx, p1.y)
@ -309,11 +309,11 @@ function Drawing.mouse_released(x,y, button)
drawing.pending.p2 = Drawing.insert_point(drawing.points, p1.x, my) drawing.pending.p2 = Drawing.insert_point(drawing.points, p1.x, my)
end end
local p2 = drawing.points[drawing.pending.p2] local p2 = drawing.points[drawing.pending.p2]
App.mouse_move(Margin_left+Drawing.pixels(p2.x), drawing.y+Drawing.pixels(p2.y)) App.mouse_move(Editor_state.margin_left+Drawing.pixels(p2.x), drawing.y+Drawing.pixels(p2.y))
table.insert(drawing.shapes, drawing.pending) table.insert(drawing.shapes, drawing.pending)
end end
elseif drawing.pending.mode == 'polygon' then elseif drawing.pending.mode == 'polygon' then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
table.insert(drawing.pending.vertices, Drawing.insert_point(drawing.points, mx,my)) table.insert(drawing.pending.vertices, Drawing.insert_point(drawing.points, mx,my))
table.insert(drawing.shapes, drawing.pending) table.insert(drawing.shapes, drawing.pending)
@ -321,7 +321,7 @@ function Drawing.mouse_released(x,y, button)
elseif drawing.pending.mode == 'rectangle' then elseif drawing.pending.mode == 'rectangle' then
assert(#drawing.pending.vertices <= 2) assert(#drawing.pending.vertices <= 2)
if #drawing.pending.vertices == 2 then if #drawing.pending.vertices == 2 then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local first = drawing.points[drawing.pending.vertices[1]] local first = drawing.points[drawing.pending.vertices[1]]
local second = drawing.points[drawing.pending.vertices[2]] local second = drawing.points[drawing.pending.vertices[2]]
@ -336,7 +336,7 @@ function Drawing.mouse_released(x,y, button)
elseif drawing.pending.mode == 'square' then elseif drawing.pending.mode == 'square' then
assert(#drawing.pending.vertices <= 2) assert(#drawing.pending.vertices <= 2)
if #drawing.pending.vertices == 2 then if #drawing.pending.vertices == 2 then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local first = drawing.points[drawing.pending.vertices[1]] local first = drawing.points[drawing.pending.vertices[1]]
local second = drawing.points[drawing.pending.vertices[2]] local second = drawing.points[drawing.pending.vertices[2]]
@ -347,14 +347,14 @@ function Drawing.mouse_released(x,y, button)
end end
end end
elseif drawing.pending.mode == 'circle' then elseif drawing.pending.mode == 'circle' then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local center = drawing.points[drawing.pending.center] local center = drawing.points[drawing.pending.center]
drawing.pending.radius = geom.dist(center.x,center.y, mx,my) drawing.pending.radius = geom.dist(center.x,center.y, mx,my)
table.insert(drawing.shapes, drawing.pending) table.insert(drawing.shapes, drawing.pending)
end end
elseif drawing.pending.mode == 'arc' then elseif drawing.pending.mode == 'arc' then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local center = drawing.points[drawing.pending.center] local center = drawing.points[drawing.pending.center]
drawing.pending.end_angle = geom.angle_with_hint(center.x,center.y, mx,my, drawing.pending.end_angle) drawing.pending.end_angle = geom.angle_with_hint(center.x,center.y, mx,my, drawing.pending.end_angle)
@ -366,17 +366,17 @@ function Drawing.mouse_released(x,y, button)
print(drawing.pending.mode) print(drawing.pending.mode)
assert(false) assert(false)
end end
Lines.current_drawing.pending = {} Editor_state.lines.current_drawing.pending = {}
Lines.current_drawing = nil Editor_state.lines.current_drawing = nil
end end
end end
end end
function Drawing.keychord_pressed(chord) function Drawing.keychord_pressed(chord)
if chord == 'C-p' and not App.mouse_down(1) then if chord == 'C-p' and not App.mouse_down(1) then
Current_drawing_mode = 'freehand' Editor_state.current_drawing_mode = 'freehand'
elseif App.mouse_down(1) and chord == 'l' then elseif App.mouse_down(1) and chord == 'l' then
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
@ -387,9 +387,9 @@ function Drawing.keychord_pressed(chord)
end end
drawing.pending.mode = 'line' drawing.pending.mode = 'line'
elseif chord == 'C-l' and not App.mouse_down(1) then elseif chord == 'C-l' and not App.mouse_down(1) then
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
elseif App.mouse_down(1) and chord == 'm' then elseif App.mouse_down(1) and chord == 'm' then
Current_drawing_mode = 'manhattan' Editor_state.current_drawing_mode = 'manhattan'
local drawing = Drawing.select_drawing_at_mouse() local drawing = Drawing.select_drawing_at_mouse()
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
@ -402,11 +402,11 @@ function Drawing.keychord_pressed(chord)
end end
drawing.pending.mode = 'manhattan' drawing.pending.mode = 'manhattan'
elseif chord == 'C-m' and not App.mouse_down(1) then elseif chord == 'C-m' and not App.mouse_down(1) then
Current_drawing_mode = 'manhattan' Editor_state.current_drawing_mode = 'manhattan'
elseif chord == 'C-g' and not App.mouse_down(1) then elseif chord == 'C-g' and not App.mouse_down(1) then
Current_drawing_mode = 'polygon' Editor_state.current_drawing_mode = 'polygon'
elseif App.mouse_down(1) and chord == 'g' then elseif App.mouse_down(1) and chord == 'g' then
Current_drawing_mode = 'polygon' Editor_state.current_drawing_mode = 'polygon'
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)} drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
@ -421,9 +421,9 @@ function Drawing.keychord_pressed(chord)
end end
drawing.pending.mode = 'polygon' drawing.pending.mode = 'polygon'
elseif chord == 'C-r' and not App.mouse_down(1) then elseif chord == 'C-r' and not App.mouse_down(1) then
Current_drawing_mode = 'rectangle' Editor_state.current_drawing_mode = 'rectangle'
elseif App.mouse_down(1) and chord == 'r' then elseif App.mouse_down(1) and chord == 'r' then
Current_drawing_mode = 'rectangle' Editor_state.current_drawing_mode = 'rectangle'
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)} drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
@ -438,9 +438,9 @@ function Drawing.keychord_pressed(chord)
end end
drawing.pending.mode = 'rectangle' drawing.pending.mode = 'rectangle'
elseif chord == 'C-s' and not App.mouse_down(1) then elseif chord == 'C-s' and not App.mouse_down(1) then
Current_drawing_mode = 'square' Editor_state.current_drawing_mode = 'square'
elseif App.mouse_down(1) and chord == 's' then elseif App.mouse_down(1) and chord == 's' then
Current_drawing_mode = 'square' Editor_state.current_drawing_mode = 'square'
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)} drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)}
@ -458,30 +458,30 @@ function Drawing.keychord_pressed(chord)
drawing.pending.vertices = {drawing.pending.center} drawing.pending.vertices = {drawing.pending.center}
end end
drawing.pending.mode = 'square' drawing.pending.mode = 'square'
elseif App.mouse_down(1) and chord == 'p' and Current_drawing_mode == 'polygon' then elseif App.mouse_down(1) and chord == 'p' and Editor_state.current_drawing_mode == 'polygon' then
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
local mx,my = Drawing.coord(App.mouse_x()-Margin_left), Drawing.coord(App.mouse_y()-drawing.y) local mx,my = Drawing.coord(App.mouse_x()-Editor_state.margin_left), Drawing.coord(App.mouse_y()-drawing.y)
local j = Drawing.insert_point(drawing.points, mx,my) local j = Drawing.insert_point(drawing.points, mx,my)
table.insert(drawing.pending.vertices, j) 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 elseif App.mouse_down(1) and chord == 'p' and (Editor_state.current_drawing_mode == 'rectangle' or Editor_state.current_drawing_mode == 'square') then
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
local mx,my = Drawing.coord(App.mouse_x()-Margin_left), Drawing.coord(App.mouse_y()-drawing.y) local mx,my = Drawing.coord(App.mouse_x()-Editor_state.margin_left), Drawing.coord(App.mouse_y()-drawing.y)
local j = Drawing.insert_point(drawing.points, mx,my) local j = Drawing.insert_point(drawing.points, mx,my)
while #drawing.pending.vertices >= 2 do while #drawing.pending.vertices >= 2 do
table.remove(drawing.pending.vertices) table.remove(drawing.pending.vertices)
end end
table.insert(drawing.pending.vertices, j) table.insert(drawing.pending.vertices, j)
elseif chord == 'C-o' and not App.mouse_down(1) then elseif chord == 'C-o' and not App.mouse_down(1) then
Current_drawing_mode = 'circle' Editor_state.current_drawing_mode = 'circle'
elseif App.mouse_down(1) and chord == 'a' and Current_drawing_mode == 'circle' then elseif App.mouse_down(1) and chord == 'a' and Editor_state.current_drawing_mode == 'circle' then
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
drawing.pending.mode = 'arc' drawing.pending.mode = 'arc'
local mx,my = Drawing.coord(App.mouse_x()-Margin_left), Drawing.coord(App.mouse_y()-drawing.y) local mx,my = Drawing.coord(App.mouse_x()-Editor_state.margin_left), Drawing.coord(App.mouse_y()-drawing.y)
local center = drawing.points[drawing.pending.center] local center = drawing.points[drawing.pending.center]
drawing.pending.radius = geom.dist(center.x,center.y, mx,my) drawing.pending.radius = geom.dist(center.x,center.y, mx,my)
drawing.pending.start_angle = geom.angle(center.x,center.y, mx,my) drawing.pending.start_angle = geom.angle(center.x,center.y, mx,my)
elseif App.mouse_down(1) and chord == 'o' then elseif App.mouse_down(1) and chord == 'o' then
Current_drawing_mode = 'circle' Editor_state.current_drawing_mode = 'circle'
local _,drawing = Drawing.current_drawing() local _,drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then if drawing.pending.mode == 'freehand' then
drawing.pending.center = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) drawing.pending.center = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
@ -494,26 +494,26 @@ function Drawing.keychord_pressed(chord)
elseif chord == 'C-u' and not App.mouse_down(1) then elseif chord == 'C-u' and not App.mouse_down(1) then
local drawing_index,drawing,i,p = Drawing.select_point_at_mouse() local drawing_index,drawing,i,p = Drawing.select_point_at_mouse()
if drawing then if drawing then
if Previous_drawing_mode == nil then if Editor_state.previous_drawing_mode == nil then
Previous_drawing_mode = Current_drawing_mode Editor_state.previous_drawing_mode = Editor_state.current_drawing_mode
end end
Current_drawing_mode = 'move' Editor_state.current_drawing_mode = 'move'
drawing.pending = {mode=Current_drawing_mode, target_point=p, target_point_index=i} drawing.pending = {mode=Editor_state.current_drawing_mode, target_point=p, target_point_index=i}
Lines.current_drawing_index = drawing_index Editor_state.lines.current_drawing_index = drawing_index
Lines.current_drawing = drawing Editor_state.lines.current_drawing = drawing
end end
elseif chord == 'C-n' and not App.mouse_down(1) then elseif chord == 'C-n' and not App.mouse_down(1) then
local drawing_index,drawing,point_index,p = Drawing.select_point_at_mouse() local drawing_index,drawing,point_index,p = Drawing.select_point_at_mouse()
if drawing then if drawing then
if Previous_drawing_mode == nil then if Editor_state.previous_drawing_mode == nil then
-- don't clobber -- don't clobber
Previous_drawing_mode = Current_drawing_mode Editor_state.previous_drawing_mode = Editor_state.current_drawing_mode
end end
Current_drawing_mode = 'name' Editor_state.current_drawing_mode = 'name'
p.name = '' p.name = ''
drawing.pending = {mode=Current_drawing_mode, target_point=point_index} drawing.pending = {mode=Editor_state.current_drawing_mode, target_point=point_index}
Lines.current_drawing_index = drawing_index Editor_state.lines.current_drawing_index = drawing_index
Lines.current_drawing = drawing Editor_state.lines.current_drawing = drawing
end end
elseif chord == 'C-d' and not App.mouse_down(1) then elseif chord == 'C-d' and not App.mouse_down(1) then
local _,drawing,i,p = Drawing.select_point_at_mouse() local _,drawing,i,p = Drawing.select_point_at_mouse()
@ -599,7 +599,7 @@ end
function Drawing.current_drawing() function Drawing.current_drawing()
local x, y = App.mouse_x(), App.mouse_y() local x, y = App.mouse_x(), App.mouse_y()
for drawing_index,drawing in ipairs(Lines) do for drawing_index,drawing in ipairs(Editor_state.lines) do
if drawing.mode == 'drawing' then if drawing.mode == 'drawing' then
if Drawing.in_drawing(drawing, x,y) then if Drawing.in_drawing(drawing, x,y) then
return drawing_index,drawing return drawing_index,drawing
@ -610,11 +610,11 @@ function Drawing.current_drawing()
end end
function Drawing.select_shape_at_mouse() function Drawing.select_shape_at_mouse()
for _,drawing in ipairs(Lines) do for _,drawing in ipairs(Editor_state.lines) do
if drawing.mode == 'drawing' then if drawing.mode == 'drawing' then
local x, y = App.mouse_x(), App.mouse_y() local x, y = App.mouse_x(), App.mouse_y()
if Drawing.in_drawing(drawing, x,y) then if Drawing.in_drawing(drawing, x,y) then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
for i,shape in ipairs(drawing.shapes) do for i,shape in ipairs(drawing.shapes) do
assert(shape) assert(shape)
if geom.on_shape(mx,my, drawing, shape) then if geom.on_shape(mx,my, drawing, shape) then
@ -627,11 +627,11 @@ function Drawing.select_shape_at_mouse()
end end
function Drawing.select_point_at_mouse() function Drawing.select_point_at_mouse()
for drawing_index,drawing in ipairs(Lines) do for drawing_index,drawing in ipairs(Editor_state.lines) do
if drawing.mode == 'drawing' then if drawing.mode == 'drawing' then
local x, y = App.mouse_x(), App.mouse_y() local x, y = App.mouse_x(), App.mouse_y()
if Drawing.in_drawing(drawing, x,y) then if Drawing.in_drawing(drawing, x,y) then
local mx,my = Drawing.coord(x-Margin_left), Drawing.coord(y-drawing.y) local mx,my = Drawing.coord(x-Editor_state.margin_left), Drawing.coord(y-drawing.y)
for i,point in ipairs(drawing.points) do for i,point in ipairs(drawing.points) do
assert(point) assert(point)
if Drawing.near(point, mx,my) then if Drawing.near(point, mx,my) then
@ -644,7 +644,7 @@ function Drawing.select_point_at_mouse()
end end
function Drawing.select_drawing_at_mouse() function Drawing.select_drawing_at_mouse()
for _,drawing in ipairs(Lines) do for _,drawing in ipairs(Editor_state.lines) do
if drawing.mode == 'drawing' then if drawing.mode == 'drawing' then
local x, y = App.mouse_x(), App.mouse_y() local x, y = App.mouse_x(), App.mouse_y()
if Drawing.in_drawing(drawing, x,y) then if Drawing.in_drawing(drawing, x,y) then
@ -700,14 +700,14 @@ end
function Drawing.near(point, x,y) function Drawing.near(point, x,y)
local px,py = Drawing.pixels(x),Drawing.pixels(y) local px,py = Drawing.pixels(x),Drawing.pixels(y)
local cx,cy = Drawing.pixels(point.x), Drawing.pixels(point.y) local cx,cy = Drawing.pixels(point.x), Drawing.pixels(point.y)
return (cx-px)*(cx-px) + (cy-py)*(cy-py) < Margin_left return (cx-px)*(cx-px) + (cy-py)*(cy-py) < Editor_state.margin_left
end end
function Drawing.pixels(n) -- parts to pixels function Drawing.pixels(n) -- parts to pixels
return math.floor(n*(App.screen.width-Margin_width)/256) return math.floor(n*(App.screen.width-Editor_state.margin_width)/256)
end end
function Drawing.coord(n) -- pixels to parts function Drawing.coord(n) -- pixels to parts
return math.floor(n*256/(App.screen.width-Margin_width)) return math.floor(n*256/(App.screen.width-Editor_state.margin_width))
end end
function table.find(h, x) function table.find(h, x)

View File

@ -5,11 +5,11 @@
function test_creating_drawing_saves() function test_creating_drawing_saves()
io.write('\ntest_creating_drawing_saves') io.write('\ntest_creating_drawing_saves')
App.screen.init{width=120, height=60} App.screen.init{width=120, height=60}
Filename = 'foo' Editor_state.filename = 'foo'
Lines = load_array{} Editor_state.lines = load_array{}
edit.draw() edit.draw()
-- click on button to create drawing -- click on button to create drawing
App.run_after_mouse_click(8,Margin_top+8, 1) App.run_after_mouse_click(8,Editor_state.margin_top+8, 1)
-- file not immediately saved -- file not immediately saved
App.update(0.01) App.update(0.01)
check_nil(App.filesystem['foo'], 'F - test_creating_drawing_saves/early') check_nil(App.filesystem['foo'], 'F - test_creating_drawing_saves/early')
@ -23,20 +23,20 @@ end
function test_draw_line() function test_draw_line()
io.write('\ntest_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) -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
check_eq(#Lines, 2, 'F - test_draw_line/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_line/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_line/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_draw_line/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_line/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_line/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_line/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_line/baseline/#shapes')
-- draw a line -- draw a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_line/#shapes') check_eq(#drawing.shapes, 1, 'F - test_draw_line/#shapes')
check_eq(#drawing.points, 2, 'F - test_draw_line/#points') check_eq(#drawing.points, 2, 'F - test_draw_line/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/shape:1')
@ -51,8 +51,8 @@ function test_draw_line()
App.update(0) App.update(0)
-- The format on disk isn't perfectly stable. Table fields can be reordered. -- The format on disk isn't perfectly stable. Table fields can be reordered.
-- So just reload from disk to verify. -- So just reload from disk to verify.
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_line/save/#shapes') 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.points, 2, 'F - test_draw_line/save/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/save/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_draw_line/save/shape:1')
@ -67,19 +67,19 @@ end
function test_draw_horizontal_line() function test_draw_horizontal_line()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'manhattan' Editor_state.current_drawing_mode = 'manhattan'
edit.draw() edit.draw()
check_eq(#Lines, 2, 'F - test_draw_horizontal_line/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_horizontal_line/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_horizontal_line/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.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(Editor_state.lines[1].h, 128, 'F - test_draw_horizontal_line/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_horizontal_line/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_horizontal_line/baseline/#shapes')
-- draw a line that is more horizontal than vertical -- 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_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+26, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_horizontal_line/#shapes') 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.points, 2, 'F - test_draw_horizontal_line/#points')
check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_draw_horizontal_line/shape_mode') check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_draw_horizontal_line/shape_mode')
@ -94,21 +94,21 @@ end
function test_draw_circle() function test_draw_circle()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
check_eq(#Lines, 2, 'F - test_draw_circle/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_circle/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_circle/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_draw_circle/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_circle/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_circle/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_circle/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_circle/baseline/#shapes')
-- draw a circle -- draw a circle
App.mouse_move(Margin_left+4, Margin_top+Drawing_padding_top+4) -- hover on drawing App.mouse_move(Editor_state.margin_left+4, Editor_state.margin_top+Editor_state.drawing_padding_top+4) -- hover on drawing
App.run_after_keychord('C-o') 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_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+35+30, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35+30, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_circle/#shapes') check_eq(#drawing.shapes, 1, 'F - test_draw_circle/#shapes')
check_eq(#drawing.points, 1, 'F - test_draw_circle/#points') 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].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
@ -121,58 +121,58 @@ end
function test_cancel_stroke() function test_cancel_stroke()
io.write('\ntest_cancel_stroke') io.write('\ntest_cancel_stroke')
-- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end) -- display a drawing followed by a line of text (you shouldn't ever have a drawing right at the end)
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
check_eq(#Lines, 2, 'F - test_cancel_stroke/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_cancel_stroke/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_cancel_stroke/baseline/mode') check_eq(Editor_state.lines[1].mode, 'drawing', 'F - test_cancel_stroke/baseline/mode')
check_eq(Lines[1].y, Margin_top+Drawing_padding_top, 'F - test_cancel_stroke/baseline/y') check_eq(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_cancel_stroke/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_cancel_stroke/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_cancel_stroke/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_cancel_stroke/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_cancel_stroke/baseline/#shapes')
-- start drawing a line -- start drawing a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
-- cancel -- cancel
App.run_after_keychord('escape') App.run_after_keychord('escape')
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 0, 'F - test_cancel_stroke/#shapes') check_eq(#drawing.shapes, 0, 'F - test_cancel_stroke/#shapes')
end end
function test_keys_do_not_affect_shape_when_mouse_up() function test_keys_do_not_affect_shape_when_mouse_up()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
-- hover over drawing and press 'o' without holding mouse -- 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.mouse_move(Editor_state.margin_left+4, Editor_state.margin_top+Editor_state.drawing_padding_top+4) -- hover on drawing
App.run_after_keychord('o') App.run_after_keychord('o')
-- no change to drawing mode -- no change to drawing mode
check_eq(Current_drawing_mode, 'line', 'F - test_keys_do_not_affect_shape_when_mouse_up/drawing_mode') check_eq(Editor_state.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 -- no change to text either because we didn't run the textinput event
end end
function test_draw_circle_mid_stroke() function test_draw_circle_mid_stroke()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
check_eq(#Lines, 2, 'F - test_draw_circle_mid_stroke/baseline/#lines') check_eq(#Editor_state.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(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.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(Editor_state.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') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_circle_mid_stroke/baseline/#shapes')
-- draw a circle -- draw a circle
App.mouse_move(Margin_left+4, Margin_top+Drawing_padding_top+4) -- hover on drawing App.mouse_move(Editor_state.margin_left+4, Editor_state.margin_top+Editor_state.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_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_keychord('o') App.run_after_keychord('o')
App.run_after_mouse_release(Margin_left+35+30, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35+30, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_circle_mid_stroke/#shapes') 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.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].mode, 'circle', 'F - test_draw_horizontal_line/shape_mode')
@ -185,21 +185,21 @@ end
function test_draw_arc() function test_draw_arc()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'circle' Editor_state.current_drawing_mode = 'circle'
edit.draw() edit.draw()
check_eq(#Lines, 2, 'F - test_draw_arc/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_arc/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_arc/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_draw_arc/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_arc/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_arc/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_arc/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_arc/baseline/#shapes')
-- draw an arc -- draw an arc
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.mouse_move(Margin_left+35+30, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+35+30, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('a') -- arc mode 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° App.run_after_mouse_release(Editor_state.margin_left+35+50, Editor_state.margin_top+Editor_state.drawing_padding_top+36+50, 1) -- 45°
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_arc/#shapes') check_eq(#drawing.shapes, 1, 'F - test_draw_arc/#shapes')
check_eq(#drawing.points, 1, 'F - test_draw_arc/#points') check_eq(#drawing.points, 1, 'F - test_draw_arc/#points')
check_eq(drawing.shapes[1].mode, 'arc', 'F - test_draw_horizontal_line/shape_mode') check_eq(drawing.shapes[1].mode, 'arc', 'F - test_draw_horizontal_line/shape_mode')
@ -215,24 +215,24 @@ end
function test_draw_polygon() function test_draw_polygon()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
edit.draw() edit.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_polygon/baseline/drawing_mode') check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_polygon/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_polygon/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_polygon/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_polygon/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_draw_polygon/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_polygon/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_polygon/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_polygon/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_polygon/baseline/#shapes')
-- first point -- first point
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_keychord('g') -- polygon mode App.run_after_keychord('g') -- polygon mode
-- second point -- second point
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+65, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('p') -- add point App.run_after_keychord('p') -- add point
-- final point -- final point
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+26, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_polygon/#shapes') check_eq(#drawing.shapes, 1, 'F - test_draw_polygon/#shapes')
check_eq(#drawing.points, 3, 'F - test_draw_polygon/vertices') check_eq(#drawing.points, 3, 'F - test_draw_polygon/vertices')
local shape = drawing.shapes[1] local shape = drawing.shapes[1]
@ -252,27 +252,27 @@ end
function test_draw_rectangle() function test_draw_rectangle()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
edit.draw() edit.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_rectangle/baseline/drawing_mode') check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_rectangle/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_rectangle/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_rectangle/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_rectangle/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_draw_rectangle/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_rectangle/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_rectangle/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_rectangle/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_rectangle/baseline/#shapes')
-- first point -- first point
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_keychord('r') -- rectangle mode App.run_after_keychord('r') -- rectangle mode
-- second point/first edge -- second point/first edge
App.mouse_move(Margin_left+42, Margin_top+Drawing_padding_top+45) App.mouse_move(Editor_state.margin_left+42, Editor_state.margin_top+Editor_state.drawing_padding_top+45)
App.run_after_keychord('p') App.run_after_keychord('p')
-- override second point/first edge -- override second point/first edge
App.mouse_move(Margin_left+75, Margin_top+Drawing_padding_top+76) App.mouse_move(Editor_state.margin_left+75, Editor_state.margin_top+Editor_state.drawing_padding_top+76)
App.run_after_keychord('p') App.run_after_keychord('p')
-- release (decides 'thickness' of rectangle perpendicular to first edge) -- release (decides 'thickness' of rectangle perpendicular to first edge)
App.run_after_mouse_release(Margin_left+15, Margin_top+Drawing_padding_top+26, 1) App.run_after_mouse_release(Editor_state.margin_left+15, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_rectangle/#shapes') 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 check_eq(#drawing.points, 5, 'F - test_draw_rectangle/#points') -- currently includes every point added
local shape = drawing.shapes[1] local shape = drawing.shapes[1]
@ -295,25 +295,25 @@ end
function test_draw_rectangle_intermediate() function test_draw_rectangle_intermediate()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
edit.draw() edit.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_rectangle_intermediate/baseline/drawing_mode') check_eq(Editor_state.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(#Editor_state.lines, 2, 'F - test_draw_rectangle_intermediate/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_rectangle_intermediate/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.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(Editor_state.lines[1].h, 128, 'F - test_draw_rectangle_intermediate/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_rectangle_intermediate/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_rectangle_intermediate/baseline/#shapes')
-- first point -- first point
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_keychord('r') -- rectangle mode App.run_after_keychord('r') -- rectangle mode
-- second point/first edge -- second point/first edge
App.mouse_move(Margin_left+42, Margin_top+Drawing_padding_top+45) App.mouse_move(Editor_state.margin_left+42, Editor_state.margin_top+Editor_state.drawing_padding_top+45)
App.run_after_keychord('p') App.run_after_keychord('p')
-- override second point/first edge -- override second point/first edge
App.mouse_move(Margin_left+75, Margin_top+Drawing_padding_top+76) App.mouse_move(Editor_state.margin_left+75, Editor_state.margin_top+Editor_state.drawing_padding_top+76)
App.run_after_keychord('p') App.run_after_keychord('p')
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.points, 3, 'F - test_draw_rectangle_intermediate/#points') -- currently includes every point added check_eq(#drawing.points, 3, 'F - test_draw_rectangle_intermediate/#points') -- currently includes every point added
local pending = drawing.pending local pending = drawing.pending
check_eq(pending.mode, 'rectangle', 'F - test_draw_rectangle_intermediate/shape_mode') check_eq(pending.mode, 'rectangle', 'F - test_draw_rectangle_intermediate/shape_mode')
@ -330,27 +330,27 @@ end
function test_draw_square() function test_draw_square()
io.write('\ntest_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) -- 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_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
edit.draw() edit.draw()
check_eq(Current_drawing_mode, 'line', 'F - test_draw_square/baseline/drawing_mode') check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_draw_square/baseline/drawing_mode')
check_eq(#Lines, 2, 'F - test_draw_square/baseline/#lines') check_eq(#Editor_state.lines, 2, 'F - test_draw_square/baseline/#lines')
check_eq(Lines[1].mode, 'drawing', 'F - test_draw_square/baseline/mode') check_eq(Editor_state.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(Editor_state.lines[1].y, Editor_state.margin_top+Editor_state.drawing_padding_top, 'F - test_draw_square/baseline/y')
check_eq(Lines[1].h, 128, 'F - test_draw_square/baseline/y') check_eq(Editor_state.lines[1].h, 128, 'F - test_draw_square/baseline/y')
check_eq(#Lines[1].shapes, 0, 'F - test_draw_square/baseline/#shapes') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_draw_square/baseline/#shapes')
-- first point -- first point
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_keychord('s') -- square mode App.run_after_keychord('s') -- square mode
-- second point/first edge -- second point/first edge
App.mouse_move(Margin_left+42, Margin_top+Drawing_padding_top+45) App.mouse_move(Editor_state.margin_left+42, Editor_state.margin_top+Editor_state.drawing_padding_top+45)
App.run_after_keychord('p') App.run_after_keychord('p')
-- override second point/first edge -- override second point/first edge
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+66) App.mouse_move(Editor_state.margin_left+65, Editor_state.margin_top+Editor_state.drawing_padding_top+66)
App.run_after_keychord('p') App.run_after_keychord('p')
-- release (decides which side of first edge to draw square on) -- 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) App.run_after_mouse_release(Editor_state.margin_left+15, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_draw_square/#shapes') 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.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].mode, 'square', 'F - test_draw_square/shape_mode')
@ -372,15 +372,15 @@ end
function test_name_point() function test_name_point()
io.write('\ntest_name_point') io.write('\ntest_name_point')
-- create a drawing with a line -- create a drawing with a line
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
-- draw a line -- draw a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_name_point/baseline/#shapes') 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.points, 2, 'F - test_name_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_name_point/baseline/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_name_point/baseline/shape:1')
@ -393,35 +393,35 @@ function test_name_point()
check_nil(p2.name, 'F - test_name_point/baseline/p2:name') check_nil(p2.name, 'F - test_name_point/baseline/p2:name')
-- enter 'name' mode without moving the mouse -- enter 'name' mode without moving the mouse
App.run_after_keychord('C-n') App.run_after_keychord('C-n')
check_eq(Current_drawing_mode, 'name', 'F - test_name_point/mode:1') check_eq(Editor_state.current_drawing_mode, 'name', 'F - test_name_point/mode:1')
App.run_after_textinput('A') App.run_after_textinput('A')
check_eq(p2.name, 'A', 'F - test_name_point') check_eq(p2.name, 'A', 'F - test_name_point')
-- still in 'name' mode -- still in 'name' mode
check_eq(Current_drawing_mode, 'name', 'F - test_name_point/mode:2') check_eq(Editor_state.current_drawing_mode, 'name', 'F - test_name_point/mode:2')
-- exit 'name' mode -- exit 'name' mode
App.run_after_keychord('return') App.run_after_keychord('return')
check_eq(Current_drawing_mode, 'line', 'F - test_name_point/mode:3') check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_name_point/mode:3')
check_eq(p2.name, 'A', 'F - test_name_point') check_eq(p2.name, 'A', 'F - test_name_point')
-- wait until save -- wait until save
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- change is saved -- change is saved
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
local p2 = Lines[1].points[drawing.shapes[1].p2] local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
check_eq(p2.name, 'A', 'F - test_name_point/save') check_eq(p2.name, 'A', 'F - test_name_point/save')
end end
function test_move_point() function test_move_point()
io.write('\ntest_move_point') io.write('\ntest_move_point')
-- create a drawing with a line -- create a drawing with a line
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_move_point/baseline/#shapes') 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.points, 2, 'F - test_move_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point/baseline/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point/baseline/shape:1')
@ -435,34 +435,34 @@ function test_move_point()
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- line is saved to disk -- line is saved to disk
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
local p2 = Lines[1].points[drawing.shapes[1].p2] local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
check_eq(p2.x, 35, 'F - test_move_point/save/x') check_eq(p2.x, 35, 'F - test_move_point/save/x')
check_eq(p2.y, 36, 'F - test_move_point/save/y') check_eq(p2.y, 36, 'F - test_move_point/save/y')
edit.draw() edit.draw()
-- enter 'move' mode without moving the mouse -- enter 'move' mode without moving the mouse
App.run_after_keychord('C-u') App.run_after_keychord('C-u')
check_eq(Current_drawing_mode, 'move', 'F - test_move_point/mode:1') check_eq(Editor_state.current_drawing_mode, 'move', 'F - test_move_point/mode:1')
-- point is lifted -- point is lifted
check_eq(drawing.pending.mode, 'move', 'F - test_move_point/mode:2') check_eq(drawing.pending.mode, 'move', 'F - test_move_point/mode:2')
check_eq(drawing.pending.target_point, p2, 'F - test_move_point/target') check_eq(drawing.pending.target_point, p2, 'F - test_move_point/target')
-- move point -- move point
App.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44) App.mouse_move(Editor_state.margin_left+26, Editor_state.margin_top+Editor_state.drawing_padding_top+44)
App.update(0.05) App.update(0.05)
local p2 = drawing.points[drawing.shapes[1].p2] local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p2.x, 26, 'F - test_move_point/x') check_eq(p2.x, 26, 'F - test_move_point/x')
check_eq(p2.y, 44, 'F - test_move_point/y') check_eq(p2.y, 44, 'F - test_move_point/y')
-- exit 'move' mode -- exit 'move' mode
App.run_after_mouse_click(Margin_left+26, Margin_top+Drawing_padding_top+44, 1) App.run_after_mouse_click(Editor_state.margin_left+26, Editor_state.margin_top+Editor_state.drawing_padding_top+44, 1)
check_eq(Current_drawing_mode, 'line', 'F - test_move_point/mode:3') check_eq(Editor_state.current_drawing_mode, 'line', 'F - test_move_point/mode:3')
check_eq(drawing.pending, {}, 'F - test_move_point/pending') check_eq(drawing.pending, {}, 'F - test_move_point/pending')
-- wait until save -- wait until save
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- change is saved -- change is saved
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
local p2 = Lines[1].points[drawing.shapes[1].p2] local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
check_eq(p2.x, 26, 'F - test_move_point/save/x') check_eq(p2.x, 26, 'F - test_move_point/save/x')
check_eq(p2.y, 44, 'F - test_move_point/save/y') check_eq(p2.y, 44, 'F - test_move_point/save/y')
end end
@ -470,23 +470,23 @@ end
function test_move_point_on_manhattan_line() function test_move_point_on_manhattan_line()
io.write('\ntest_move_point_on_manhattan_line') io.write('\ntest_move_point_on_manhattan_line')
-- create a drawing with a manhattan line -- create a drawing with a manhattan line
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'manhattan' Editor_state.current_drawing_mode = 'manhattan'
edit.draw() edit.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+46, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+46, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_move_point_on_manhattan_line/baseline/#shapes') check_eq(#drawing.shapes, 1, 'F - test_move_point_on_manhattan_line/baseline/#shapes')
check_eq(#drawing.points, 2, 'F - test_move_point_on_manhattan_line/baseline/#points') check_eq(#drawing.points, 2, 'F - test_move_point_on_manhattan_line/baseline/#points')
check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_move_point_on_manhattan_line/baseline/shape:1') check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
edit.draw() edit.draw()
-- enter 'move' mode -- enter 'move' mode
App.run_after_keychord('C-u') App.run_after_keychord('C-u')
check_eq(Current_drawing_mode, 'move', 'F - test_move_point_on_manhattan_line/mode:1') check_eq(Editor_state.current_drawing_mode, 'move', 'F - test_move_point_on_manhattan_line/mode:1')
-- move point -- move point
App.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44) App.mouse_move(Editor_state.margin_left+26, Editor_state.margin_top+Editor_state.drawing_padding_top+44)
App.update(0.05) App.update(0.05)
-- line is no longer manhattan -- line is no longer manhattan
check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point_on_manhattan_line/baseline/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
@ -495,21 +495,21 @@ end
function test_delete_lines_at_point() function test_delete_lines_at_point()
io.write('\ntest_delete_lines_at_point') io.write('\ntest_delete_lines_at_point')
-- create a drawing with two lines connected at a point -- create a drawing with two lines connected at a point
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+55, Margin_top+Drawing_padding_top+26, 1) App.run_after_mouse_release(Editor_state.margin_left+55, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 2, 'F - test_delete_lines_at_point/baseline/#shapes') 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[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') check_eq(drawing.shapes[2].mode, 'line', 'F - test_delete_lines_at_point/baseline/shape:2')
-- hover on the common point and delete -- hover on the common point and delete
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('C-d') 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[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') check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_delete_lines_at_point/shape:2')
@ -517,27 +517,27 @@ function test_delete_lines_at_point()
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- deleted points disappear after file is reloaded -- deleted points disappear after file is reloaded
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
check_eq(#Lines[1].shapes, 0, 'F - test_delete_lines_at_point/save') check_eq(#Editor_state.lines[1].shapes, 0, 'F - test_delete_lines_at_point/save')
end end
function test_delete_line_under_mouse_pointer() function test_delete_line_under_mouse_pointer()
io.write('\ntest_delete_line_under_mouse_pointer') io.write('\ntest_delete_line_under_mouse_pointer')
-- create a drawing with two lines connected at a point -- create a drawing with two lines connected at a point
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+55, Margin_top+Drawing_padding_top+26, 1) App.run_after_mouse_release(Editor_state.margin_left+55, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 2, 'F - test_delete_line_under_mouse_pointer/baseline/#shapes') 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[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') 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 -- hover on one of the lines and delete
App.mouse_move(Margin_left+25, Margin_top+Drawing_padding_top+26) App.mouse_move(Editor_state.margin_left+25, Editor_state.margin_top+Editor_state.drawing_padding_top+26)
App.run_after_keychord('C-d') App.run_after_keychord('C-d')
-- only that line is deleted -- 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[1].mode, 'deleted', 'F - test_delete_line_under_mouse_pointer/shape:1')
@ -547,27 +547,27 @@ end
function test_delete_point_from_polygon() function test_delete_point_from_polygon()
io.write('\ntest_delete_point_from_polygon') io.write('\ntest_delete_point_from_polygon')
-- create a drawing with two lines connected at a point -- create a drawing with two lines connected at a point
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
-- first point -- first point
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_keychord('g') -- polygon mode App.run_after_keychord('g') -- polygon mode
-- second point -- second point
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+65, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('p') -- add point App.run_after_keychord('p') -- add point
-- third point -- third point
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+26) App.mouse_move(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+26)
App.run_after_keychord('p') -- add point App.run_after_keychord('p') -- add point
-- fourth point -- fourth point
App.run_after_mouse_release(Margin_left+14, Margin_top+Drawing_padding_top+16, 1) App.run_after_mouse_release(Editor_state.margin_left+14, Editor_state.margin_top+Editor_state.drawing_padding_top+16, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes') 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].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') check_eq(#drawing.shapes[1].vertices, 4, 'F - test_delete_point_from_polygon/baseline/vertices')
-- hover on a point and delete -- hover on a point and delete
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+26) App.mouse_move(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+26)
App.run_after_keychord('C-d') App.run_after_keychord('C-d')
-- just the one point is deleted -- 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].mode, 'polygon', 'F - test_delete_point_from_polygon/shape')
@ -577,24 +577,24 @@ end
function test_delete_point_from_polygon() function test_delete_point_from_polygon()
io.write('\ntest_delete_point_from_polygon') io.write('\ntest_delete_point_from_polygon')
-- create a drawing with two lines connected at a point -- create a drawing with two lines connected at a point
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
-- first point -- first point
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_keychord('g') -- polygon mode App.run_after_keychord('g') -- polygon mode
-- second point -- second point
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+65, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('p') -- add point App.run_after_keychord('p') -- add point
-- third point -- third point
App.run_after_mouse_release(Margin_left+14, Margin_top+Drawing_padding_top+16, 1) App.run_after_mouse_release(Editor_state.margin_left+14, Editor_state.margin_top+Editor_state.drawing_padding_top+16, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_delete_point_from_polygon/baseline/#shapes') 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].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') check_eq(#drawing.shapes[1].vertices, 3, 'F - test_delete_point_from_polygon/baseline/vertices')
-- hover on a point and delete -- hover on a point and delete
App.mouse_move(Margin_left+65, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+65, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('C-d') App.run_after_keychord('C-d')
-- there's < 3 points left, so the whole polygon is deleted -- there's < 3 points left, so the whole polygon is deleted
check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_point_from_polygon') check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_delete_point_from_polygon')
@ -603,15 +603,15 @@ end
function test_undo_name_point() function test_undo_name_point()
io.write('\ntest_undo_name_point') io.write('\ntest_undo_name_point')
-- create a drawing with a line -- create a drawing with a line
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
-- draw a line -- draw a line
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_undo_name_point/baseline/#shapes') 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.points, 2, 'F - test_undo_name_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_name_point/baseline/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_name_point/baseline/shape:1')
@ -622,40 +622,40 @@ function test_undo_name_point()
check_eq(p2.x, 35, 'F - test_undo_name_point/baseline/p2:x') 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_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_nil(p2.name, 'F - test_undo_name_point/baseline/p2:name')
check_eq(#History, 1, 'F - test_undo_name_point/baseline/history:1') check_eq(#Editor_state.history, 1, 'F - test_undo_name_point/baseline/history:1')
-- enter 'name' mode without moving the mouse -- enter 'name' mode without moving the mouse
App.run_after_keychord('C-n') App.run_after_keychord('C-n')
App.run_after_textinput('A') App.run_after_textinput('A')
App.run_after_keychord('return') App.run_after_keychord('return')
check_eq(p2.name, 'A', 'F - test_undo_name_point/baseline') 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(#Editor_state.history, 3, 'F - test_undo_name_point/baseline/history:2')
check_eq(Next_history, 4, 'F - test_undo_name_point/baseline/next_history') check_eq(Editor_state.next_history, 4, 'F - test_undo_name_point/baseline/next_history')
-- undo -- undo
App.run_after_keychord('C-z') App.run_after_keychord('C-z')
local drawing = Lines[1] local drawing = Editor_state.lines[1]
local p2 = drawing.points[drawing.shapes[1].p2] local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(Next_history, 3, 'F - test_undo_name_point/next_history') check_eq(Editor_state.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 check_eq(p2.name, '', 'F - test_undo_name_point') -- not quite what it was before, but close enough
-- wait until save -- wait until save
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- undo is saved -- undo is saved
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
local p2 = Lines[1].points[drawing.shapes[1].p2] local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
check_eq(p2.name, '', 'F - test_undo_name_point/save') check_eq(p2.name, '', 'F - test_undo_name_point/save')
end end
function test_undo_move_point() function test_undo_move_point()
io.write('\ntest_undo_move_point') io.write('\ntest_undo_move_point')
-- create a drawing with a line -- create a drawing with a line
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 1, 'F - test_undo_move_point/baseline/#shapes') 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.points, 2, 'F - test_undo_move_point/baseline/#points')
check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_move_point/baseline/shape:1') check_eq(drawing.shapes[1].mode, 'line', 'F - test_undo_move_point/baseline/shape:1')
@ -668,28 +668,28 @@ function test_undo_move_point()
check_nil(p2.name, 'F - test_undo_move_point/baseline/p2:name') check_nil(p2.name, 'F - test_undo_move_point/baseline/p2:name')
-- move p2 -- move p2
App.run_after_keychord('C-u') App.run_after_keychord('C-u')
App.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44) App.mouse_move(Editor_state.margin_left+26, Editor_state.margin_top+Editor_state.drawing_padding_top+44)
App.update(0.05) App.update(0.05)
local p2 = drawing.points[drawing.shapes[1].p2] local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(p2.x, 26, 'F - test_undo_move_point/x') check_eq(p2.x, 26, 'F - test_undo_move_point/x')
check_eq(p2.y, 44, 'F - test_undo_move_point/y') check_eq(p2.y, 44, 'F - test_undo_move_point/y')
-- exit 'move' mode -- exit 'move' mode
App.run_after_mouse_click(Margin_left+26, Margin_top+Drawing_padding_top+44, 1) App.run_after_mouse_click(Editor_state.margin_left+26, Editor_state.margin_top+Editor_state.drawing_padding_top+44, 1)
check_eq(Next_history, 4, 'F - test_undo_move_point/next_history') check_eq(Editor_state.next_history, 4, 'F - test_undo_move_point/next_history')
-- undo -- undo
App.run_after_keychord('C-z') App.run_after_keychord('C-z')
App.run_after_keychord('C-z') -- bug: need to undo twice App.run_after_keychord('C-z') -- bug: need to undo twice
local drawing = Lines[1] local drawing = Editor_state.lines[1]
local p2 = drawing.points[drawing.shapes[1].p2] local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(Next_history, 2, 'F - test_undo_move_point/next_history') check_eq(Editor_state.next_history, 2, 'F - test_undo_move_point/next_history')
check_eq(p2.x, 35, 'F - test_undo_move_point/x') check_eq(p2.x, 35, 'F - test_undo_move_point/x')
check_eq(p2.y, 36, 'F - test_undo_move_point/y') check_eq(p2.y, 36, 'F - test_undo_move_point/y')
-- wait until save -- wait until save
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- undo is saved -- undo is saved
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
local p2 = Lines[1].points[drawing.shapes[1].p2] local p2 = Editor_state.lines[1].points[drawing.shapes[1].p2]
check_eq(p2.x, 35, 'F - test_undo_move_point/save/x') check_eq(p2.x, 35, 'F - test_undo_move_point/save/x')
check_eq(p2.y, 36, 'F - test_undo_move_point/save/y') check_eq(p2.y, 36, 'F - test_undo_move_point/save/y')
end end
@ -697,35 +697,35 @@ end
function test_undo_delete_point() function test_undo_delete_point()
io.write('\ntest_undo_delete_point') io.write('\ntest_undo_delete_point')
-- create a drawing with two lines connected at a point -- create a drawing with two lines connected at a point
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_width+256, height=300} -- drawing coordinates 1:1 with pixels App.screen.init{width=Editor_state.margin_width+256, height=300} -- drawing coordinates 1:1 with pixels
Lines = load_array{'```lines', '```', ''} Editor_state.lines = load_array{'```lines', '```', ''}
Current_drawing_mode = 'line' Editor_state.current_drawing_mode = 'line'
edit.draw() edit.draw()
App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1) App.run_after_mouse_press(Editor_state.margin_left+5, Editor_state.margin_top+Editor_state.drawing_padding_top+6, 1)
App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_release(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_press(Margin_left+35, Margin_top+Drawing_padding_top+36, 1) App.run_after_mouse_press(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36, 1)
App.run_after_mouse_release(Margin_left+55, Margin_top+Drawing_padding_top+26, 1) App.run_after_mouse_release(Editor_state.margin_left+55, Editor_state.margin_top+Editor_state.drawing_padding_top+26, 1)
local drawing = Lines[1] local drawing = Editor_state.lines[1]
check_eq(#drawing.shapes, 2, 'F - test_undo_delete_point/baseline/#shapes') 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[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') check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/baseline/shape:2')
-- hover on the common point and delete -- hover on the common point and delete
App.mouse_move(Margin_left+35, Margin_top+Drawing_padding_top+36) App.mouse_move(Editor_state.margin_left+35, Editor_state.margin_top+Editor_state.drawing_padding_top+36)
App.run_after_keychord('C-d') App.run_after_keychord('C-d')
check_eq(drawing.shapes[1].mode, 'deleted', 'F - test_undo_delete_point/shape:1') 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') check_eq(drawing.shapes[2].mode, 'deleted', 'F - test_undo_delete_point/shape:2')
-- undo -- undo
App.run_after_keychord('C-z') App.run_after_keychord('C-z')
local drawing = Lines[1] local drawing = Editor_state.lines[1]
local p2 = drawing.points[drawing.shapes[1].p2] local p2 = drawing.points[drawing.shapes[1].p2]
check_eq(Next_history, 3, 'F - test_undo_move_point/next_history') check_eq(Editor_state.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[1].mode, 'line', 'F - test_undo_delete_point/shape:1')
check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/shape:2') check_eq(drawing.shapes[2].mode, 'line', 'F - test_undo_delete_point/shape:2')
-- wait until save -- wait until save
App.wait_fake_time(3.1) App.wait_fake_time(3.1)
App.update(0) App.update(0)
-- undo is saved -- undo is saved
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
check_eq(#Lines[1].shapes, 2, 'F - test_undo_delete_point/save') check_eq(#Editor_state.lines[1].shapes, 2, 'F - test_undo_delete_point/save')
end end

386
edit.lua
View File

@ -22,100 +22,110 @@ require 'icons'
edit = {} edit = {}
-- run in both tests and a real run -- run in both tests and a real run
function edit.initialize_globals() function edit.initialize_state()
-- a line is either text or a drawing local result = {
-- a text is a table with: -- a line is either text or a drawing
-- mode = 'text', -- a text is a table with:
-- string data, -- mode = 'text',
-- startpos, the index of data the line starts rendering from (if currently on screen), can only be >1 for topmost line on screen -- string data,
-- starty, the y coord in pixels -- startpos, the index of data the line starts rendering from (if currently on screen), can only be >1 for topmost line on screen
-- some cached data that's blown away and recomputed when data changes: -- starty, the y coord in pixels
-- fragments: snippets of rendered love.graphics.Text, guaranteed to not wrap -- some cached data that's blown away and recomputed when data changes:
-- screen_line_starting_pos: optional array of grapheme indices if it wraps over more than one screen line -- fragments: snippets of rendered love.graphics.Text, guaranteed to not wrap
-- a drawing is a table with: -- screen_line_starting_pos: optional array of grapheme indices if it wraps over more than one screen line
-- mode = 'drawing' -- a drawing is a table with:
-- a (y) coord in pixels (updated while painting screen), -- mode = 'drawing'
-- a (h)eight, -- a (y) coord in pixels (updated while painting screen),
-- an array of points, and -- a (h)eight,
-- an array of shapes -- an array of points, and
-- a shape is a table containing: -- an array of shapes
-- a mode -- a shape is a table containing:
-- an array points for mode 'freehand' (raw x,y coords; freehand drawings don't pollute the points array of a drawing) -- a mode
-- an array vertices for mode 'polygon', 'rectangle', 'square' -- an array points for mode 'freehand' (raw x,y coords; freehand drawings don't pollute the points array of a drawing)
-- p1, p2 for mode 'line' -- an array vertices for mode 'polygon', 'rectangle', 'square'
-- center, radius for mode 'circle' -- p1, p2 for mode 'line'
-- center, radius, start_angle, end_angle for mode 'arc' -- center, radius for mode 'circle'
-- Unless otherwise specified, coord fields are normalized; a drawing is always 256 units wide -- center, radius, start_angle, end_angle for mode 'arc'
-- The field names are carefully chosen so that switching modes in midstream -- Unless otherwise specified, coord fields are normalized; a drawing is always 256 units wide
-- remembers previously entered points where that makes sense. -- The field names are carefully chosen so that switching modes in midstream
Lines = {{mode='text', data=''}} -- remembers previously entered points where that makes sense.
lines = {{mode='text', data=''}},
-- Lines can be too long to fit on screen, in which case they _wrap_ into -- Lines can be too long to fit on screen, in which case they _wrap_ into
-- multiple _screen lines_. -- multiple _screen lines_.
-- --
-- Therefore, any potential location for the cursor can be described in two ways: -- Therefore, any potential location for the cursor can be described in two ways:
-- * schema 1: As a combination of line index and position within a line (in utf8 codepoint units) -- * schema 1: As a combination of line index and position within a line (in utf8 codepoint units)
-- * schema 2: As a combination of line index, screen line index within the line, and a position within the screen line. -- * schema 2: As a combination of line index, screen line index within the line, and a position within the screen line.
-- --
-- Most of the time we'll only persist positions in schema 1, translating to -- Most of the time we'll only persist positions in schema 1, translating to
-- schema 2 when that's convenient. -- schema 2 when that's convenient.
-- --
-- Make sure these coordinates are never aliased, so that changing one causes -- Make sure these coordinates are never aliased, so that changing one causes
-- action at a distance. -- action at a distance.
Screen_top1 = {line=1, pos=1} -- position of start of screen line at top of screen screen_top1 = {line=1, pos=1}, -- position of start of screen line at top of screen
Cursor1 = {line=1, pos=1} -- position of cursor cursor1 = {line=1, pos=1}, -- position of cursor
Screen_bottom1 = {line=1, pos=1} -- position of start of screen line at bottom of screen screen_bottom1 = {line=1, pos=1}, -- position of start of screen line at bottom of screen
Selection1 = {} selection1 = {},
Old_cursor1, Old_selection1, Mousepress_shift = nil -- some extra state to compute selection between mouse press and release -- some extra state to compute selection between mouse press and release
Recent_mouse = {} -- when selecting text, avoid recomputing some state on every single frame old_cursor1 = nil,
old_selection1 = nil,
mousepress_shift = nil,
-- when selecting text, avoid recomputing some state on every single frame
recent_mouse = {},
Cursor_x, Cursor_y = 0, 0 -- in pixels -- cursor coordinates in pixels
cursor_x = 0,
cursor_y = 0,
Current_drawing_mode = 'line' current_drawing_mode = 'line',
Previous_drawing_mode = nil previous_drawing_mode = nil, -- extra state for some ephemeral modes like moving/deleting/naming points
-- values for tests -- these default values are important for tests
Font_height = 14 font_height = 14,
Line_height = 15 line_height = 15,
-- widest possible character width -- widest possible character width
Em = App.newText(love.graphics.getFont(), 'm') em = App.newText(love.graphics.getFont(), 'm'),
Margin_top = 15 margin_top = 15,
Margin_left = 25 margin_left = 25,
Margin_right = 25 margin_right = 25,
Margin_width = Margin_left + Margin_right margin_width = nil,
Drawing_padding_top = 10 drawing_padding_top = 10,
Drawing_padding_bottom = 10 drawing_padding_bottom = 10,
Drawing_padding_height = Drawing_padding_top + Drawing_padding_bottom drawing_padding_height = nil,
Filename = love.filesystem.getUserDirectory()..'/lines.txt' filename = love.filesystem.getUserDirectory()..'/lines.txt',
Next_save = nil next_save = nil,
-- undo -- undo
History = {} history = {},
Next_history = 1 next_history = 1,
-- search -- search
Search_term = nil search_term = nil,
Search_text = nil search_text = nil,
Search_backup = nil -- stuff to restore when cancelling search search_backup = nil, -- stuff to restore when cancelling search
}
end -- App.initialize_globals result.margin_width = result.margin_left + result.margin_right
result.drawing_padding_height = result.drawing_padding_top + result.drawing_padding_bottom
return result
end -- App.initialize_state
function edit.draw() function edit.draw()
App.color(Text_color) App.color(Text_color)
--? print(Screen_top1.line, Screen_top1.pos, Cursor1.line, Cursor1.pos) --? print(Editor_state.screen_top1.line, Editor_state.screen_top1.pos, Editor_state.cursor1.line, Editor_state.cursor1.pos)
assert(Text.le1(Screen_top1, Cursor1)) assert(Text.le1(Editor_state.screen_top1, Editor_state.cursor1))
Cursor_y = -1 Editor_state.cursor_y = -1
local y = Margin_top local y = Editor_state.margin_top
--? print('== draw') --? print('== draw')
for line_index = Screen_top1.line,#Lines do for line_index = Editor_state.screen_top1.line,#Editor_state.lines do
local line = Lines[line_index] local line = Editor_state.lines[line_index]
--? print('draw:', y, line_index, line) --? print('draw:', y, line_index, line)
if y + Line_height > App.screen.height then break end if y + Editor_state.line_height > App.screen.height then break end
Screen_bottom1.line = line_index Editor_state.screen_bottom1.line = line_index
if line.mode == 'text' and line.data == '' then if line.mode == 'text' and line.data == '' then
line.starty = y line.starty = y
line.startpos = 1 line.startpos = 1
@ -124,76 +134,76 @@ function edit.draw()
icon = icon.insert_drawing, icon = icon.insert_drawing,
onpress1 = function() onpress1 = function()
Drawing.before = snapshot(line_index-1, line_index) Drawing.before = snapshot(line_index-1, line_index)
table.insert(Lines, line_index, {mode='drawing', y=y, h=256/2, points={}, shapes={}, pending={}}) table.insert(Editor_state.lines, line_index, {mode='drawing', y=y, h=256/2, points={}, shapes={}, pending={}})
if Cursor1.line >= line_index then if Editor_state.cursor1.line >= line_index then
Cursor1.line = Cursor1.line+1 Editor_state.cursor1.line = Editor_state.cursor1.line+1
end end
schedule_save() schedule_save()
record_undo_event({before=Drawing.before, after=snapshot(line_index-1, line_index+1)}) record_undo_event({before=Drawing.before, after=snapshot(line_index-1, line_index+1)})
end end
}) })
if Search_term == nil then if Editor_state.search_term == nil then
if line_index == Cursor1.line then if line_index == Editor_state.cursor1.line then
Text.draw_cursor(Margin_left, y) Text.draw_cursor(Editor_state.margin_left, y)
end end
end end
Screen_bottom1.pos = Screen_top1.pos Editor_state.screen_bottom1.pos = Editor_state.screen_top1.pos
y = y + Line_height y = y + Editor_state.line_height
elseif line.mode == 'drawing' then elseif line.mode == 'drawing' then
y = y+Drawing_padding_top y = y+Editor_state.drawing_padding_top
line.y = y line.y = y
Drawing.draw(line) Drawing.draw(line)
y = y + Drawing.pixels(line.h) + Drawing_padding_bottom y = y + Drawing.pixels(line.h) + Editor_state.drawing_padding_bottom
else else
line.starty = y line.starty = y
line.startpos = 1 line.startpos = 1
if line_index == Screen_top1.line then if line_index == Editor_state.screen_top1.line then
line.startpos = Screen_top1.pos line.startpos = Editor_state.screen_top1.pos
end end
--? print('text.draw', y, line_index) --? print('text.draw', y, line_index)
y, Screen_bottom1.pos = Text.draw(line, line_index, line.starty, Margin_left, App.screen.width-Margin_right) y, Editor_state.screen_bottom1.pos = Text.draw(line, line_index, line.starty, Editor_state.margin_left, App.screen.width-Editor_state.margin_right)
y = y + Line_height y = y + Editor_state.line_height
--? print('=> y', y) --? print('=> y', y)
end end
end end
if Cursor_y == -1 then if Editor_state.cursor_y == -1 then
Cursor_y = App.screen.height Editor_state.cursor_y = App.screen.height
end end
--? print('screen bottom: '..tostring(Screen_bottom1.pos)..' in '..tostring(Lines[Screen_bottom1.line].data)) --? print('screen bottom: '..tostring(Editor_state.screen_bottom1.pos)..' in '..tostring(Editor_state.lines[Editor_state.screen_bottom1.line].data))
if Search_term then if Editor_state.search_term then
Text.draw_search_bar() Text.draw_search_bar()
end end
end end
function edit.update(dt) function edit.update(dt)
Drawing.update(dt) Drawing.update(dt)
if Next_save and Next_save < App.getTime() then if Editor_state.next_save and Editor_state.next_save < App.getTime() then
save_to_disk(Lines, Filename) save_to_disk(Editor_state.lines, Editor_state.filename)
Next_save = nil Editor_state.next_save = nil
end end
end end
function schedule_save() function schedule_save()
if Next_save == nil then if Editor_state.next_save == nil then
Next_save = App.getTime() + 3 -- short enough that you're likely to still remember what you did Editor_state.next_save = App.getTime() + 3 -- short enough that you're likely to still remember what you did
end end
end end
function edit.quit() function edit.quit()
-- make sure to save before quitting -- make sure to save before quitting
if Next_save then if Editor_state.next_save then
save_to_disk(Lines, Filename) save_to_disk(Editor_state.lines, Editor_state.filename)
end end
end end
function edit.mouse_pressed(x,y, mouse_button) function edit.mouse_pressed(x,y, mouse_button)
if Search_term then return end if Editor_state.search_term then return end
--? print('press', Selection1.line, Selection1.pos) --? print('press', Editor_state.selection1.line, Editor_state.selection1.pos)
propagate_to_button_handlers(x,y, mouse_button) propagate_to_button_handlers(x,y, mouse_button)
for line_index,line in ipairs(Lines) do for line_index,line in ipairs(Editor_state.lines) do
if line.mode == 'text' then if line.mode == 'text' then
if Text.in_line(line, x,y, Margin_left, App.screen.width-Margin_right) then if Text.in_line(line, x,y, Editor_state.margin_left, App.screen.width-Editor_state.margin_right) then
-- delicate dance between cursor, selection and old cursor/selection -- delicate dance between cursor, selection and old cursor/selection
-- scenarios: -- scenarios:
-- regular press+release: sets cursor, clears selection -- regular press+release: sets cursor, clears selection
@ -203,20 +213,20 @@ function edit.mouse_pressed(x,y, mouse_button)
-- press and hold to start a selection: sets selection on press, cursor on release -- press and hold to start a selection: sets selection on press, cursor on release
-- press and hold, then press shift: ignore shift -- press and hold, then press shift: ignore shift
-- i.e. mousereleased should never look at shift state -- i.e. mousereleased should never look at shift state
Old_cursor1 = Cursor1 Editor_state.old_cursor1 = Editor_state.cursor1
Old_selection1 = Selection1 Editor_state.old_selection1 = Editor_state.selection1
Mousepress_shift = App.shift_down() Editor_state.mousepress_shift = App.shift_down()
Selection1 = { Editor_state.selection1 = {
line=line_index, line=line_index,
pos=Text.to_pos_on_line(line, x, y, Margin_left, App.screen.width-Margin_right), pos=Text.to_pos_on_line(line, x, y, Editor_state.margin_left, App.screen.width-Editor_state.margin_right),
} }
--? print('selection', Selection1.line, Selection1.pos) --? print('selection', Editor_state.selection1.line, Editor_state.selection1.pos)
break break
end end
elseif line.mode == 'drawing' then elseif line.mode == 'drawing' then
if Drawing.in_drawing(line, x, y) then if Drawing.in_drawing(line, x, y) then
Lines.current_drawing_index = line_index Editor_state.lines.current_drawing_index = line_index
Lines.current_drawing = line Editor_state.lines.current_drawing = line
Drawing.before = snapshot(line_index) Drawing.before = snapshot(line_index)
Drawing.mouse_pressed(line, x,y, mouse_button) Drawing.mouse_pressed(line, x,y, mouse_button)
break break
@ -226,56 +236,56 @@ function edit.mouse_pressed(x,y, mouse_button)
end end
function edit.mouse_released(x,y, mouse_button) function edit.mouse_released(x,y, mouse_button)
if Search_term then return end if Editor_state.search_term then return end
--? print('release') --? print('release')
if Lines.current_drawing then if Editor_state.lines.current_drawing then
Drawing.mouse_released(x,y, mouse_button) Drawing.mouse_released(x,y, mouse_button)
schedule_save() schedule_save()
if Drawing.before then if Drawing.before then
record_undo_event({before=Drawing.before, after=snapshot(Lines.current_drawing_index)}) record_undo_event({before=Drawing.before, after=snapshot(Editor_state.lines.current_drawing_index)})
Drawing.before = nil Drawing.before = nil
end end
else else
for line_index,line in ipairs(Lines) do for line_index,line in ipairs(Editor_state.lines) do
if line.mode == 'text' then if line.mode == 'text' then
if Text.in_line(line, x,y, Margin_left, App.screen.width-Margin_right) then if Text.in_line(line, x,y, Editor_state.margin_left, App.screen.width-Editor_state.margin_right) then
--? print('reset selection') --? print('reset selection')
Cursor1 = { Editor_state.cursor1 = {
line=line_index, line=line_index,
pos=Text.to_pos_on_line(line, x, y, Margin_left, App.screen.width-Margin_right), pos=Text.to_pos_on_line(line, x, y, Editor_state.margin_left, App.screen.width-Editor_state.margin_right),
} }
--? print('cursor', Cursor1.line, Cursor1.pos) --? print('cursor', Editor_state.cursor1.line, Editor_state.cursor1.pos)
if Mousepress_shift then if Editor_state.mousepress_shift then
if Old_selection1.line == nil then if Editor_state.old_selection1.line == nil then
Selection1 = Old_cursor1 Editor_state.selection1 = Editor_state.old_cursor1
else else
Selection1 = Old_selection1 Editor_state.selection1 = Editor_state.old_selection1
end end
end end
Old_cursor1, Old_selection1, Mousepress_shift = nil Editor_state.old_cursor1, Editor_state.old_selection1, Editor_state.mousepress_shift = nil
if eq(Cursor1, Selection1) then if eq(Editor_state.cursor1, Editor_state.selection1) then
Selection1 = {} Editor_state.selection1 = {}
end end
break break
end end
end end
end end
--? print('selection:', Selection1.line, Selection1.pos) --? print('selection:', Editor_state.selection1.line, Editor_state.selection1.pos)
end end
end end
function edit.textinput(t) function edit.textinput(t)
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
if Search_term then if Editor_state.search_term then
Search_term = Search_term..t Editor_state.search_term = Editor_state.search_term..t
Search_text = nil Editor_state.search_text = nil
Text.search_next() Text.search_next()
elseif Current_drawing_mode == 'name' then elseif Editor_state.current_drawing_mode == 'name' then
local before = snapshot(Lines.current_drawing_index) local before = snapshot(Editor_state.lines.current_drawing_index)
local drawing = Lines.current_drawing local drawing = Editor_state.lines.current_drawing
local p = drawing.points[drawing.pending.target_point] local p = drawing.points[drawing.pending.target_point]
p.name = p.name..t p.name = p.name..t
record_undo_event({before=before, after=snapshot(Lines.current_drawing_index)}) record_undo_event({before=before, after=snapshot(Editor_state.lines.current_drawing_index)})
else else
Text.textinput(t) Text.textinput(t)
end end
@ -283,94 +293,94 @@ function edit.textinput(t)
end end
function edit.keychord_pressed(chord, key) function edit.keychord_pressed(chord, key)
if Selection1.line and if Editor_state.selection1.line and
not Lines.current_drawing and not Editor_state.lines.current_drawing and
-- printable character created using shift key => delete selection -- printable character created using shift key => delete selection
-- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys) -- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys)
(not App.shift_down() or utf8.len(key) == 1) and (not App.shift_down() or utf8.len(key) == 1) and
chord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and backspace ~= 'delete' and not App.is_cursor_movement(chord) then chord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and backspace ~= 'delete' and not App.is_cursor_movement(chord) then
Text.delete_selection(Margin_left, App.screen.width-Margin_right) Text.delete_selection(Editor_state.margin_left, App.screen.width-Editor_state.margin_right)
end end
if Search_term then if Editor_state.search_term then
if chord == 'escape' then if chord == 'escape' then
Search_term = nil Editor_state.search_term = nil
Search_text = nil Editor_state.search_text = nil
Cursor1 = Search_backup.cursor Editor_state.cursor1 = Editor_state.search_backup.cursor
Screen_top1 = Search_backup.screen_top Editor_state.screen_top1 = Editor_state.search_backup.screen_top
Search_backup = nil Editor_state.search_backup = nil
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
elseif chord == 'return' then elseif chord == 'return' then
Search_term = nil Editor_state.search_term = nil
Search_text = nil Editor_state.search_text = nil
Search_backup = nil Editor_state.search_backup = nil
elseif chord == 'backspace' then elseif chord == 'backspace' then
local len = utf8.len(Search_term) local len = utf8.len(Editor_state.search_term)
local byte_offset = Text.offset(Search_term, len) local byte_offset = Text.offset(Editor_state.search_term, len)
Search_term = string.sub(Search_term, 1, byte_offset-1) Editor_state.search_term = string.sub(Editor_state.search_term, 1, byte_offset-1)
Search_text = nil Editor_state.search_text = nil
elseif chord == 'down' then elseif chord == 'down' then
Cursor1.pos = Cursor1.pos+1 Editor_state.cursor1.pos = Editor_state.cursor1.pos+1
Text.search_next() Text.search_next()
elseif chord == 'up' then elseif chord == 'up' then
Text.search_previous() Text.search_previous()
end end
return return
elseif chord == 'C-f' then elseif chord == 'C-f' then
Search_term = '' Editor_state.search_term = ''
Search_backup = {cursor={line=Cursor1.line, pos=Cursor1.pos}, screen_top={line=Screen_top1.line, pos=Screen_top1.pos}} Editor_state.search_backup = {cursor={line=Editor_state.cursor1.line, pos=Editor_state.cursor1.pos}, screen_top={line=Editor_state.screen_top1.line, pos=Editor_state.screen_top1.pos}}
assert(Search_text == nil) assert(Editor_state.search_text == nil)
elseif chord == 'C-=' then elseif chord == 'C-=' then
initialize_font_settings(Font_height+2) initialize_font_settings(Editor_state.font_height+2)
Text.redraw_all() Text.redraw_all()
elseif chord == 'C--' then elseif chord == 'C--' then
initialize_font_settings(Font_height-2) initialize_font_settings(Editor_state.font_height-2)
Text.redraw_all() Text.redraw_all()
elseif chord == 'C-0' then elseif chord == 'C-0' then
initialize_font_settings(20) initialize_font_settings(20)
Text.redraw_all() Text.redraw_all()
elseif chord == 'C-z' then elseif chord == 'C-z' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
local event = undo_event() local event = undo_event()
if event then if event then
local src = event.before local src = event.before
Screen_top1 = deepcopy(src.screen_top) Editor_state.screen_top1 = deepcopy(src.screen_top)
Cursor1 = deepcopy(src.cursor) Editor_state.cursor1 = deepcopy(src.cursor)
Selection1 = deepcopy(src.selection) Editor_state.selection1 = deepcopy(src.selection)
patch(Lines, event.after, event.before) patch(Editor_state.lines, event.after, event.before)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
schedule_save() schedule_save()
end end
elseif chord == 'C-y' then elseif chord == 'C-y' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
local event = redo_event() local event = redo_event()
if event then if event then
local src = event.after local src = event.after
Screen_top1 = deepcopy(src.screen_top) Editor_state.screen_top1 = deepcopy(src.screen_top)
Cursor1 = deepcopy(src.cursor) Editor_state.cursor1 = deepcopy(src.cursor)
Selection1 = deepcopy(src.selection) Editor_state.selection1 = deepcopy(src.selection)
patch(Lines, event.before, event.after) patch(Editor_state.lines, event.before, event.after)
Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks Text.redraw_all() -- if we're scrolling, reclaim all fragments to avoid memory leaks
schedule_save() schedule_save()
end end
-- clipboard -- clipboard
elseif chord == 'C-c' then elseif chord == 'C-c' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
local s = Text.selection() local s = Text.selection()
if s then if s then
App.setClipboardText(s) App.setClipboardText(s)
end end
elseif chord == 'C-x' then elseif chord == 'C-x' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
local s = Text.cut_selection(Margin_left, App.screen.width-Margin_right) local s = Text.cut_selection(Editor_state.margin_left, App.screen.width-Editor_state.margin_right)
if s then if s then
App.setClipboardText(s) App.setClipboardText(s)
end end
schedule_save() schedule_save()
elseif chord == 'C-v' then elseif chord == 'C-v' then
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
-- We don't have a good sense of when to scroll, so we'll be conservative -- We don't have a good sense of when to scroll, so we'll be conservative
-- and sometimes scroll when we didn't quite need to. -- and sometimes scroll when we didn't quite need to.
local before_line = Cursor1.line local before_line = Editor_state.cursor1.line
local before = snapshot(before_line) local before = snapshot(before_line)
local clipboard_data = App.getClipboardText() local clipboard_data = App.getClipboardText()
for _,code in utf8.codes(clipboard_data) do for _,code in utf8.codes(clipboard_data) do
@ -382,10 +392,10 @@ function edit.keychord_pressed(chord, key)
end end
end end
if Text.cursor_past_screen_bottom() then if Text.cursor_past_screen_bottom() then
Text.snap_cursor_to_bottom_of_screen(Margin_left, App.screen.height-Margin_right) Text.snap_cursor_to_bottom_of_screen(Editor_state.margin_left, App.screen.height-Editor_state.margin_right)
end end
schedule_save() schedule_save()
record_undo_event({before=before, after=snapshot(before_line, Cursor1.line)}) record_undo_event({before=before, after=snapshot(before_line, Editor_state.cursor1.line)})
-- dispatch to drawing or text -- dispatch to drawing or text
elseif App.mouse_down(1) or chord:sub(1,2) == 'C-' then elseif App.mouse_down(1) or chord:sub(1,2) == 'C-' then
-- DON'T reset line.y here -- DON'T reset line.y here
@ -397,33 +407,33 @@ function edit.keychord_pressed(chord, key)
schedule_save() schedule_save()
end end
elseif chord == 'escape' and not App.mouse_down(1) then elseif chord == 'escape' and not App.mouse_down(1) then
for _,line in ipairs(Lines) do for _,line in ipairs(Editor_state.lines) do
if line.mode == 'drawing' then if line.mode == 'drawing' then
line.show_help = false line.show_help = false
end end
end end
elseif Current_drawing_mode == 'name' then elseif Editor_state.current_drawing_mode == 'name' then
if chord == 'return' then if chord == 'return' then
Current_drawing_mode = Previous_drawing_mode Editor_state.current_drawing_mode = Editor_state.previous_drawing_mode
Previous_drawing_mode = nil Editor_state.previous_drawing_mode = nil
else else
local before = snapshot(Lines.current_drawing_index) local before = snapshot(Editor_state.lines.current_drawing_index)
local drawing = Lines.current_drawing local drawing = Editor_state.lines.current_drawing
local p = drawing.points[drawing.pending.target_point] local p = drawing.points[drawing.pending.target_point]
if chord == 'escape' then if chord == 'escape' then
p.name = nil p.name = nil
record_undo_event({before=before, after=snapshot(Lines.current_drawing_index)}) record_undo_event({before=before, after=snapshot(Editor_state.lines.current_drawing_index)})
elseif chord == 'backspace' then elseif chord == 'backspace' then
local len = utf8.len(p.name) local len = utf8.len(p.name)
local byte_offset = Text.offset(p.name, len-1) local byte_offset = Text.offset(p.name, len-1)
if len == 1 then byte_offset = 0 end if len == 1 then byte_offset = 0 end
p.name = string.sub(p.name, 1, byte_offset) p.name = string.sub(p.name, 1, byte_offset)
record_undo_event({before=before, after=snapshot(Lines.current_drawing_index)}) record_undo_event({before=before, after=snapshot(Editor_state.lines.current_drawing_index)})
end end
end end
schedule_save() schedule_save()
else else
for _,line in ipairs(Lines) do line.y = nil end -- just in case we scroll for _,line in ipairs(Editor_state.lines) do line.y = nil end -- just in case we scroll
Text.keychord_pressed(chord) Text.keychord_pressed(chord)
end end
end end

200
help.lua
View File

@ -1,144 +1,144 @@
function draw_help_without_mouse_pressed(drawing) function draw_help_without_mouse_pressed(drawing)
App.color(Help_color) App.color(Help_color)
local y = drawing.y+10 local y = drawing.y+10
love.graphics.print("Things you can do:", Margin_left+30,y) love.graphics.print("Things you can do:", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Press the mouse button to start drawing a "..current_shape(), Margin_left+30,y) love.graphics.print("* Press the mouse button to start drawing a "..current_shape(), Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Hover on a point and press 'ctrl+u' to pick it up and start moving it,", Margin_left+30,y) love.graphics.print("* Hover on a point and press 'ctrl+u' to pick it up and start moving it,", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("then press the mouse button to drop it", Margin_left+30+bullet_indent(),y) love.graphics.print("then press the mouse button to drop it", Editor_state.margin_left+30+bullet_indent(),y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Hover on a point and press 'ctrl+n', type a name, then press 'enter'", Margin_left+30,y) love.graphics.print("* Hover on a point and press 'ctrl+n', type a name, then press 'enter'", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Hover on a point or shape and press 'ctrl+d' to delete it", Margin_left+30,y) love.graphics.print("* Hover on a point or shape and press 'ctrl+d' to delete it", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
if Current_drawing_mode ~= 'freehand' then if Editor_state.current_drawing_mode ~= 'freehand' then
love.graphics.print("* Press 'ctrl+p' to switch to drawing freehand strokes", Margin_left+30,y) love.graphics.print("* Press 'ctrl+p' to switch to drawing freehand strokes", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'line' then if Editor_state.current_drawing_mode ~= 'line' then
love.graphics.print("* Press 'ctrl+l' to switch to drawing lines", Margin_left+30,y) love.graphics.print("* Press 'ctrl+l' to switch to drawing lines", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'manhattan' then if Editor_state.current_drawing_mode ~= 'manhattan' then
love.graphics.print("* Press 'ctrl+m' to switch to drawing horizontal/vertical lines", Margin_left+30,y) love.graphics.print("* Press 'ctrl+m' to switch to drawing horizontal/vertical lines", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'circle' then if Editor_state.current_drawing_mode ~= 'circle' then
love.graphics.print("* Press 'ctrl+o' to switch to drawing circles/arcs", Margin_left+30,y) love.graphics.print("* Press 'ctrl+o' to switch to drawing circles/arcs", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'polygon' then if Editor_state.current_drawing_mode ~= 'polygon' then
love.graphics.print("* Press 'ctrl+g' to switch to drawing polygons", Margin_left+30,y) love.graphics.print("* Press 'ctrl+g' to switch to drawing polygons", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'rectangle' then if Editor_state.current_drawing_mode ~= 'rectangle' then
love.graphics.print("* Press 'ctrl+r' to switch to drawing rectangles", Margin_left+30,y) love.graphics.print("* Press 'ctrl+r' to switch to drawing rectangles", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'square' then if Editor_state.current_drawing_mode ~= 'square' then
love.graphics.print("* Press 'ctrl+s' to switch to drawing squares", Margin_left+30,y) love.graphics.print("* Press 'ctrl+s' to switch to drawing squares", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
love.graphics.print("* Press 'ctrl+=' or 'ctrl+-' to zoom in or out, ctrl+0 to reset zoom", Margin_left+30,y) love.graphics.print("* Press 'ctrl+=' or 'ctrl+-' to zoom in or out, ctrl+0 to reset zoom", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("Press 'esc' now to hide this message", Margin_left+30,y) love.graphics.print("Press 'esc' now to hide this message", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
App.color(Help_background_color) App.color(Help_background_color)
love.graphics.rectangle('fill', Margin_left,drawing.y, App.screen.width-Margin_width, math.max(Drawing.pixels(drawing.h),y-drawing.y)) love.graphics.rectangle('fill', Editor_state.margin_left,drawing.y, App.screen.width-Editor_state.margin_width, math.max(Drawing.pixels(drawing.h),y-drawing.y))
end end
function draw_help_with_mouse_pressed(drawing) function draw_help_with_mouse_pressed(drawing)
App.color(Help_color) App.color(Help_color)
local y = drawing.y+10 local y = drawing.y+10
love.graphics.print("You're currently drawing a "..current_shape(drawing.pending), Margin_left+30,y) love.graphics.print("You're currently drawing a "..current_shape(drawing.pending), Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print('Things you can do now:', Margin_left+30,y) love.graphics.print('Things you can do now:', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
if Current_drawing_mode == 'freehand' then if Editor_state.current_drawing_mode == 'freehand' then
love.graphics.print('* Release the mouse button to finish drawing the stroke', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the stroke', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
elseif Current_drawing_mode == 'line' or Current_drawing_mode == 'manhattan' then elseif Editor_state.current_drawing_mode == 'line' or Editor_state.current_drawing_mode == 'manhattan' then
love.graphics.print('* Release the mouse button to finish drawing the line', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the line', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
elseif Current_drawing_mode == 'circle' then elseif Editor_state.current_drawing_mode == 'circle' then
if drawing.pending.mode == 'circle' then if drawing.pending.mode == 'circle' then
love.graphics.print('* Release the mouse button to finish drawing the circle', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the circle', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Press 'a' to draw just an arc of a circle", Margin_left+30,y) love.graphics.print("* Press 'a' to draw just an arc of a circle", Editor_state.margin_left+30,y)
else else
love.graphics.print('* Release the mouse button to finish drawing the arc', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the arc', Editor_state.margin_left+30,y)
end end
y = y + Line_height y = y + Editor_state.line_height
elseif Current_drawing_mode == 'polygon' then elseif Editor_state.current_drawing_mode == 'polygon' then
love.graphics.print('* Release the mouse button to finish drawing the polygon', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the polygon', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Press 'p' to add a vertex to the polygon", Margin_left+30,y) love.graphics.print("* Press 'p' to add a vertex to the polygon", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
elseif Current_drawing_mode == 'rectangle' then elseif Editor_state.current_drawing_mode == 'rectangle' then
if #drawing.pending.vertices < 2 then if #drawing.pending.vertices < 2 then
love.graphics.print("* Press 'p' to add a vertex to the rectangle", Margin_left+30,y) love.graphics.print("* Press 'p' to add a vertex to the rectangle", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
else else
love.graphics.print('* Release the mouse button to finish drawing the rectangle', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the rectangle', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Press 'p' to replace the second vertex of the rectangle", Margin_left+30,y) love.graphics.print("* Press 'p' to replace the second vertex of the rectangle", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
elseif Current_drawing_mode == 'square' then elseif Editor_state.current_drawing_mode == 'square' then
if #drawing.pending.vertices < 2 then if #drawing.pending.vertices < 2 then
love.graphics.print("* Press 'p' to add a vertex to the square", Margin_left+30,y) love.graphics.print("* Press 'p' to add a vertex to the square", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
else else
love.graphics.print('* Release the mouse button to finish drawing the square', Margin_left+30,y) love.graphics.print('* Release the mouse button to finish drawing the square', Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
love.graphics.print("* Press 'p' to replace the second vertex of the square", Margin_left+30,y) love.graphics.print("* Press 'p' to replace the second vertex of the square", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
end end
love.graphics.print("* Press 'esc' then release the mouse button to cancel the current shape", Margin_left+30,y) love.graphics.print("* Press 'esc' then release the mouse button to cancel the current shape", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
y = y + Line_height y = y + Editor_state.line_height
if Current_drawing_mode ~= 'line' then if Editor_state.current_drawing_mode ~= 'line' then
love.graphics.print("* Press 'l' to switch to drawing lines", Margin_left+30,y) love.graphics.print("* Press 'l' to switch to drawing lines", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'manhattan' then if Editor_state.current_drawing_mode ~= 'manhattan' then
love.graphics.print("* Press 'm' to switch to drawing horizontal/vertical lines", Margin_left+30,y) love.graphics.print("* Press 'm' to switch to drawing horizontal/vertical lines", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'circle' then if Editor_state.current_drawing_mode ~= 'circle' then
love.graphics.print("* Press 'o' to switch to drawing circles/arcs", Margin_left+30,y) love.graphics.print("* Press 'o' to switch to drawing circles/arcs", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'polygon' then if Editor_state.current_drawing_mode ~= 'polygon' then
love.graphics.print("* Press 'g' to switch to drawing polygons", Margin_left+30,y) love.graphics.print("* Press 'g' to switch to drawing polygons", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'rectangle' then if Editor_state.current_drawing_mode ~= 'rectangle' then
love.graphics.print("* Press 'r' to switch to drawing rectangles", Margin_left+30,y) love.graphics.print("* Press 'r' to switch to drawing rectangles", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
if Current_drawing_mode ~= 'square' then if Editor_state.current_drawing_mode ~= 'square' then
love.graphics.print("* Press 's' to switch to drawing squares", Margin_left+30,y) love.graphics.print("* Press 's' to switch to drawing squares", Editor_state.margin_left+30,y)
y = y + Line_height y = y + Editor_state.line_height
end end
App.color(Help_background_color) App.color(Help_background_color)
love.graphics.rectangle('fill', Margin_left,drawing.y, App.screen.width-Margin_width, math.max(Drawing.pixels(drawing.h),y-drawing.y)) love.graphics.rectangle('fill', Editor_state.margin_left,drawing.y, App.screen.width-Editor_state.margin_width, math.max(Drawing.pixels(drawing.h),y-drawing.y))
end end
function current_shape(shape) function current_shape(shape)
if Current_drawing_mode == 'freehand' then if Editor_state.current_drawing_mode == 'freehand' then
return 'freehand stroke' return 'freehand stroke'
elseif Current_drawing_mode == 'line' then elseif Editor_state.current_drawing_mode == 'line' then
return 'straight line' return 'straight line'
elseif Current_drawing_mode == 'manhattan' then elseif Editor_state.current_drawing_mode == 'manhattan' then
return 'horizontal/vertical line' return 'horizontal/vertical line'
elseif Current_drawing_mode == 'circle' and shape and shape.start_angle then elseif Editor_state.current_drawing_mode == 'circle' and shape and shape.start_angle then
return 'arc' return 'arc'
else else
return Current_drawing_mode return Editor_state.current_drawing_mode
end end
end end

View File

@ -14,7 +14,7 @@ Editor_state = {}
-- called both in tests and real run -- called both in tests and real run
function App.initialize_globals() function App.initialize_globals()
edit.initialize_globals() Editor_state = edit.initialize_state()
-- resize -- resize
Last_resize_time = nil Last_resize_time = nil
@ -37,28 +37,28 @@ function App.initialize(arg)
end end
if #arg > 0 then if #arg > 0 then
Filename = arg[1] Editor_state.filename = arg[1]
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
Screen_top1 = {line=1, pos=1} Editor_state.screen_top1 = {line=1, pos=1}
Cursor1 = {line=1, pos=1} Editor_state.cursor1 = {line=1, pos=1}
for i,line in ipairs(Lines) do for i,line in ipairs(Editor_state.lines) do
if line.mode == 'text' then if line.mode == 'text' then
Cursor1.line = i Editor_state.cursor1.line = i
break break
end end
end end
else else
Lines = load_from_disk(Filename) Editor_state.lines = load_from_disk(Editor_state.filename)
if Cursor1.line > #Lines or Lines[Cursor1.line].mode ~= 'text' then if Editor_state.cursor1.line > #Editor_state.lines or Editor_state.lines[Editor_state.cursor1.line].mode ~= 'text' then
for i,line in ipairs(Lines) do for i,line in ipairs(Editor_state.lines) do
if line.mode == 'text' then if line.mode == 'text' then
Cursor1.line = i Editor_state.cursor1.line = i
break break
end end
end end
end end
end end
love.window.setTitle('lines.love - '..Filename) love.window.setTitle('lines.love - '..Editor_state.filename)
if #arg > 1 then if #arg > 1 then
print('ignoring commandline args after '..arg[1]) print('ignoring commandline args after '..arg[1])
@ -83,10 +83,10 @@ function load_settings()
App.screen.flags.minheight = math.min(App.screen.width, 200) App.screen.flags.minheight = math.min(App.screen.width, 200)
App.screen.width, App.screen.height = settings.width, settings.height App.screen.width, App.screen.height = settings.width, settings.height
love.window.setMode(App.screen.width, App.screen.height, App.screen.flags) love.window.setMode(App.screen.width, App.screen.height, App.screen.flags)
Filename = settings.filename Editor_state.filename = settings.filename
initialize_font_settings(settings.font_height) initialize_font_settings(settings.font_height)
Screen_top1 = settings.screen_top Editor_state.screen_top1 = settings.screen_top
Cursor1 = settings.cursor Editor_state.cursor1 = settings.cursor
end end
function load_defaults() function load_defaults()
@ -99,7 +99,7 @@ function initialize_window_geometry()
love.window.setMode(0, 0) -- maximize love.window.setMode(0, 0) -- maximize
App.screen.width, App.screen.height, App.screen.flags = love.window.getMode() App.screen.width, App.screen.height, App.screen.flags = love.window.getMode()
-- shrink slightly to account for window decoration -- shrink slightly to account for window decoration
App.screen.width = 40*App.width(Em) App.screen.width = 40*App.width(Editor_state.em)
App.screen.height = App.screen.height-100 App.screen.height = App.screen.height-100
App.screen.flags.resizable = true App.screen.flags.resizable = true
App.screen.flags.minwidth = math.min(App.screen.width, 200) App.screen.flags.minwidth = math.min(App.screen.width, 200)
@ -111,37 +111,37 @@ function App.resize(w, h)
--? print(("Window resized to width: %d and height: %d."):format(w, h)) --? print(("Window resized to width: %d and height: %d."):format(w, h))
App.screen.width, App.screen.height = w, h App.screen.width, App.screen.height = w, h
Text.redraw_all() Text.redraw_all()
Selection1 = {} -- no support for shift drag while we're resizing Editor_state.selection1 = {} -- no support for shift drag while we're resizing
Text.tweak_screen_top_and_cursor(Margin_left, App.screen.height-Margin_right) Text.tweak_screen_top_and_cursor(Editor_state.margin_left, App.screen.height-Editor_state.margin_right)
Last_resize_time = App.getTime() Last_resize_time = App.getTime()
end end
function initialize_font_settings(font_height) function initialize_font_settings(font_height)
Font_height = font_height Editor_state.font_height = font_height
love.graphics.setFont(love.graphics.newFont(Font_height)) love.graphics.setFont(love.graphics.newFont(Editor_state.font_height))
Line_height = math.floor(font_height*1.3) Editor_state.line_height = math.floor(font_height*1.3)
Em = App.newText(love.graphics.getFont(), 'm') Editor_state.em = App.newText(love.graphics.getFont(), 'm')
end end
function App.filedropped(file) function App.filedropped(file)
-- first make sure to save edits on any existing file -- first make sure to save edits on any existing file
if Next_save then if Editor_state.next_save then
save_to_disk(Lines, Filename) save_to_disk(Editor_state.lines, Editor_state.filename)
end end
-- clear the slate for the new file -- clear the slate for the new file
App.initialize_globals() -- in particular, forget all undo history App.initialize_globals() -- in particular, forget all undo history
Filename = file:getFilename() Editor_state.filename = file:getFilename()
file:open('r') file:open('r')
Lines = load_from_file(file) Editor_state.lines = load_from_file(file)
file:close() file:close()
for i,line in ipairs(Lines) do for i,line in ipairs(Editor_state.lines) do
if line.mode == 'text' then if line.mode == 'text' then
Cursor1.line = i Editor_state.cursor1.line = i
break break
end end
end end
love.window.setTitle('Text with Lines - '..Filename) love.window.setTitle('Text with Editor_state.lines - '..Editor_state.filename)
end end
function App.draw() function App.draw()
@ -166,16 +166,16 @@ function love.quit()
edit.quit() edit.quit()
-- save some important settings -- save some important settings
local x,y,displayindex = love.window.getPosition() local x,y,displayindex = love.window.getPosition()
local filename = Filename local filename = Editor_state.filename
if filename:sub(1,1) ~= '/' then if filename:sub(1,1) ~= '/' then
filename = love.filesystem.getWorkingDirectory()..'/'..filename -- '/' should work even on Windows filename = love.filesystem.getWorkingDirectory()..'/'..filename -- '/' should work even on Windows
end end
local settings = { local settings = {
x=x, y=y, displayindex=displayindex, x=x, y=y, displayindex=displayindex,
width=App.screen.width, height=App.screen.height, width=App.screen.width, height=App.screen.height,
font_height=Font_height, font_height=Editor_state.font_height,
filename=filename, filename=filename,
screen_top=Screen_top1, cursor=Cursor1} screen_top=Editor_state.screen_top1, cursor=Editor_state.cursor1}
love.filesystem.write('config', json.encode(settings)) love.filesystem.write('config', json.encode(settings))
end end

View File

@ -1,8 +1,8 @@
function test_resize_window() function test_resize_window()
io.write('\ntest_resize_window') io.write('\ntest_resize_window')
Filename = 'foo' Editor_state.filename = 'foo'
App.screen.init{width=Margin_left+300, height=300} App.screen.init{width=Editor_state.margin_left+300, height=300}
check_eq(App.screen.width, Margin_left+300, 'F - test_resize_window/baseline/width') check_eq(App.screen.width, Editor_state.margin_left+300, 'F - test_resize_window/baseline/width')
check_eq(App.screen.height, 300, 'F - test_resize_window/baseline/height') check_eq(App.screen.height, 300, 'F - test_resize_window/baseline/height')
App.resize(200, 400) App.resize(200, 400)
check_eq(App.screen.width, 200, 'F - test_resize_window/width') check_eq(App.screen.width, 200, 'F - test_resize_window/width')
@ -12,7 +12,7 @@ end
function test_drop_file() function test_drop_file()
io.write('\ntest_drop_file') io.write('\ntest_drop_file')
App.screen.init{width=Margin_left+300, height=300} App.screen.init{width=Editor_state.margin_left+300, height=300}
App.filesystem['foo'] = 'abc\ndef\nghi\n' App.filesystem['foo'] = 'abc\ndef\nghi\n'
local fake_dropped_file = { local fake_dropped_file = {
opened = false, opened = false,
@ -31,18 +31,18 @@ function test_drop_file()
end, end,
} }
App.filedropped(fake_dropped_file) App.filedropped(fake_dropped_file)
check_eq(#Lines, 3, 'F - test_drop_file/#lines') check_eq(#Editor_state.lines, 3, 'F - test_drop_file/#lines')
check_eq(Lines[1].data, 'abc', 'F - test_drop_file/lines:1') check_eq(Editor_state.lines[1].data, 'abc', 'F - test_drop_file/lines:1')
check_eq(Lines[2].data, 'def', 'F - test_drop_file/lines:2') check_eq(Editor_state.lines[2].data, 'def', 'F - test_drop_file/lines:2')
check_eq(Lines[3].data, 'ghi', 'F - test_drop_file/lines:3') check_eq(Editor_state.lines[3].data, 'ghi', 'F - test_drop_file/lines:3')
end end
function test_drop_file_saves_previous() function test_drop_file_saves_previous()
io.write('\ntest_drop_file_saves_previous') io.write('\ntest_drop_file_saves_previous')
App.screen.init{width=Margin_left+300, height=300} App.screen.init{width=Editor_state.margin_left+300, height=300}
-- initially editing a file called foo that hasn't been saved to filesystem yet -- initially editing a file called foo that hasn't been saved to filesystem yet
Lines = load_array{'abc', 'def'} Editor_state.lines = load_array{'abc', 'def'}
Filename = 'foo' Editor_state.filename = 'foo'
schedule_save() schedule_save()
-- now drag a new file bar from the filesystem -- now drag a new file bar from the filesystem
App.filesystem['bar'] = 'abc\ndef\nghi\n' App.filesystem['bar'] = 'abc\ndef\nghi\n'

View File

@ -1,7 +1,7 @@
-- helpers for the search bar (C-f) -- helpers for the search bar (C-f)
function Text.draw_search_bar() function Text.draw_search_bar()
local h = Line_height+2 local h = Editor_state.line_height+2
local y = App.screen.height-h local y = App.screen.height-h
love.graphics.setColor(0.9,0.9,0.9) love.graphics.setColor(0.9,0.9,0.9)
love.graphics.rectangle('fill', 0, y-10, App.screen.width-1, h+8) love.graphics.rectangle('fill', 0, y-10, App.screen.width-1, h+8)
@ -12,92 +12,92 @@ function Text.draw_search_bar()
love.graphics.setColor(0.6,0.6,0.6) love.graphics.setColor(0.6,0.6,0.6)
love.graphics.rectangle('line', 20, y-6, App.screen.width-40, h+2, 2,2) love.graphics.rectangle('line', 20, y-6, App.screen.width-40, h+2, 2,2)
App.color(Text_color) App.color(Text_color)
App.screen.print(Search_term, 25,y-5) App.screen.print(Editor_state.search_term, 25,y-5)
App.color(Cursor_color) App.color(Cursor_color)
if Search_text == nil then if Editor_state.search_text == nil then
Search_text = App.newText(love.graphics.getFont(), Search_term) Editor_state.search_text = App.newText(love.graphics.getFont(), Editor_state.search_term)
end end
love.graphics.circle('fill', 25+App.width(Search_text),y-5+h, 2) love.graphics.circle('fill', 25+App.width(Editor_state.search_text),y-5+h, 2)
App.color(Text_color) App.color(Text_color)
end end
function Text.search_next() function Text.search_next()
-- search current line -- search current line
local pos = Lines[Cursor1.line].data:find(Search_term, Cursor1.pos) local pos = Editor_state.lines[Editor_state.cursor1.line].data:find(Editor_state.search_term, Editor_state.cursor1.pos)
if pos then if pos then
Cursor1.pos = pos Editor_state.cursor1.pos = pos
end end
if pos == nil then if pos == nil then
for i=Cursor1.line+1,#Lines do for i=Editor_state.cursor1.line+1,#Editor_state.lines do
pos = Lines[i].data:find(Search_term) pos = Editor_state.lines[i].data:find(Editor_state.search_term)
if pos then if pos then
Cursor1.line = i Editor_state.cursor1.line = i
Cursor1.pos = pos Editor_state.cursor1.pos = pos
break break
end end
end end
end end
if pos == nil then if pos == nil then
-- wrap around -- wrap around
for i=1,Cursor1.line-1 do for i=1,Editor_state.cursor1.line-1 do
pos = Lines[i].data:find(Search_term) pos = Editor_state.lines[i].data:find(Editor_state.search_term)
if pos then if pos then
Cursor1.line = i Editor_state.cursor1.line = i
Cursor1.pos = pos Editor_state.cursor1.pos = pos
break break
end end
end end
end end
if pos == nil then if pos == nil then
Cursor1.line = Search_backup.cursor.line Editor_state.cursor1.line = Editor_state.search_backup.cursor.line
Cursor1.pos = Search_backup.cursor.pos Editor_state.cursor1.pos = Editor_state.search_backup.cursor.pos
Screen_top1.line = Search_backup.screen_top.line Editor_state.screen_top1.line = Editor_state.search_backup.screen_top.line
Screen_top1.pos = Search_backup.screen_top.pos Editor_state.screen_top1.pos = Editor_state.search_backup.screen_top.pos
end end
if Text.lt1(Cursor1, Screen_top1) or Text.lt1(Screen_bottom1, Cursor1) then if Text.lt1(Editor_state.cursor1, Editor_state.screen_top1) or Text.lt1(Editor_state.screen_bottom1, Editor_state.cursor1) then
Screen_top1.line = Cursor1.line Editor_state.screen_top1.line = Editor_state.cursor1.line
local _, pos = Text.pos_at_start_of_cursor_screen_line(Margin_left, App.screen.width-Margin_right) local _, pos = Text.pos_at_start_of_cursor_screen_line(Editor_state.margin_left, App.screen.width-Editor_state.margin_right)
Screen_top1.pos = pos Editor_state.screen_top1.pos = pos
end end
end end
function Text.search_previous() function Text.search_previous()
-- search current line -- search current line
local pos = rfind(Lines[Cursor1.line].data, Search_term, Cursor1.pos) local pos = rfind(Editor_state.lines[Editor_state.cursor1.line].data, Editor_state.search_term, Editor_state.cursor1.pos)
if pos then if pos then
Cursor1.pos = pos Editor_state.cursor1.pos = pos
end end
if pos == nil then if pos == nil then
for i=Cursor1.line-1,1,-1 do for i=Editor_state.cursor1.line-1,1,-1 do
pos = rfind(Lines[i].data, Search_term) pos = rfind(Editor_state.lines[i].data, Editor_state.search_term)
if pos then if pos then
Cursor1.line = i Editor_state.cursor1.line = i
Cursor1.pos = pos Editor_state.cursor1.pos = pos
break break
end end
end end
end end
if pos == nil then if pos == nil then
-- wrap around -- wrap around
for i=#Lines,Cursor1.line+1,-1 do for i=#Editor_state.lines,Editor_state.cursor1.line+1,-1 do
pos = rfind(Lines[i].data, Search_term) pos = rfind(Editor_state.lines[i].data, Editor_state.search_term)
if pos then if pos then
Cursor1.line = i Editor_state.cursor1.line = i
Cursor1.pos = pos Editor_state.cursor1.pos = pos
break break
end end
end end
end end
if pos == nil then if pos == nil then
Cursor1.line = Search_backup.cursor.line Editor_state.cursor1.line = Editor_state.search_backup.cursor.line
Cursor1.pos = Search_backup.cursor.pos Editor_state.cursor1.pos = Editor_state.search_backup.cursor.pos
Screen_top1.line = Search_backup.screen_top.line Editor_state.screen_top1.line = Editor_state.search_backup.screen_top.line
Screen_top1.pos = Search_backup.screen_top.pos Editor_state.screen_top1.pos = Editor_state.search_backup.screen_top.pos
end end
if Text.lt1(Cursor1, Screen_top1) or Text.lt1(Screen_bottom1, Cursor1) then if Text.lt1(Editor_state.cursor1, Editor_state.screen_top1) or Text.lt1(Editor_state.screen_bottom1, Editor_state.cursor1) then
Screen_top1.line = Cursor1.line Editor_state.screen_top1.line = Editor_state.cursor1.line
local _, pos = Text.pos_at_start_of_cursor_screen_line(Margin_left, App.screen.width-Margin_right) local _, pos = Text.pos_at_start_of_cursor_screen_line(Editor_state.margin_left, App.screen.width-Editor_state.margin_right)
Screen_top1.pos = pos Editor_state.screen_top1.pos = pos
end end
end end

View File

@ -1,20 +1,20 @@
-- helpers for selecting portions of text -- helpers for selecting portions of text
-- Return any intersection of the region from Selection1 to Cursor1 (or -- Return any intersection of the region from Editor_state.selection1 to Editor_state.cursor1 (or
-- current mouse, if mouse is pressed; or recent mouse if mouse is pressed and -- current mouse, if mouse is pressed; or recent mouse if mouse is pressed and
-- currently over a drawing) with the region between {line=line_index, pos=apos} -- currently over a drawing) with the region between {line=line_index, pos=apos}
-- and {line=line_index, pos=bpos}. -- and {line=line_index, pos=bpos}.
-- apos must be less than bpos. However Selection1 and Cursor1 can be in any order. -- apos must be less than bpos. However Editor_state.selection1 and Editor_state.cursor1 can be in any order.
-- Result: positions spos,epos between apos,bpos. -- Result: positions spos,epos between apos,bpos.
function Text.clip_selection(line_index, apos, bpos, left, right) function Text.clip_selection(line_index, apos, bpos, left, right)
if Selection1.line == nil then return nil,nil end if Editor_state.selection1.line == nil then return nil,nil end
-- min,max = sorted(Selection1,Cursor1) -- min,max = sorted(Editor_state.selection1,Editor_state.cursor1)
local minl,minp = Selection1.line,Selection1.pos local minl,minp = Editor_state.selection1.line,Editor_state.selection1.pos
local maxl,maxp local maxl,maxp
if App.mouse_down(1) then if App.mouse_down(1) then
maxl,maxp = Text.mouse_pos(left, right) maxl,maxp = Text.mouse_pos(left, right)
else else
maxl,maxp = Cursor1.line,Cursor1.pos maxl,maxp = Editor_state.cursor1.line,Editor_state.cursor1.pos
end end
if minl > maxl then if minl > maxl then
minl,maxl = maxl,minl minl,maxl = maxl,minl
@ -69,7 +69,7 @@ function Text.draw_highlight(line, x,y, pos, lo,hi)
local text = App.newText(love.graphics.getFont(), s) local text = App.newText(love.graphics.getFont(), s)
local text_width = App.width(text) local text_width = App.width(text)
App.color(Highlight_color) App.color(Highlight_color)
love.graphics.rectangle('fill', x+lo_px,y, text_width,Line_height) love.graphics.rectangle('fill', x+lo_px,y, text_width,Editor_state.line_height)
App.color(Text_color) App.color(Text_color)
return lo_px return lo_px
end end
@ -78,20 +78,20 @@ end
-- inefficient for some reason, so don't do it on every frame -- inefficient for some reason, so don't do it on every frame
function Text.mouse_pos(left, right) function Text.mouse_pos(left, right)
local time = love.timer.getTime() local time = love.timer.getTime()
if Recent_mouse.time and Recent_mouse.time > time-0.1 then if Editor_state.recent_mouse.time and Editor_state.recent_mouse.time > time-0.1 then
return Recent_mouse.line, Recent_mouse.pos return Editor_state.recent_mouse.line, Editor_state.recent_mouse.pos
end end
Recent_mouse.time = time Editor_state.recent_mouse.time = time
local line,pos = Text.to_pos(App.mouse_x(), App.mouse_y(), left, right) local line,pos = Text.to_pos(App.mouse_x(), App.mouse_y(), left, right)
if line then if line then
Recent_mouse.line = line Editor_state.recent_mouse.line = line
Recent_mouse.pos = pos Editor_state.recent_mouse.pos = pos
end end
return Recent_mouse.line, Recent_mouse.pos return Editor_state.recent_mouse.line, Editor_state.recent_mouse.pos
end end
function Text.to_pos(x,y, left, right) function Text.to_pos(x,y, left, right)
for line_index,line in ipairs(Lines) do for line_index,line in ipairs(Editor_state.lines) do
if line.mode == 'text' then if line.mode == 'text' then
if Text.in_line(line, x,y, left, right) then if Text.in_line(line, x,y, left, right) then
return line_index, Text.to_pos_on_line(line, x,y, left, right) return line_index, Text.to_pos_on_line(line, x,y, left, right)
@ -101,25 +101,25 @@ function Text.to_pos(x,y, left, right)
end end
function Text.cut_selection(left, right) function Text.cut_selection(left, right)
if Selection1.line == nil then return end if Editor_state.selection1.line == nil then return end
local result = Text.selection() local result = Text.selection()
Text.delete_selection(left, right) Text.delete_selection(left, right)
return result return result
end end
function Text.delete_selection(left, right) function Text.delete_selection(left, right)
if Selection1.line == nil then return end if Editor_state.selection1.line == nil then return end
local minl,maxl = minmax(Selection1.line, Cursor1.line) local minl,maxl = minmax(Editor_state.selection1.line, Editor_state.cursor1.line)
local before = snapshot(minl, maxl) local before = snapshot(minl, maxl)
Text.delete_selection_without_undo(left, right) Text.delete_selection_without_undo(left, right)
record_undo_event({before=before, after=snapshot(Cursor1.line)}) record_undo_event({before=before, after=snapshot(Editor_state.cursor1.line)})
end end
function Text.delete_selection_without_undo(left, right) function Text.delete_selection_without_undo(left, right)
if Selection1.line == nil then return end if Editor_state.selection1.line == nil then return end
-- min,max = sorted(Selection1,Cursor1) -- min,max = sorted(Editor_state.selection1,Editor_state.cursor1)
local minl,minp = Selection1.line,Selection1.pos local minl,minp = Editor_state.selection1.line,Editor_state.selection1.pos
local maxl,maxp = Cursor1.line,Cursor1.pos local maxl,maxp = Editor_state.cursor1.line,Editor_state.cursor1.pos
if minl > maxl then if minl > maxl then
minl,maxl = maxl,minl minl,maxl = maxl,minl
minp,maxp = maxp,minp minp,maxp = maxp,minp
@ -128,36 +128,36 @@ function Text.delete_selection_without_undo(left, right)
minp,maxp = maxp,minp minp,maxp = maxp,minp
end end
end end
-- update Cursor1 and Selection1 -- update Editor_state.cursor1 and Editor_state.selection1
Cursor1.line = minl Editor_state.cursor1.line = minl
Cursor1.pos = minp Editor_state.cursor1.pos = minp
if Text.lt1(Cursor1, Screen_top1) then if Text.lt1(Editor_state.cursor1, Editor_state.screen_top1) then
Screen_top1.line = Cursor1.line Editor_state.screen_top1.line = Editor_state.cursor1.line
_,Screen_top1.pos = Text.pos_at_start_of_cursor_screen_line(left, right) _,Editor_state.screen_top1.pos = Text.pos_at_start_of_cursor_screen_line(left, right)
end end
Selection1 = {} Editor_state.selection1 = {}
-- delete everything between min (inclusive) and max (exclusive) -- delete everything between min (inclusive) and max (exclusive)
Text.clear_cache(Lines[minl]) Text.clear_cache(Editor_state.lines[minl])
local min_offset = Text.offset(Lines[minl].data, minp) local min_offset = Text.offset(Editor_state.lines[minl].data, minp)
local max_offset = Text.offset(Lines[maxl].data, maxp) local max_offset = Text.offset(Editor_state.lines[maxl].data, maxp)
if minl == maxl then if minl == maxl then
--? print('minl == maxl') --? print('minl == maxl')
Lines[minl].data = Lines[minl].data:sub(1, min_offset-1)..Lines[minl].data:sub(max_offset) Editor_state.lines[minl].data = Editor_state.lines[minl].data:sub(1, min_offset-1)..Editor_state.lines[minl].data:sub(max_offset)
return return
end end
assert(minl < maxl) assert(minl < maxl)
local rhs = Lines[maxl].data:sub(max_offset) local rhs = Editor_state.lines[maxl].data:sub(max_offset)
for i=maxl,minl+1,-1 do for i=maxl,minl+1,-1 do
table.remove(Lines, i) table.remove(Editor_state.lines, i)
end end
Lines[minl].data = Lines[minl].data:sub(1, min_offset-1)..rhs Editor_state.lines[minl].data = Editor_state.lines[minl].data:sub(1, min_offset-1)..rhs
end end
function Text.selection() function Text.selection()
if Selection1.line == nil then return end if Editor_state.selection1.line == nil then return end
-- min,max = sorted(Selection1,Cursor1) -- min,max = sorted(Editor_state.selection1,Editor_state.cursor1)
local minl,minp = Selection1.line,Selection1.pos local minl,minp = Editor_state.selection1.line,Editor_state.selection1.pos
local maxl,maxp = Cursor1.line,Cursor1.pos local maxl,maxp = Editor_state.cursor1.line,Editor_state.cursor1.pos
if minl > maxl then if minl > maxl then
minl,maxl = maxl,minl minl,maxl = maxl,minl
minp,maxp = maxp,minp minp,maxp = maxp,minp
@ -166,18 +166,18 @@ function Text.selection()
minp,maxp = maxp,minp minp,maxp = maxp,minp
end end
end end
local min_offset = Text.offset(Lines[minl].data, minp) local min_offset = Text.offset(Editor_state.lines[minl].data, minp)
local max_offset = Text.offset(Lines[maxl].data, maxp) local max_offset = Text.offset(Editor_state.lines[maxl].data, maxp)
if minl == maxl then if minl == maxl then
return Lines[minl].data:sub(min_offset, max_offset-1) return Editor_state.lines[minl].data:sub(min_offset, max_offset-1)
end end
assert(minl < maxl) assert(minl < maxl)
local result = {Lines[minl].data:sub(min_offset)} local result = {Editor_state.lines[minl].data:sub(min_offset)}
for i=minl+1,maxl-1 do for i=minl+1,maxl-1 do
if Lines[i].mode == 'text' then if Editor_state.lines[i].mode == 'text' then
table.insert(result, Lines[i].data) table.insert(result, Editor_state.lines[i].data)
end end
end end
table.insert(result, Lines[maxl].data:sub(1, max_offset-1)) table.insert(result, Editor_state.lines[maxl].data:sub(1, max_offset-1))
return table.concat(result, '\n') return table.concat(result, '\n')
end end

598
text.lua

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,27 +7,27 @@
-- TODO: coalesce multiple similar operations -- TODO: coalesce multiple similar operations
function record_undo_event(data) function record_undo_event(data)
History[Next_history] = data Editor_state.history[Editor_state.next_history] = data
Next_history = Next_history+1 Editor_state.next_history = Editor_state.next_history+1
for i=Next_history,#History do for i=Editor_state.next_history,#Editor_state.history do
History[i] = nil Editor_state.history[i] = nil
end end
end end
function undo_event() function undo_event()
if Next_history > 1 then if Editor_state.next_history > 1 then
--? print('moving to history', Next_history-1) --? print('moving to history', Editor_state.next_history-1)
Next_history = Next_history-1 Editor_state.next_history = Editor_state.next_history-1
local result = History[Next_history] local result = Editor_state.history[Editor_state.next_history]
return result return result
end end
end end
function redo_event() function redo_event()
if Next_history <= #History then if Editor_state.next_history <= #Editor_state.history then
--? print('restoring history', Next_history+1) --? print('restoring history', Editor_state.next_history+1)
local result = History[Next_history] local result = Editor_state.history[Editor_state.next_history]
Next_history = Next_history+1 Editor_state.next_history = Editor_state.next_history+1
return result return result
end end
end end
@ -40,18 +40,18 @@ function snapshot(s,e)
if e == nil then if e == nil then
e = s e = s
end end
assert(#Lines > 0) assert(#Editor_state.lines > 0)
if s < 1 then s = 1 end if s < 1 then s = 1 end
if s > #Lines then s = #Lines end if s > #Editor_state.lines then s = #Editor_state.lines end
if e < 1 then e = 1 end if e < 1 then e = 1 end
if e > #Lines then e = #Lines end if e > #Editor_state.lines then e = #Editor_state.lines end
-- compare with App.initialize_globals -- compare with App.initialize_globals
local event = { local event = {
screen_top=deepcopy(Screen_top1), screen_top=deepcopy(Editor_state.screen_top1),
selection=deepcopy(Selection1), selection=deepcopy(Editor_state.selection1),
cursor=deepcopy(Cursor1), cursor=deepcopy(Editor_state.cursor1),
current_drawing_mode=Drawing_mode, current_drawing_mode=Drawing_mode,
previous_drawing_mode=Previous_drawing_mode, previous_drawing_mode=Editor_state.previous_drawing_mode,
lines={}, lines={},
start_line=s, start_line=s,
end_line=e, end_line=e,
@ -59,7 +59,7 @@ function snapshot(s,e)
} }
-- deep copy lines without cached stuff like text fragments -- deep copy lines without cached stuff like text fragments
for i=s,e do for i=s,e do
local line = Lines[i] local line = Editor_state.lines[i]
if line.mode == 'text' then if line.mode == 'text' then
table.insert(event.lines, {mode='text', data=line.data}) table.insert(event.lines, {mode='text', data=line.data})
elseif line.mode == 'drawing' then elseif line.mode == 'drawing' then