State, Editor_state -> Editor

This commit is contained in:
Kartik K. Agaram 2024-07-20 00:24:12 -07:00
parent 4aa23aefef
commit bf520b6e69
11 changed files with 1191 additions and 1191 deletions

View File

@ -8,20 +8,20 @@
-- event will continue to propagate elsewhere in the widget.
-- draw button and queue up event handlers
function button(State, name, params)
function button(Editor, name, params)
if params.bg then
love.graphics.setColor(params.bg.r, params.bg.g, params.bg.b, params.bg.a)
love.graphics.rectangle('fill', params.x,params.y, params.w,params.h, 5,5)
end
if params.icon then params.icon(params) end
table.insert(State.button_handlers, params)
table.insert(Editor.button_handlers, params)
end
-- process button event handlers
function mouse_press_consumed_by_any_button(State, x, y, mouse_button)
function mouse_press_consumed_by_any_button(Editor, x, y, mouse_button)
local button_pressed = false
local consume_press = true
for _,ev in ipairs(State.button_handlers) do
for _,ev in ipairs(Editor.button_handlers) do
if x>ev.x and x<ev.x+ev.w and y>ev.y and y<ev.y+ev.h then
if ev.onpress1 and mouse_button == 1 then
button_pressed = true

View File

@ -3,38 +3,38 @@ Drawing = {}
-- All drawings span 100% of some conceptual 'page width' and divide it up
-- into 256 parts.
function Drawing.draw(State, line_index, starty)
local line = State.lines[line_index]
function Drawing.draw(Editor, line_index, starty)
local line = Editor.lines[line_index]
local pmx,pmy = love.mouse.getPosition()
local height = Drawing.pixels(line.h, State.width)
if line_index == State.cursor.line then
local height = Drawing.pixels(line.h, Editor.width)
if line_index == Editor.cursor.line then
App.color(Cursor_color)
love.graphics.rectangle('line', State.left, starty, State.width, height)
elseif geom.in_rect(pmx,pmy, State.left, starty, State.width, height) then
love.graphics.rectangle('line', Editor.left, starty, Editor.width, height)
elseif geom.in_rect(pmx,pmy, Editor.left, starty, Editor.width, height) then
App.color(Icon_color)
love.graphics.rectangle('line', State.left, starty, State.width, height)
love.graphics.rectangle('line', Editor.left, starty, Editor.width, height)
end
if geom.in_rect(pmx,pmy, State.left, starty, State.width, height) then
if geom.in_rect(pmx,pmy, Editor.left, starty, Editor.width, height) then
App.color(Icon_color)
if icon[State.current_drawing_mode] then
icon[State.current_drawing_mode](State.right-22, starty+4)
if icon[Editor.current_drawing_mode] then
icon[Editor.current_drawing_mode](Editor.right-22, starty+4)
else
icon[State.previous_drawing_mode](State.right-22, starty+4)
icon[Editor.previous_drawing_mode](Editor.right-22, starty+4)
end
if love.mouse.isDown(1) and love.keyboard.isDown('h') then
draw_help_with_mouse_pressed(State, line_index)
draw_help_with_mouse_pressed(Editor, line_index)
return
end
end
if line.show_help then
draw_help_without_mouse_pressed(State, line_index)
draw_help_without_mouse_pressed(Editor, line_index)
return
end
local mx = Drawing.coord(pmx-State.left, State.width)
local my = Drawing.coord(pmy-starty, State.width)
local mx = Drawing.coord(pmx-Editor.left, Editor.width)
local my = Drawing.coord(pmy-starty, Editor.width)
for _,shape in ipairs(line.shapes) do
if geom.on_shape(mx,my, line, shape) then
@ -42,14 +42,14 @@ function Drawing.draw(State, line_index, starty)
else
App.color(Stroke_color)
end
Drawing.draw_shape(line, shape, starty, State.left,State.right)
Drawing.draw_shape(line, shape, starty, Editor.left,Editor.right)
end
local function px(x) return Drawing.pixels(x, State.width)+State.left end
local function py(y) return Drawing.pixels(y, State.width)+starty end
local function px(x) return Drawing.pixels(x, Editor.width)+Editor.left end
local function py(y) return Drawing.pixels(y, Editor.width)+starty end
for i,p in ipairs(line.points) do
if p.deleted == nil then
if Drawing.near(p, mx,my, State.width) then
if Drawing.near(p, mx,my, Editor.width) then
App.color(Focus_stroke_color)
love.graphics.circle('line', px(p.x),py(p.y), Same_point_distance)
else
@ -60,22 +60,22 @@ function Drawing.draw(State, line_index, starty)
-- TODO: clip
local x,y = px(p.x)+5, py(p.y)+5
love.graphics.print(p.name, x,y)
if State.current_drawing_mode == 'name' and i == line.pending.target_point then
if Editor.current_drawing_mode == 'name' and i == line.pending.target_point then
-- create a faint red box for the name
App.color(Current_name_background_color)
local name_width
if p.name == '' then
name_width = State.font:getWidth('m')
name_width = Editor.font:getWidth('m')
else
name_width = State.font:getWidth(p.name)
name_width = Editor.font:getWidth(p.name)
end
love.graphics.rectangle('fill', x,y, name_width, State.line_height)
love.graphics.rectangle('fill', x,y, name_width, Editor.line_height)
end
end
end
end
App.color(Current_stroke_color)
Drawing.draw_pending_shape(line, starty, State.left,State.right)
Drawing.draw_pending_shape(line, starty, Editor.left,Editor.right)
end
function Drawing.draw_shape(drawing, shape, top, left,right)
@ -213,51 +213,51 @@ function Drawing.draw_pending_shape(drawing, top, left,right)
end
end
function Drawing.in_current_drawing(State, x,y, left,right)
if State.cursor.mode ~= 'drawing' then return false end
assert(State.lines[State.cursor.line].mode == 'drawing')
return Drawing.in_drawing(State, State.cursor.line, x,y, left,right)
function Drawing.in_current_drawing(Editor, x,y, left,right)
if Editor.cursor.mode ~= 'drawing' then return false end
assert(Editor.lines[Editor.cursor.line].mode == 'drawing')
return Drawing.in_drawing(Editor, Editor.cursor.line, x,y, left,right)
end
function Drawing.in_drawing(State, line_index, x,y, left,right)
assert(State.lines[line_index].mode == 'drawing')
local starty = Text.starty(State, line_index)
function Drawing.in_drawing(Editor, line_index, x,y, left,right)
assert(Editor.lines[line_index].mode == 'drawing')
local starty = Text.starty(Editor, line_index)
if starty == nil then return false end -- outside current page
local drawing = State.lines[line_index]
local drawing = Editor.lines[line_index]
local width = right-left
return y >= starty and y < starty + Drawing.pixels(drawing.h, width) and x >= left and x < right
end
function Drawing.mouse_press(State, drawing_index, x,y, mouse_button)
local drawing = State.lines[drawing_index]
local starty = Text.starty(State, drawing_index)
local cx = Drawing.coord(x-State.left, State.width)
local cy = Drawing.coord(y-starty, State.width)
if State.current_drawing_mode == 'freehand' then
drawing.pending = {mode=State.current_drawing_mode, points={{x=cx, y=cy}}}
elseif State.current_drawing_mode == 'line' or State.current_drawing_mode == 'manhattan' then
local j = Drawing.find_or_insert_point(drawing.points, cx, cy, State.width)
drawing.pending = {mode=State.current_drawing_mode, p1=j}
elseif State.current_drawing_mode == 'polygon' or State.current_drawing_mode == 'rectangle' or State.current_drawing_mode == 'square' then
local j = Drawing.find_or_insert_point(drawing.points, cx, cy, State.width)
drawing.pending = {mode=State.current_drawing_mode, vertices={j}}
elseif State.current_drawing_mode == 'circle' then
local j = Drawing.find_or_insert_point(drawing.points, cx, cy, State.width)
drawing.pending = {mode=State.current_drawing_mode, center=j}
elseif State.current_drawing_mode == 'move' then
function Drawing.mouse_press(Editor, drawing_index, x,y, mouse_button)
local drawing = Editor.lines[drawing_index]
local starty = Text.starty(Editor, drawing_index)
local cx = Drawing.coord(x-Editor.left, Editor.width)
local cy = Drawing.coord(y-starty, Editor.width)
if Editor.current_drawing_mode == 'freehand' then
drawing.pending = {mode=Editor.current_drawing_mode, points={{x=cx, y=cy}}}
elseif Editor.current_drawing_mode == 'line' or Editor.current_drawing_mode == 'manhattan' then
local j = Drawing.find_or_insert_point(drawing.points, cx, cy, Editor.width)
drawing.pending = {mode=Editor.current_drawing_mode, p1=j}
elseif Editor.current_drawing_mode == 'polygon' or Editor.current_drawing_mode == 'rectangle' or Editor.current_drawing_mode == 'square' then
local j = Drawing.find_or_insert_point(drawing.points, cx, cy, Editor.width)
drawing.pending = {mode=Editor.current_drawing_mode, vertices={j}}
elseif Editor.current_drawing_mode == 'circle' then
local j = Drawing.find_or_insert_point(drawing.points, cx, cy, Editor.width)
drawing.pending = {mode=Editor.current_drawing_mode, center=j}
elseif Editor.current_drawing_mode == 'move' then
-- all the action is in mouse_release
elseif State.current_drawing_mode == 'name' then
elseif Editor.current_drawing_mode == 'name' then
-- nothing
else
assert(false, ('unknown drawing mode %s'):format(State.current_drawing_mode))
assert(false, ('unknown drawing mode %s'):format(Editor.current_drawing_mode))
end
end
-- a couple of operations on drawings need to constantly check the state of the mouse
function Drawing.update(State)
if State.cursor.mode ~= 'drawing' then return end
local drawing = State.lines[State.cursor.line]
local starty = Text.starty(State, State.cursor.line)
function Drawing.update(Editor)
if Editor.cursor.mode ~= 'drawing' then return end
local drawing = Editor.lines[Editor.cursor.line]
local starty = Text.starty(Editor, Editor.cursor.line)
if starty == nil then
-- some event cleared starty just this frame
-- draw in this frame will soon set starty
@ -266,10 +266,10 @@ function Drawing.update(State)
end
assert(drawing.mode == 'drawing', 'Drawing.update: line is not a drawing')
local pmx,pmy = love.mouse.getPosition()
local mx = Drawing.coord(pmx-State.left, State.width)
local my = Drawing.coord(pmy-starty, State.width)
local mx = Drawing.coord(pmx-Editor.left, Editor.width)
local my = Drawing.coord(pmy-starty, Editor.width)
if love.mouse.isDown(1) then
if Drawing.in_current_drawing(State, pmx,pmy, State.left,State.right) then
if Drawing.in_current_drawing(Editor, pmx,pmy, Editor.left,Editor.right) then
if drawing.pending.mode == 'freehand' then
table.insert(drawing.pending.points, {x=mx, y=my})
elseif drawing.pending.mode == 'move' then
@ -278,8 +278,8 @@ function Drawing.update(State)
Drawing.relax_constraints(drawing, drawing.pending.target_point_index)
end
end
elseif State.current_drawing_mode == 'move' then
if Drawing.in_current_drawing(State, pmx, pmy, State.left,State.right) then
elseif Editor.current_drawing_mode == 'move' then
if Drawing.in_current_drawing(Editor, pmx, pmy, Editor.left,Editor.right) then
drawing.pending.target_point.x = mx
drawing.pending.target_point.y = my
Drawing.relax_constraints(drawing, drawing.pending.target_point_index)
@ -307,14 +307,14 @@ function Drawing.relax_constraints(drawing, p)
end
end
function Drawing.mouse_release(State, x,y, mouse_button)
if State.cursor.mode ~= 'drawing' then return end
if State.current_drawing_mode == 'move' then
State.current_drawing_mode = State.previous_drawing_mode
State.previous_drawing_mode = nil
function Drawing.mouse_release(Editor, x,y, mouse_button)
if Editor.cursor.mode ~= 'drawing' then return end
if Editor.current_drawing_mode == 'move' then
Editor.current_drawing_mode = Editor.previous_drawing_mode
Editor.previous_drawing_mode = nil
else
local drawing = State.lines[State.cursor.line]
local starty = Text.starty(State, State.cursor.line)
local drawing = Editor.lines[Editor.cursor.line]
local starty = Text.starty(Editor, Editor.cursor.line)
if drawing.pending then
if drawing.pending.mode == nil then
-- nothing pending
@ -323,40 +323,40 @@ function Drawing.mouse_release(State, x,y, mouse_button)
Drawing.smoothen(drawing.pending)
table.insert(drawing.shapes, drawing.pending)
elseif drawing.pending.mode == 'line' then
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
drawing.pending.p2 = Drawing.find_or_insert_point(drawing.points, mx,my, State.width)
drawing.pending.p2 = Drawing.find_or_insert_point(drawing.points, mx,my, Editor.width)
table.insert(drawing.shapes, drawing.pending)
end
elseif drawing.pending.mode == 'manhattan' then
local p1 = drawing.points[drawing.pending.p1]
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
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
drawing.pending.p2 = Drawing.find_or_insert_point(drawing.points, mx, p1.y, State.width)
drawing.pending.p2 = Drawing.find_or_insert_point(drawing.points, mx, p1.y, Editor.width)
else
drawing.pending.p2 = Drawing.find_or_insert_point(drawing.points, p1.x, my, State.width)
drawing.pending.p2 = Drawing.find_or_insert_point(drawing.points, p1.x, my, Editor.width)
end
local p2 = drawing.points[drawing.pending.p2]
love.mouse.setPosition(State.left+Drawing.pixels(p2.x, State.width), starty+Drawing.pixels(p2.y, State.width))
love.mouse.setPosition(Editor.left+Drawing.pixels(p2.x, Editor.width), starty+Drawing.pixels(p2.y, Editor.width))
table.insert(drawing.shapes, drawing.pending)
end
elseif drawing.pending.mode == 'polygon' then
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, mx,my, State.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, mx,my, Editor.width))
table.insert(drawing.shapes, drawing.pending)
end
elseif drawing.pending.mode == 'rectangle' then
assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: rectangle has too many pending vertices')
if #drawing.pending.vertices == 2 then
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local first = drawing.points[drawing.pending.vertices[1]]
local second = drawing.points[drawing.pending.vertices[2]]
local thirdx,thirdy, fourthx,fourthy = Drawing.complete_rectangle(first.x,first.y, second.x,second.y, mx,my)
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, thirdx,thirdy, State.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, fourthx,fourthy, State.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, thirdx,thirdy, Editor.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, fourthx,fourthy, Editor.width))
table.insert(drawing.shapes, drawing.pending)
end
else
@ -365,25 +365,25 @@ function Drawing.mouse_release(State, x,y, mouse_button)
elseif drawing.pending.mode == 'square' then
assert(#drawing.pending.vertices <= 2, 'Drawing.mouse_release: square has too many pending vertices')
if #drawing.pending.vertices == 2 then
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local first = drawing.points[drawing.pending.vertices[1]]
local second = drawing.points[drawing.pending.vertices[2]]
local thirdx,thirdy, fourthx,fourthy = Drawing.complete_square(first.x,first.y, second.x,second.y, mx,my)
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, thirdx,thirdy, State.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, fourthx,fourthy, State.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, thirdx,thirdy, Editor.width))
table.insert(drawing.pending.vertices, Drawing.find_or_insert_point(drawing.points, fourthx,fourthy, Editor.width))
table.insert(drawing.shapes, drawing.pending)
end
end
elseif drawing.pending.mode == 'circle' then
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
local center = drawing.points[drawing.pending.center]
drawing.pending.radius = round(geom.dist(center.x,center.y, mx,my))
table.insert(drawing.shapes, drawing.pending)
end
elseif drawing.pending.mode == 'arc' then
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
if mx >= 0 and mx < 256 and my >= 0 and my < drawing.h then
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)
@ -399,15 +399,15 @@ function Drawing.mouse_release(State, x,y, mouse_button)
end
end
function Drawing.keychord_press(State, chord)
function Drawing.keychord_press(Editor, chord)
local pmx,pmy = love.mouse.getPosition()
if chord == 'C-p' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'freehand'
Editor.current_drawing_mode = 'freehand'
elseif love.mouse.isDown(1) and chord == 'l' then
State.current_drawing_mode = 'line'
local drawing = State.lines[State.cursor.line]
Editor.current_drawing_mode = 'line'
local drawing = Editor.lines[Editor.cursor.line]
if drawing.pending.mode == 'freehand' then
drawing.pending.p1 = Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, State.width)
drawing.pending.p1 = Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, Editor.width)
elseif drawing.pending.mode == 'polygon' or drawing.pending.mode == 'rectangle' or drawing.pending.mode == 'square' then
drawing.pending.p1 = drawing.pending.vertices[1]
elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then
@ -415,12 +415,12 @@ function Drawing.keychord_press(State, chord)
end
drawing.pending.mode = 'line'
elseif chord == 'C-l' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'line'
Editor.current_drawing_mode = 'line'
elseif love.mouse.isDown(1) and chord == 'm' then
State.current_drawing_mode = 'manhattan'
local drawing = Drawing.select_drawing_at_mouse(State)
Editor.current_drawing_mode = 'manhattan'
local drawing = Drawing.select_drawing_at_mouse(Editor)
if drawing.pending.mode == 'freehand' then
drawing.pending.p1 = Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, State.width)
drawing.pending.p1 = Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, Editor.width)
elseif drawing.pending.mode == 'line' then
-- do nothing
elseif drawing.pending.mode == 'polygon' or drawing.pending.mode == 'rectangle' or drawing.pending.mode == 'square' then
@ -430,14 +430,14 @@ function Drawing.keychord_press(State, chord)
end
drawing.pending.mode = 'manhattan'
elseif chord == 'C-m' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'manhattan'
Editor.current_drawing_mode = 'manhattan'
elseif chord == 'C-g' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'polygon'
Editor.current_drawing_mode = 'polygon'
elseif love.mouse.isDown(1) and chord == 'g' then
State.current_drawing_mode = 'polygon'
local drawing = State.lines[State.cursor.line]
Editor.current_drawing_mode = 'polygon'
local drawing = Editor.lines[Editor.cursor.line]
if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, State.width)}
drawing.pending.vertices = {Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, Editor.width)}
elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then
if drawing.pending.vertices == nil then
drawing.pending.vertices = {drawing.pending.p1}
@ -449,12 +449,12 @@ function Drawing.keychord_press(State, chord)
end
drawing.pending.mode = 'polygon'
elseif chord == 'C-r' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'rectangle'
Editor.current_drawing_mode = 'rectangle'
elseif love.mouse.isDown(1) and chord == 'r' then
State.current_drawing_mode = 'rectangle'
local drawing = State.lines[State.cursor.line]
Editor.current_drawing_mode = 'rectangle'
local drawing = Editor.lines[Editor.cursor.line]
if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, State.width)}
drawing.pending.vertices = {Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, Editor.width)}
elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then
if drawing.pending.vertices == nil then
drawing.pending.vertices = {drawing.pending.p1}
@ -466,12 +466,12 @@ function Drawing.keychord_press(State, chord)
end
drawing.pending.mode = 'rectangle'
elseif chord == 'C-s' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'square'
Editor.current_drawing_mode = 'square'
elseif love.mouse.isDown(1) and chord == 's' then
State.current_drawing_mode = 'square'
local drawing = State.lines[State.cursor.line]
Editor.current_drawing_mode = 'square'
local drawing = Editor.lines[Editor.cursor.line]
if drawing.pending.mode == 'freehand' then
drawing.pending.vertices = {Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, State.width)}
drawing.pending.vertices = {Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, Editor.width)}
elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then
if drawing.pending.vertices == nil then
drawing.pending.vertices = {drawing.pending.p1}
@ -486,36 +486,36 @@ function Drawing.keychord_press(State, chord)
drawing.pending.vertices = {drawing.pending.center}
end
drawing.pending.mode = 'square'
elseif love.mouse.isDown(1) and chord == 'p' and State.current_drawing_mode == 'polygon' then
local drawing = State.lines[State.cursor.line]
local starty = Text.starty(State, State.cursor.line)
local mx,my = Drawing.coord(pmx-State.left, State.width), Drawing.coord(pmy-starty, State.width)
local j = Drawing.find_or_insert_point(drawing.points, mx,my, State.width)
elseif love.mouse.isDown(1) and chord == 'p' and Editor.current_drawing_mode == 'polygon' then
local drawing = Editor.lines[Editor.cursor.line]
local starty = Text.starty(Editor, Editor.cursor.line)
local mx,my = Drawing.coord(pmx-Editor.left, Editor.width), Drawing.coord(pmy-starty, Editor.width)
local j = Drawing.find_or_insert_point(drawing.points, mx,my, Editor.width)
table.insert(drawing.pending.vertices, j)
elseif love.mouse.isDown(1) and chord == 'p' and (State.current_drawing_mode == 'rectangle' or State.current_drawing_mode == 'square') then
local drawing = State.lines[State.cursor.line]
local starty = Text.starty(State, State.cursor.line)
local mx,my = Drawing.coord(pmx-State.left, State.width), Drawing.coord(pmy-starty, State.width)
local j = Drawing.find_or_insert_point(drawing.points, mx,my, State.width)
elseif love.mouse.isDown(1) and chord == 'p' and (Editor.current_drawing_mode == 'rectangle' or Editor.current_drawing_mode == 'square') then
local drawing = Editor.lines[Editor.cursor.line]
local starty = Text.starty(Editor, Editor.cursor.line)
local mx,my = Drawing.coord(pmx-Editor.left, Editor.width), Drawing.coord(pmy-starty, Editor.width)
local j = Drawing.find_or_insert_point(drawing.points, mx,my, Editor.width)
while #drawing.pending.vertices >= 2 do
table.remove(drawing.pending.vertices)
end
table.insert(drawing.pending.vertices, j)
elseif chord == 'C-o' and not love.mouse.isDown(1) then
State.current_drawing_mode = 'circle'
elseif love.mouse.isDown(1) and chord == 'a' and State.current_drawing_mode == 'circle' then
local drawing = State.lines[State.cursor.line]
local starty = Text.starty(State, State.cursor.line)
Editor.current_drawing_mode = 'circle'
elseif love.mouse.isDown(1) and chord == 'a' and Editor.current_drawing_mode == 'circle' then
local drawing = Editor.lines[Editor.cursor.line]
local starty = Text.starty(Editor, Editor.cursor.line)
drawing.pending.mode = 'arc'
local mx,my = Drawing.coord(pmx-State.left, State.width), Drawing.coord(pmy-starty, State.width)
local mx,my = Drawing.coord(pmx-Editor.left, Editor.width), Drawing.coord(pmy-starty, Editor.width)
local center = drawing.points[drawing.pending.center]
drawing.pending.radius = round(geom.dist(center.x,center.y, mx,my))
drawing.pending.start_angle = geom.angle(center.x,center.y, mx,my)
elseif love.mouse.isDown(1) and chord == 'o' then
State.current_drawing_mode = 'circle'
local drawing = State.lines[State.cursor.line]
Editor.current_drawing_mode = 'circle'
local drawing = Editor.lines[Editor.cursor.line]
if drawing.pending.mode == 'freehand' then
drawing.pending.center = Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, State.width)
drawing.pending.center = Drawing.find_or_insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y, Editor.width)
elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then
drawing.pending.center = drawing.pending.p1
elseif drawing.pending.mode == 'polygon' or drawing.pending.mode == 'rectangle' or drawing.pending.mode == 'square' then
@ -523,32 +523,32 @@ function Drawing.keychord_press(State, chord)
end
drawing.pending.mode = 'circle'
elseif chord == 'C-u' and not love.mouse.isDown(1) then
if Drawing.in_current_drawing(State, pmx, pmy, State.left,State.right) then
local drawing = State.lines[State.cursor.line]
local point_index,p = Drawing.select_point_at_mouse(State)
if State.previous_drawing_mode == nil then
State.previous_drawing_mode = State.current_drawing_mode
if Drawing.in_current_drawing(Editor, pmx, pmy, Editor.left,Editor.right) then
local drawing = Editor.lines[Editor.cursor.line]
local point_index,p = Drawing.select_point_at_mouse(Editor)
if Editor.previous_drawing_mode == nil then
Editor.previous_drawing_mode = Editor.current_drawing_mode
end
State.current_drawing_mode = 'move'
drawing.pending = {mode=State.current_drawing_mode, target_point=p, target_point_index=point_index}
Editor.current_drawing_mode = 'move'
drawing.pending = {mode=Editor.current_drawing_mode, target_point=p, target_point_index=point_index}
end
elseif chord == 'C-n' and not love.mouse.isDown(1) then
if Drawing.in_current_drawing(State, pmx, pmy, State.left,State.right) then
local drawing = State.lines[State.cursor.line]
local point_index,p = Drawing.select_point_at_mouse(State)
if State.previous_drawing_mode == nil then
State.previous_drawing_mode = State.current_drawing_mode
if Drawing.in_current_drawing(Editor, pmx, pmy, Editor.left,Editor.right) then
local drawing = Editor.lines[Editor.cursor.line]
local point_index,p = Drawing.select_point_at_mouse(Editor)
if Editor.previous_drawing_mode == nil then
Editor.previous_drawing_mode = Editor.current_drawing_mode
end
State.current_drawing_mode = 'name'
Editor.current_drawing_mode = 'name'
p.name = ''
drawing.pending = {mode=State.current_drawing_mode, target_point=point_index}
drawing.pending = {mode=Editor.current_drawing_mode, target_point=point_index}
end
elseif chord == 'C-d' and not love.mouse.isDown(1) then
if Drawing.in_current_drawing(State, pmx, pmy, State.left,State.right) then
local starty = Text.starty(State, State.cursor.line)
local mx, my = Drawing.coord(pmx-State.left, State.width), Drawing.coord(pmy-starty, State.width)
local drawing = State.lines[State.cursor.line]
local point_index,p = Drawing.select_point_at_mouse(State)
if Drawing.in_current_drawing(Editor, pmx, pmy, Editor.left,Editor.right) then
local starty = Text.starty(Editor, Editor.cursor.line)
local mx, my = Drawing.coord(pmx-Editor.left, Editor.width), Drawing.coord(pmy-starty, Editor.width)
local drawing = Editor.lines[Editor.cursor.line]
local point_index,p = Drawing.select_point_at_mouse(Editor)
for _,shape in ipairs(drawing.shapes) do
if point_index and Drawing.contains_point(shape, point_index) then
if shape.mode == 'polygon' then
@ -571,12 +571,12 @@ function Drawing.keychord_press(State, chord)
end
end
elseif chord == 'C-h' and not love.mouse.isDown(1) then
local drawing = Drawing.select_drawing_at_mouse(State)
local drawing = Drawing.select_drawing_at_mouse(Editor)
if drawing then
drawing.show_help = true
end
elseif chord == 'escape' and love.mouse.isDown(1) then
local _,drawing = Drawing.current_drawing(State)
local _,drawing = Drawing.current_drawing(Editor)
drawing.pending = {}
end
end
@ -629,26 +629,26 @@ function Drawing.complete_square(firstx,firsty, secondx,secondy, x,y)
return thirdx,thirdy, fourthx,fourthy
end
function Drawing.select_point_at_mouse(State)
if State.cursor.mode ~= 'drawing' then return end
function Drawing.select_point_at_mouse(Editor)
if Editor.cursor.mode ~= 'drawing' then return end
local x,y = love.mouse.getPosition()
if not Drawing.in_current_drawing(State, x,y, State.left,State.right) then return end
local starty = Text.starty(State, State.cursor.line)
local mx,my = Drawing.coord(x-State.left, State.width), Drawing.coord(y-starty, State.width)
local drawing = State.lines[State.cursor.line]
if not Drawing.in_current_drawing(Editor, x,y, Editor.left,Editor.right) then return end
local starty = Text.starty(Editor, Editor.cursor.line)
local mx,my = Drawing.coord(x-Editor.left, Editor.width), Drawing.coord(y-starty, Editor.width)
local drawing = Editor.lines[Editor.cursor.line]
assert(drawing.mode == 'drawing')
for i,point in ipairs(drawing.points) do
if Drawing.near(point, mx,my, State.width) then
if Drawing.near(point, mx,my, Editor.width) then
return i,point
end
end
end
function Drawing.select_drawing_at_mouse(State)
for drawing_index,drawing in ipairs(State.lines) do
function Drawing.select_drawing_at_mouse(Editor)
for drawing_index,drawing in ipairs(Editor.lines) do
if drawing.mode == 'drawing' then
local x,y = love.mouse.getPosition()
if Drawing.in_drawing(State, drawing_index, x,y, State.left,State.right) then
if Drawing.in_drawing(Editor, drawing_index, x,y, Editor.left,Editor.right) then
return drawing
end
end

