State, Editor_state -> Editor
This commit is contained in:
parent
4aa23aefef
commit
bf520b6e69
|
@ -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
|
||||
|
|
308
drawing.lua
308
drawing.lua
|
@ -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
444
edit.lua
|
@ -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)})
|
||||