444
edit.lua
View File

@ -108,101 +108,101 @@ function new_editor(top, left, right, font, font_height, line_height) -- curren
return result
end -- new_editor
function edit.scroll_to_top(State)
assert(#State.lines > 0)
if State.lines[1].mode == 'text' then
State.screen_top = {mode='text', line=1, pos=1}
State.cursor = {mode='text', line=1, pos=1}
function edit.scroll_to_top(Editor)
assert(#Editor.lines > 0)
if Editor.lines[1].mode == 'text' then
Editor.screen_top = {mode='text', line=1, pos=1}
Editor.cursor = {mode='text', line=1, pos=1}
else
State.screen_top = {mode='drawing', line=1, yoff=0}
State.cursor = {mode='drawing', line=1, yoff=0}
Editor.screen_top = {mode='drawing', line=1, yoff=0}
Editor.cursor = {mode='drawing', line=1, yoff=0}
end
end
function edit.valid_loc(State, loc)
assert(#State.lines > 0)
function edit.valid_loc(Editor, loc)
assert(#Editor.lines > 0)
if loc == nil then return end
if loc.line > #State.lines then return end
return State.lines[loc.line].mode == loc.mode
if loc.line > #Editor.lines then return end
return Editor.lines[loc.line].mode == loc.mode
end
-- return y drawn until
function edit.draw(State)
State.button_handlers = {}
love.graphics.setFont(State.font)
State.cursor_x = nil
State.cursor_y = nil
function edit.draw(Editor)
Editor.button_handlers = {}
love.graphics.setFont(Editor.font)
Editor.cursor_x = nil
Editor.cursor_y = nil
local cursor_or_mouse_loc = State.cursor
if State.mouse_down then
local loc = Text.mouse_loc(State)
local cursor_or_mouse_loc = Editor.cursor
if Editor.mouse_down then
local loc = Text.mouse_loc(Editor)
if loc.mode == 'text' then
cursor_or_mouse_loc = loc
end
end
local do_it = function(x,y, w, line_index, pos, char)
if in_selection(State, line_index, pos, cursor_or_mouse_loc)
or in_search(State, line_index, pos)
if in_selection(Editor, line_index, pos, cursor_or_mouse_loc)
or in_search(Editor, line_index, pos)
then
App.color(Highlight_color)
love.graphics.rectangle('fill', x,y, w,State.line_height)
love.graphics.rectangle('fill', x,y, w,Editor.line_height)
end
App.color(Text_color)
love.graphics.print(char, x,y)
if line_index == State.cursor.line and pos == State.cursor.pos then
Text.draw_cursor(State, x,y)
if line_index == Editor.cursor.line and pos == Editor.cursor.pos then
Text.draw_cursor(Editor, x,y)
end
end
local draw_just_cursor = function(x,y, line_index, pos)
if line_index == State.cursor.line and pos == State.cursor.pos then
Text.draw_cursor(State, x,y)
if line_index == Editor.cursor.line and pos == Editor.cursor.pos then
Text.draw_cursor(Editor, x,y)
end
end
local y = State.top
for line_index, line in array.each(State.lines, State.screen_top.line) do
local y = Editor.top
for line_index, line in array.each(Editor.lines, Editor.screen_top.line) do
if line.mode == 'text' then
local x = State.left
local x = Editor.left
local initpos = 1
if line_index == State.screen_top.line then
initpos = State.screen_top.pos
if line_index == Editor.screen_top.line then
initpos = Editor.screen_top.pos
end
if line.data == '' then
-- button to insert new drawing
button(State, 'draw', {x=State.left-Margin_left+4, y=y+4, w=12,h=12, bg={r=1,g=1,b=0},
button(Editor, 'draw', {x=Editor.left-Margin_left+4, y=y+4, w=12,h=12, bg={r=1,g=1,b=0},
icon = icon.insert_drawing,
onpress1 = function()
State.drawing_before = snapshot(State, line_index-1, line_index)
table.insert(State.lines, line_index, {mode='drawing', y=y, h=256/2, points={}, shapes={}, pending={}})
table.insert(State.line_cache, line_index, {})
State.cursor = {mode='drawing', line=line_index, yoff=0}
schedule_save(State)
record_undo_event(State, {before=State.drawing_before, after=snapshot(State, line_index-1, line_index+1)})
Editor.drawing_before = snapshot(Editor, line_index-1, line_index)
table.insert(Editor.lines, line_index, {mode='drawing', y=y, h=256/2, points={}, shapes={}, pending={}})
table.insert(Editor.line_cache, line_index, {})
Editor.cursor = {mode='drawing', line=line_index, yoff=0}
schedule_save(Editor)
record_undo_event(Editor, {before=Editor.drawing_before, after=snapshot(Editor, line_index-1, line_index+1)})
end,
})
else
for pos,char in utf8chars(line.data, initpos) do
local w = State.font:getWidth(char)
local w = Editor.font:getWidth(char)
if char:match('%s') then
if line_wrap_at_word_boundary(State, x, line.data, pos) then
if line_wrap_at_word_boundary(Editor, x, line.data, pos) then
do_it(x,y, w, line_index, pos, char)
x = State.left
y = y + State.line_height
x = Editor.left
y = y + Editor.line_height
-- optional: show cursor symmetrically when between wrapped screen lines
if line_index == State.cursor.line and pos == State.cursor.pos then
Text.draw_cursor(State, x,y)
if line_index == Editor.cursor.line and pos == Editor.cursor.pos then
Text.draw_cursor(Editor, x,y)
end
else
do_it(x,y, w, line_index, pos, char)
x = x + w
end
else
if x+w > State.right then
if x+w > Editor.right then
draw_just_cursor(x,y, line_index, pos)
x = State.left
y = y + State.line_height
x = Editor.left
y = y + Editor.line_height
do_it(x,y, w, line_index, pos, char)
else
do_it(x,y, w, line_index, pos, char)
@ -213,14 +213,14 @@ function edit.draw(State)
end
-- draw cursor if it's at end of line
do_it(x,y, 0, line_index, utf8.len(line.data)+1, '')
y = y + State.line_height
y = y + Editor.line_height
elseif line.mode == 'drawing' then
local yoff = 0
if line_index == State.screen_top.line then
yoff = State.screen_top.yoff or 0
if line_index == Editor.screen_top.line then
yoff = Editor.screen_top.yoff or 0
end
local h = Drawing_padding_height + Drawing.pixels(line.h, State.width)
Drawing.draw(State, line_index, y+Drawing_padding_top-yoff)
local h = Drawing_padding_height + Drawing.pixels(line.h, Editor.width)
Drawing.draw(Editor, line_index, y+Drawing_padding_top-yoff)
y = y + h - yoff
else
assert(false, ('unknown line mode %s'):format(line.mode))
@ -229,52 +229,52 @@ function edit.draw(State)
break
end
end
if State.search_term then
Text.draw_search_bar(State)
if Editor.search_term then
Text.draw_search_bar(Editor)
end
return y
end
function edit.update(State, dt)
Drawing.update(State, dt)
if State.next_save and State.next_save < Current_time then
save_to_disk(State)
State.next_save = nil
function edit.update(Editor, dt)
Drawing.update(Editor, dt)
if Editor.next_save and Editor.next_save < Current_time then
save_to_disk(Editor)
Editor.next_save = nil
end
end
function schedule_save(State)
if State.next_save == nil then
State.next_save = Current_time + 3 -- short enough that you're likely to still remember what you did
function schedule_save(Editor)
if Editor.next_save == nil then
Editor.next_save = Current_time + 3 -- short enough that you're likely to still remember what you did
end
end
function edit.quit(State)
function edit.quit(Editor)
-- make sure to save before quitting
if State.next_save then
save_to_disk(State)
if Editor.next_save then
save_to_disk(Editor)
-- give some time for the OS to flush everything to disk
love.timer.sleep(0.1)
end
end
function edit.mouse_press(State, mx,my, mouse_button)
function edit.mouse_press(Editor, mx,my, mouse_button)
love.keyboard.setTextInput(true) -- bring up keyboard on touch screen
if State.search_term then return end
State.mouse_down = mouse_button
if mouse_press_consumed_by_any_button(State, mx,my, mouse_button) then
if Editor.search_term then return end
Editor.mouse_down = mouse_button
if mouse_press_consumed_by_any_button(Editor, mx,my, mouse_button) then
-- press on a button and it returned 'true' to short-circuit
return
end
local loc = to_loc(State, mx,my)
local loc = to_loc(Editor, mx,my)
if loc == nil then
-- either the click is above the top margin and the top line is not text
-- or the click is below the bottom margin and the bottom line is not text
return
end
State.cursor = loc
Editor.cursor = loc
if loc.mode == 'text' then
-- prepare for a drag selecting text
-- delicate dance between cursor/selection and old cursor/selection
@ -286,62 +286,62 @@ function edit.mouse_press(State, mx,my, mouse_button)
-- press and hold to start a selection: sets selection on press, cursor on release
-- press and hold, then press shift: ignore shift
-- i.e. mouse_release should never look at shift state
State.old_cursor1 = State.cursor
State.old_selection1 = State.selection1
State.mousepress_shift = shift_down()
State.selection1 = deepcopy(loc)
Editor.old_cursor1 = Editor.cursor
Editor.old_selection1 = Editor.selection1
Editor.mousepress_shift = shift_down()
Editor.selection1 = deepcopy(loc)
else
State.drawing_before = snapshot(State, loc.line)
Drawing.mouse_press(State, loc.line, mx,my, mouse_button)
Editor.drawing_before = snapshot(Editor, loc.line)
Drawing.mouse_press(Editor, loc.line, mx,my, mouse_button)
end
end
function edit.mouse_release(State, mx,my, mouse_button)
if State.search_term then return end
State.mouse_down = nil
function edit.mouse_release(Editor, mx,my, mouse_button)
if Editor.search_term then return end
Editor.mouse_down = nil
local loc = to_loc(State, mx,my)
local loc = to_loc(Editor, mx,my)
if loc.mode == 'text' then
State.cursor = loc
edit.clean_up_mouse_press(State)
Editor.cursor = loc
edit.clean_up_mouse_press(Editor)
else
State.selection1 = {}
Drawing.mouse_release(State, mx,my, mouse_button)
schedule_save(State)
if State.drawing_before then
record_undo_event(State, {before=State.drawing_before, after=snapshot(State, State.cursor.line)})
State.drawing_before = nil
Editor.selection1 = {}
Drawing.mouse_release(Editor, mx,my, mouse_button)
schedule_save(Editor)
if Editor.drawing_before then
record_undo_event(Editor, {before=Editor.drawing_before, after=snapshot(Editor, Editor.cursor.line)})
Editor.drawing_before = nil
end
end
end
function edit.clean_up_mouse_press(State)
if State.mousepress_shift then
if State.old_selection1.line == nil then
State.selection1 = State.old_cursor1
function edit.clean_up_mouse_press(Editor)
if Editor.mousepress_shift then
if Editor.old_selection1.line == nil then
Editor.selection1 = Editor.old_cursor1
else
State.selection1 = State.old_selection1
Editor.selection1 = Editor.old_selection1
end
end
State.old_cursor1, State.old_selection1, State.mousepress_shift = nil
if Text.eq1(State.cursor, State.selection1) then
State.selection1 = {}
Editor.old_cursor1, Editor.old_selection1, Editor.mousepress_shift = nil
if Text.eq1(Editor.cursor, Editor.selection1) then
Editor.selection1 = {}
end
end
-- helper to check if space character at pos, x is final possible candidate
-- for line wrapping before x = State.right
function line_wrap_at_word_boundary(State, x, line, pos)
if x - State.left > 0.8 * (State.right - State.left) then
-- for line wrapping before x = Editor.right
function line_wrap_at_word_boundary(Editor, x, line, pos)
if x - Editor.left > 0.8 * (Editor.right - Editor.left) then
-- word boundary more than 80% of the way across.
-- check if there's any more word boundaries before x gets to State.right
-- check if there's any more word boundaries before x gets to Editor.right
for pos, char in utf8chars(line, pos+1) do
if x > State.right then
if x > Editor.right then
return true
end
local w = State.font:getWidth(char) -- width of char
local w = Editor.font:getWidth(char) -- width of char
if char:match('%s') then
if x+w < State.right then
if x+w < Editor.right then
break
end
end
@ -351,63 +351,63 @@ function line_wrap_at_word_boundary(State, x, line, pos)
end
-- returns line index and pos (which will be nil for drawings)
function to_loc(State, mx,my)
if my < State.top then
return deepcopy(State.screen_top)
function to_loc(Editor, mx,my)
if my < Editor.top then
return deepcopy(Editor.screen_top)
end
local y = State.top
for line_index,line in array.each(State.lines, State.screen_top.line) do
local y = Editor.top
for line_index,line in array.each(Editor.lines, Editor.screen_top.line) do
if line.mode == 'text' then
local x = State.left
local x = Editor.left
local initpos = 1
if line_index == State.screen_top.line then
initpos = State.screen_top.pos
if line_index == Editor.screen_top.line then
initpos = Editor.screen_top.pos
end
for pos, char in utf8chars(line.data, initpos) do
local w = State.font:getWidth(char) -- width of char
local w = Editor.font:getWidth(char) -- width of char
if char:match('%s') then
if line_wrap_at_word_boundary(State, x, line.data, pos) then
if my < y+State.line_height then
if line_wrap_at_word_boundary(Editor, x, line.data, pos) then
if my < y+Editor.line_height then
return {mode='text', line=line_index, pos=pos}
end
x = State.left
y = y + State.line_height
x = Editor.left
y = y + Editor.line_height
else
if my < y+State.line_height and mx < x+w then
if my < y+Editor.line_height and mx < x+w then
return {mode='text', line=line_index, pos=pos}
end
x = x + w
end
else
if x+w > State.right then
if my < y+State.line_height then
if x+w > Editor.right then
if my < y+Editor.line_height then
return {mode='text', line=line_index, pos=pos}
end
x = State.left
y = y + State.line_height
if my < y+State.line_height and mx < x+w then
x = Editor.left
y = y + Editor.line_height
if my < y+Editor.line_height and mx < x+w then
return {mode='text', line=line_index, pos=pos}
end
else
if my < y+State.line_height and mx < x+w then
if my < y+Editor.line_height and mx < x+w then
return {mode='text', line=line_index, pos=pos}
end
end
x = x+w
end
end
if my < y+State.line_height then
if my < y+Editor.line_height then
return {mode='text', line=line_index, pos=utf8.len(line.data)+1}
end
y = y + State.line_height
y = y + Editor.line_height
else
-- drawing
local yoff = 0
if line_index == State.screen_top.line then
assert(State.screen_top.mode == 'drawing')
yoff = State.screen_top.yoff or 0
if line_index == Editor.screen_top.line then
assert(Editor.screen_top.mode == 'drawing')
yoff = Editor.screen_top.yoff or 0
end
local h = Drawing_padding_height + Drawing.pixels(line.h, State.width) - yoff
local h = Drawing_padding_height + Drawing.pixels(line.h, Editor.width) - yoff
if my < y+h then
return {mode='drawing', line=line_index, yoff=yoff}
end
@ -416,188 +416,188 @@ function to_loc(State, mx,my)
end
end
function edit.mouse_wheel_move(State, dx,dy)
function edit.mouse_wheel_move(Editor, dx,dy)
if dy > 0 then
State.cursor = deepcopy(State.screen_top)
Editor.cursor = deepcopy(Editor.screen_top)
for i=1,math.floor(dy) do
Text.up(State)
Text.up(Editor)
end
elseif dy < 0 then
State.cursor = Text.screen_bottom1(State)
Editor.cursor = Text.screen_bottom1(Editor)
for i=1,math.floor(-dy) do
Text.down(State)
Text.down(Editor)
end
end
end
function edit.text_input(State, t)
if State.search_term then
State.search_term = State.search_term..t
Text.search_next(State)
elseif State.cursor.mode == 'drawing' and State.current_drawing_mode == 'name' then
local before = snapshot(State, State.cursor.line)
local drawing = State.lines[State.cursor.line]
function edit.text_input(Editor, t)
if Editor.search_term then
Editor.search_term = Editor.search_term..t
Text.search_next(Editor)
elseif Editor.cursor.mode == 'drawing' and Editor.current_drawing_mode == 'name' then
local before = snapshot(Editor, Editor.cursor.line)
local drawing = Editor.lines[Editor.cursor.line]
local p = drawing.points[drawing.pending.target_point]
p.name = p.name..t
record_undo_event(State, {before=before, after=snapshot(State, State.cursor.line)})
record_undo_event(Editor, {before=before, after=snapshot(Editor, Editor.cursor.line)})
else
-- why is this here?
Text.text_input(State, t)
Text.text_input(Editor, t)
end
schedule_save(State)
schedule_save(Editor)
end
function edit.keychord_press(State, chord, key)
if State.selection1.line and State.cursor.mode == 'text' and
function edit.keychord_press(Editor, chord, key)
if Editor.selection1.line and Editor.cursor.mode == 'text' and
-- printable character created using shift key => delete selection
-- (we're not creating any ctrl-shift- or alt-shift- combinations using regular/printable keys)
(not shift_down() or utf8.len(key) == 1) and
chord ~= 'C-a' and chord ~= 'C-c' and chord ~= 'C-x' and chord ~= 'backspace' and chord ~= 'delete' and chord ~= 'C-z' and chord ~= 'C-y' and not is_cursor_movement(key) then
Text.delete_selection(State, State.left, State.right)
Text.delete_selection(Editor, Editor.left, Editor.right)
end
if State.search_term then
if Editor.search_term then
if chord == 'escape' then
State.search_term = nil
State.cursor = State.search_backup.cursor
State.screen_top = State.search_backup.screen_top
State.search_backup = nil
Text.redraw_all(State) -- if we're scrolling, reclaim all line caches to avoid memory leaks
Editor.search_term = nil
Editor.cursor = Editor.search_backup.cursor
Editor.screen_top = Editor.search_backup.screen_top
Editor.search_backup = nil
Text.redraw_all(Editor) -- if we're scrolling, reclaim all line caches to avoid memory leaks
elseif chord == 'return' then
State.search_term = nil
State.search_backup = nil
Editor.search_term = nil
Editor.search_backup = nil
elseif chord == 'backspace' then
local len = utf8.len(State.search_term)
local byte_offset = Text.offset(State.search_term, len)
State.search_term = string.sub(State.search_term, 1, byte_offset-1)
State.cursor = deepcopy(State.search_backup.cursor)
State.screen_top = deepcopy(State.search_backup.screen_top)
Text.search_next(State)
local len = utf8.len(Editor.search_term)
local byte_offset = Text.offset(Editor.search_term, len)
Editor.search_term = string.sub(Editor.search_term, 1, byte_offset-1)
Editor.cursor = deepcopy(Editor.search_backup.cursor)
Editor.screen_top = deepcopy(Editor.search_backup.screen_top)
Text.search_next(Editor)
elseif chord == 'down' then
Text.right(State)
Text.search_next(State)
Text.right(Editor)
Text.search_next(Editor)
elseif chord == 'up' then
Text.search_previous(State)
Text.search_previous(Editor)
end
return
elseif chord == 'C-f' then
State.search_term = ''
State.search_backup = {
cursor=deepcopy(State.cursor),
screen_top=deepcopy(State.screen_top),
Editor.search_term = ''
Editor.search_backup = {
cursor=deepcopy(Editor.cursor),
screen_top=deepcopy(Editor.screen_top),
}
-- zoom
elseif chord == 'C-=' then
edit.update_font_settings(State, State.font_height+2)
Text.redraw_all(State)
edit.update_font_settings(Editor, Editor.font_height+2)
Text.redraw_all(Editor)
elseif chord == 'C--' then
if State.font_height > 2 then
edit.update_font_settings(State, State.font_height-2)
Text.redraw_all(State)
if Editor.font_height > 2 then
edit.update_font_settings(Editor, Editor.font_height-2)
Text.redraw_all(Editor)
end
elseif chord == 'C-0' then
edit.update_font_settings(State, 20)
Text.redraw_all(State)
edit.update_font_settings(Editor, 20)
Text.redraw_all(Editor)
-- undo
elseif chord == 'C-z' then
local event = undo_event(State)
local event = undo_event(Editor)
if event then
local src = event.before
State.screen_top = deepcopy(src.screen_top)
State.cursor = deepcopy(src.cursor)
State.selection1 = deepcopy(src.selection)
patch(State.lines, event.after, event.before)
Text.redraw_all(State) -- if we're scrolling, reclaim all line caches to avoid memory leaks
schedule_save(State)
Editor.screen_top = deepcopy(src.screen_top)
Editor.cursor = deepcopy(src.cursor)
Editor.selection1 = deepcopy(src.selection)
patch(Editor.lines, event.after, event.before)
Text.redraw_all(Editor) -- if we're scrolling, reclaim all line caches to avoid memory leaks
schedule_save(Editor)
end
elseif chord == 'C-y' then
local event = redo_event(State)
local event = redo_event(Editor)
if event then
local src = event.after
State.screen_top = deepcopy(src.screen_top)
State.cursor = deepcopy(src.cursor)
State.selection1 = deepcopy(src.selection)
patch(State.lines, event.before, event.after)
Text.redraw_all(State) -- if we're scrolling, reclaim all line caches to avoid memory leaks
schedule_save(State)
Editor.screen_top = deepcopy(src.screen_top)
Editor.cursor = deepcopy(src.cursor)
Editor.selection1 = deepcopy(src.selection)
patch(Editor.lines, event.before, event.after)
Text.redraw_all(Editor) -- if we're scrolling, reclaim all line caches to avoid memory leaks
schedule_save(Editor)
end
-- clipboard
elseif chord == 'C-a' then
State.selection1 = {line=1, pos=1}
State.cursor = {mode='text', line=#State.lines, pos=utf8.len(State.lines[#State.lines].data)+1}
Editor.selection1 = {line=1, pos=1}
Editor.cursor = {mode='text', line=#Editor.lines, pos=utf8.len(Editor.lines[#Editor.lines].data)+1}
elseif chord == 'C-c' then
local s = Text.selection(State)
local s = Text.selection(Editor)
if s then
love.system.setClipboardText(s)
end
elseif chord == 'C-x' then
local s = Text.cut_selection(State, State.left, State.right)
local s = Text.cut_selection(Editor, Editor.left, Editor.right)
if s then
love.system.setClipboardText(s)
end
schedule_save(State)
schedule_save(Editor)
elseif chord == 'C-v' then
-- 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.
local before_line = State.cursor.line
local before = snapshot(State, before_line)
local before_line = Editor.cursor.line
local before = snapshot(Editor, before_line)
local clipboard_data = love.system.getClipboardText()
for _,code in utf8.codes(clipboard_data) do
local c = utf8.char(code)
if c == '\n' then
Text.insert_return(State)
Text.insert_return(Editor)
else
Text.insert_at_cursor(State, c)
Text.insert_at_cursor(Editor, c)
end
end
maybe_scroll(State)
record_undo_event(State, {before=before, after=snapshot(State, before_line, State.cursor.line)})
schedule_save(State)
maybe_scroll(Editor)
record_undo_event(Editor, {before=before, after=snapshot(Editor, before_line, Editor.cursor.line)})
schedule_save(Editor)
-- dispatch to drawing or text
elseif love.mouse.isDown(1) or chord:sub(1,2) == 'C-' then
if State.cursor.mode == 'drawing' then
local before = snapshot(State, State.cursor.line)
Drawing.keychord_press(State, chord)
record_undo_event(State, {before=before, after=snapshot(State, State.cursor.line)})
schedule_save(State)
if Editor.cursor.mode == 'drawing' then
local before = snapshot(Editor, Editor.cursor.line)
Drawing.keychord_press(Editor, chord)
record_undo_event(Editor, {before=before, after=snapshot(Editor, Editor.cursor.line)})
schedule_save(Editor)
end
elseif chord == 'escape' and not love.mouse.isDown(1) then
for _,line in ipairs(State.lines) do
for _,line in ipairs(Editor.lines) do
if line.mode == 'drawing' then
line.show_help = false
end
end
elseif State.cursor.mode == 'drawing' and State.current_drawing_mode == 'name' then
elseif Editor.cursor.mode == 'drawing' and Editor.current_drawing_mode == 'name' then
if chord == 'return' then
State.current_drawing_mode = State.previous_drawing_mode
State.previous_drawing_mode = nil
Editor.current_drawing_mode = Editor.previous_drawing_mode
Editor.previous_drawing_mode = nil
else
local before = snapshot(State, State.cursor.line)
local drawing = State.lines[State.cursor.line]
local before = snapshot(Editor, Editor.cursor.line)
local drawing = Editor.lines[Editor.cursor.line]
local p = drawing.points[drawing.pending.target_point]
if chord == 'escape' then
p.name = nil
record_undo_event(State, {before=before, after=snapshot(State, State.cursor.line)})
record_undo_event(Editor, {before=before, after=snapshot(Editor, Editor.cursor.line)})