From 222a11a8dd0c8b5b68b5628928a38f05d0a3d13c Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 17 May 2022 22:36:10 -0700 Subject: split keyboard handling between Text and Drawing --- drawing.lua | 165 +++++++++++++++++++++++++++++++++- geom.lua | 6 +- main.lua | 290 +----------------------------------------------------------- text.lua | 132 +++++++++++++++++++++++++++ 4 files changed, 302 insertions(+), 291 deletions(-) diff --git a/drawing.lua b/drawing.lua index 30182a2..9592587 100644 --- a/drawing.lua +++ b/drawing.lua @@ -49,6 +49,159 @@ function Drawing.draw(line, y) Drawing.draw_pending_shape(16,line.y, line) end +function Drawing.keychord_pressed(chord) + if chord == 'C-=' then + Drawing_width = Drawing_width/Zoom + Zoom = Zoom+0.5 + Drawing_width = Drawing_width*Zoom + elseif chord == 'C--' then + Drawing_width = Drawing_width/Zoom + Zoom = Zoom-0.5 + Drawing_width = Drawing_width*Zoom + elseif chord == 'C-0' then + Drawing_width = Drawing_width/Zoom + Zoom = 1.5 + Drawing_width = Drawing_width*Zoom + elseif chord == 'escape' and love.mouse.isDown('1') then + local drawing = Drawing.current_drawing() + drawing.pending = {} + elseif chord == 'C-f' and not love.mouse.isDown('1') then + Current_drawing_mode = 'freehand' + elseif chord == 'C-g' and not love.mouse.isDown('1') then + Current_drawing_mode = 'polygon' + elseif love.mouse.isDown('1') and chord == 'g' then + Current_drawing_mode = 'polygon' + local drawing = Drawing.current_drawing() + if drawing.pending.mode == 'freehand' then + drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)} + elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then + if drawing.pending.vertices == nil then + drawing.pending.vertices = {drawing.pending.p1} + end + elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then + drawing.pending.vertices = {drawing.pending.center} + end + drawing.pending.mode = 'polygon' + elseif love.mouse.isDown('1') and chord == 'p' and Current_drawing_mode == 'polygon' then + local drawing = Drawing.current_drawing() + local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y) + local j = Drawing.insert_point(drawing.points, mx,my) + table.insert(drawing.pending.vertices, j) + elseif chord == 'C-c' and not love.mouse.isDown('1') then + Current_drawing_mode = 'circle' + elseif love.mouse.isDown('1') and chord == 'a' and Current_drawing_mode == 'circle' then + local drawing = Drawing.current_drawing() + drawing.pending.mode = 'arc' + local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y) + local j = Drawing.insert_point(drawing.points, mx,my) + local center = drawing.points[drawing.pending.center] + drawing.pending.radius = 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 == 'c' then + Current_drawing_mode = 'circle' + local drawing = Drawing.current_drawing() + if drawing.pending.mode == 'freehand' then + drawing.pending.center = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) + elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then + drawing.pending.center = drawing.pending.p1 + elseif drawing.pending.mode == 'polygon' then + drawing.pending.center = drawing.pending.vertices[1] + end + drawing.pending.mode = 'circle' + elseif love.mouse.isDown('1') and chord == 'l' then + Current_drawing_mode = 'line' + local drawing = Drawing.current_drawing() + if drawing.pending.mode == 'freehand' then + drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) + elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then + drawing.pending.p1 = drawing.pending.center + elseif drawing.pending.mode == 'polygon' then + drawing.pending.p1 = drawing.pending.vertices[1] + end + drawing.pending.mode = 'line' + elseif chord == 'C-l' then + Current_drawing_mode = 'line' + local drawing,_,shape = Drawing.select_shape_at_mouse() + if drawing then + convert_line(drawing, shape) + end + elseif love.mouse.isDown('1') and chord == 'm' then + Current_drawing_mode = 'manhattan' + local drawing = Drawing.select_drawing_at_mouse() + if drawing.pending.mode == 'freehand' then + drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) + elseif drawing.pending.mode == 'line' then + -- do nothing + elseif drawing.pending.mode == 'polygon' then + drawing.pending.p1 = drawing.pending.vertices[1] + elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then + drawing.pending.p1 = drawing.pending.center + end + drawing.pending.mode = 'manhattan' + elseif chord == 'C-m' and not love.mouse.isDown('1') then + Current_drawing_mode = 'manhattan' + local drawing,_,shape = Drawing.select_shape_at_mouse() + if drawing then + convert_horvert(drawing, shape) + end + elseif chord == 'C-s' and not love.mouse.isDown('1') then + local drawing,_,shape = Drawing.select_shape_at_mouse() + if drawing then + smoothen(shape) + end + elseif chord == 'C-v' and not love.mouse.isDown('1') then + local drawing,_,p = Drawing.select_point_at_mouse() + if drawing then + Previous_drawing_mode = Current_drawing_mode + Current_drawing_mode = 'move' + drawing.pending = {mode=Current_drawing_mode, target_point=p} + Lines.current = drawing + end + elseif love.mouse.isDown('1') and chord == 'v' then + local drawing,_,p = Drawing.select_point_at_mouse() + if drawing then + Previous_drawing_mode = Current_drawing_mode + Current_drawing_mode = 'move' + drawing.pending = {mode=Current_drawing_mode, target_point=p} + Lines.current = drawing + end + elseif chord == 'C-d' and not love.mouse.isDown('1') then + local drawing,i,p = Drawing.select_point_at_mouse() + if drawing then + for _,shape in ipairs(drawing.shapes) do + if Drawing.contains_point(shape, i) then + if shape.mode == 'polygon' then + local idx = table.find(shape.vertices, i) + assert(idx) + table.remove(shape.vertices, idx) + if #shape.vertices < 3 then + shape.mode = 'deleted' + end + else + shape.mode = 'deleted' + end + end + end + drawing.points[i].deleted = true + end + local drawing,_,shape = Drawing.select_shape_at_mouse() + if drawing then + shape.mode = 'deleted' + end + elseif chord == 'C-h' and not love.mouse.isDown('1') then + local drawing = Drawing.select_drawing_at_mouse() + if drawing then + drawing.show_help = true + end + elseif chord == 'escape' and not love.mouse.isDown('1') then + for _,line in ipairs(Lines) do + if line.mode == 'drawing' then + line.show_help = false + end + end + end +end + function Drawing.current_drawing() local x, y = love.mouse.getX(), love.mouse.getY() for _,drawing in ipairs(Lines) do @@ -223,7 +376,7 @@ end function Drawing.draw_pending_shape(left,top, drawing) local shape = drawing.pending if shape.mode == 'freehand' then - draw_shape(left,top, drawing, shape) + Drawing.draw_shape(left,top, drawing, shape) elseif shape.mode == 'line' then local p1 = drawing.points[shape.p1] local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y) @@ -260,7 +413,7 @@ function Drawing.draw_pending_shape(left,top, drawing) return end local cx,cy = Drawing.pixels(center.x)+left, Drawing.pixels(center.y)+top - love.graphics.circle('line', cx,cy, math.dist(cx,cy, love.mouse.getX(),love.mouse.getY())) + love.graphics.circle('line', cx,cy, geom.dist(cx,cy, love.mouse.getX(),love.mouse.getY())) elseif shape.mode == 'arc' then local center = drawing.points[shape.center] local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y) @@ -280,4 +433,12 @@ function Drawing.coord(n) -- pixels to parts return math.floor(n*256/Drawing_width) end +function table.find(h, x) + for k,v in pairs(h) do + if v == x then + return k + end + end +end + return Drawing diff --git a/geom.lua b/geom.lua index 7b71df3..20cc5dd 100644 --- a/geom.lua +++ b/geom.lua @@ -11,10 +11,10 @@ function geom.on_shape(x,y, drawing, shape) return geom.on_polygon(x,y, drawing, shape) elseif shape.mode == 'circle' then local center = drawing.points[shape.center] - return math.dist(center.x,center.y, x,y) == shape.radius + return geom.dist(center.x,center.y, x,y) == shape.radius elseif shape.mode == 'arc' then local center = drawing.points[shape.center] - local dist = math.dist(center.x,center.y, x,y) + local dist = geom.dist(center.x,center.y, x,y) if dist < shape.radius*0.95 or dist > shape.radius*1.05 then return false end @@ -109,7 +109,7 @@ end -- is the line between x,y and cx,cy at an angle between s and e? function geom.angle_between(ox,oy, x,y, s,e) - local angle = math.angle(ox,oy, x,y) + local angle = geom.angle(ox,oy, x,y) if s > e then s,e = e,s end diff --git a/main.lua b/main.lua index 884a2cf..36ff345 100644 --- a/main.lua +++ b/main.lua @@ -245,295 +245,13 @@ function love.mousereleased(x,y, button) save_to_disk(Lines, Filename) end -function love.textinput(t) - if love.mouse.isDown('1') then return end - if Lines[Cursor_line].mode == 'drawing' then return end - local byte_offset - if Cursor_pos > 1 then - byte_offset = utf8.offset(Lines[Cursor_line].data, Cursor_pos-1) - else - byte_offset = 0 - end - Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_offset)..t..string.sub(Lines[Cursor_line].data, byte_offset+1) - Cursor_pos = Cursor_pos+1 - save_to_disk(Lines, Filename) -end - function keychord_pressed(chord) - -- Don't handle any keys here that would trigger love.textinput above. - -- shortcuts for text - if chord == 'return' then - local byte_offset = utf8.offset(Lines[Cursor_line].data, Cursor_pos) - table.insert(Lines, Cursor_line+1, {mode='text', data=string.sub(Lines[Cursor_line].data, byte_offset)}) - Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_offset-1) - Cursor_line = Cursor_line+1 - Cursor_pos = 1 - save_to_disk(Lines, Filename) - elseif chord == 'left' then - assert(Lines[Cursor_line].mode == 'text') - if Cursor_pos > 1 then - Cursor_pos = Cursor_pos-1 - else - local new_cursor_line = Cursor_line - while new_cursor_line > 1 do - new_cursor_line = new_cursor_line-1 - if Lines[new_cursor_line].mode == 'text' then - Cursor_line = new_cursor_line - Cursor_pos = #Lines[Cursor_line].data+1 - break - end - end - end - elseif chord == 'right' then - assert(Lines[Cursor_line].mode == 'text') - if Cursor_pos <= #Lines[Cursor_line].data then - Cursor_pos = Cursor_pos+1 - else - local new_cursor_line = Cursor_line - while new_cursor_line <= #Lines-1 do - new_cursor_line = new_cursor_line+1 - if Lines[new_cursor_line].mode == 'text' then - Cursor_line = new_cursor_line - Cursor_pos = 1 - break - end - end - end - elseif chord == 'home' then - Cursor_pos = 1 - elseif chord == 'end' then - Cursor_pos = #Lines[Cursor_line].data+1 - -- transitioning between drawings and text - elseif chord == 'backspace' then - if Cursor_pos > 1 then - local byte_start = utf8.offset(Lines[Cursor_line].data, Cursor_pos-1) - local byte_end = utf8.offset(Lines[Cursor_line].data, Cursor_pos) - if byte_start then - if byte_end then - Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1)..string.sub(Lines[Cursor_line].data, byte_end) - else - Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1) - end - Cursor_pos = Cursor_pos-1 - end - elseif Cursor_line > 1 then - if Lines[Cursor_line-1].mode == 'drawing' then - table.remove(Lines, Cursor_line-1) - else - -- join lines - Cursor_pos = utf8.len(Lines[Cursor_line-1].data)+1 - Lines[Cursor_line-1].data = Lines[Cursor_line-1].data..Lines[Cursor_line].data - table.remove(Lines, Cursor_line) - end - Cursor_line = Cursor_line-1 - end - save_to_disk(Lines, Filename) - elseif chord == 'delete' then - if Cursor_pos <= #Lines[Cursor_line].data then - local byte_start = utf8.offset(Lines[Cursor_line].data, Cursor_pos) - local byte_end = utf8.offset(Lines[Cursor_line].data, Cursor_pos+1) - if byte_start then - if byte_end then - Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1)..string.sub(Lines[Cursor_line].data, byte_end) - else - Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1) - end - -- no change to Cursor_pos - end - elseif Cursor_line < #Lines then - if Lines[Cursor_line+1].mode == 'drawing' then - table.remove(Lines, Cursor_line+1) - else - -- join lines - Lines[Cursor_line].data = Lines[Cursor_line].data..Lines[Cursor_line+1].data - table.remove(Lines, Cursor_line+1) - end - end - save_to_disk(Lines, Filename) - elseif chord == 'up' then - assert(Lines[Cursor_line].mode == 'text') - local new_cursor_line = Cursor_line - while new_cursor_line > 1 do - new_cursor_line = new_cursor_line-1 - if Lines[new_cursor_line].mode == 'text' then - local old_x = Text.cursor_x(Lines[new_cursor_line].data, Cursor_pos) - Cursor_line = new_cursor_line - Cursor_pos = Text.nearest_cursor_pos(Lines[Cursor_line].data, old_x, Cursor_pos) - break - end - end - elseif chord == 'down' then - assert(Lines[Cursor_line].mode == 'text') - local new_cursor_line = Cursor_line - while new_cursor_line < #Lines do - new_cursor_line = new_cursor_line+1 - if Lines[new_cursor_line].mode == 'text' then - local old_x = Text.cursor_x(Lines[new_cursor_line].data, Cursor_pos) - Cursor_line = new_cursor_line - Cursor_pos = Text.nearest_cursor_pos(Lines[Cursor_line].data, old_x, Cursor_pos) - break - end - end - elseif chord == 'C-=' then - Drawing_width = Drawing_width/Zoom - Zoom = Zoom+0.5 - Drawing_width = Drawing_width*Zoom - elseif chord == 'C--' then - Drawing_width = Drawing_width/Zoom - Zoom = Zoom-0.5 - Drawing_width = Drawing_width*Zoom - elseif chord == 'C-0' then - Drawing_width = Drawing_width/Zoom - Zoom = 1.5 - Drawing_width = Drawing_width*Zoom - -- shortcuts for drawings - elseif chord == 'escape' and love.mouse.isDown('1') then - local drawing = Drawing.current_drawing() - drawing.pending = {} - elseif chord == 'C-f' and not love.mouse.isDown('1') then - Current_drawing_mode = 'freehand' - elseif chord == 'C-g' and not love.mouse.isDown('1') then - Current_drawing_mode = 'polygon' - elseif love.mouse.isDown('1') and chord == 'g' then - Current_drawing_mode = 'polygon' - local drawing = Drawing.current_drawing() - if drawing.pending.mode == 'freehand' then - drawing.pending.vertices = {Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)} - elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then - if drawing.pending.vertices == nil then - drawing.pending.vertices = {drawing.pending.p1} - end - elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then - drawing.pending.vertices = {drawing.pending.center} - end - drawing.pending.mode = 'polygon' - elseif love.mouse.isDown('1') and chord == 'p' and Current_drawing_mode == 'polygon' then - local drawing = Drawing.current_drawing() - local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y) - local j = Drawing.insert_point(drawing.points, mx,my) - table.insert(drawing.pending.vertices, j) - elseif chord == 'C-c' and not love.mouse.isDown('1') then - Current_drawing_mode = 'circle' - elseif love.mouse.isDown('1') and chord == 'a' and Current_drawing_mode == 'circle' then - local drawing = Drawing.current_drawing() - drawing.pending.mode = 'arc' - local mx,my = Drawing.coord(love.mouse.getX()-16), Drawing.coord(love.mouse.getY()-drawing.y) - local j = Drawing.insert_point(drawing.points, mx,my) - local center = drawing.points[drawing.pending.center] - drawing.pending.radius = math.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 == 'c' then - Current_drawing_mode = 'circle' - local drawing = Drawing.current_drawing() - if drawing.pending.mode == 'freehand' then - drawing.pending.center = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) - elseif drawing.pending.mode == 'line' or drawing.pending.mode == 'manhattan' then - drawing.pending.center = drawing.pending.p1 - elseif drawing.pending.mode == 'polygon' then - drawing.pending.center = drawing.pending.vertices[1] - end - drawing.pending.mode = 'circle' - elseif love.mouse.isDown('1') and chord == 'l' then - Current_drawing_mode = 'line' - local drawing = Drawing.current_drawing() - if drawing.pending.mode == 'freehand' then - drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) - elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then - drawing.pending.p1 = drawing.pending.center - elseif drawing.pending.mode == 'polygon' then - drawing.pending.p1 = drawing.pending.vertices[1] - end - drawing.pending.mode = 'line' - elseif chord == 'C-l' then - Current_drawing_mode = 'line' - local drawing,_,shape = Drawing.select_shape_at_mouse() - if drawing then - convert_line(drawing, shape) - end - elseif love.mouse.isDown('1') and chord == 'm' then - Current_drawing_mode = 'manhattan' - local drawing = Drawing.select_drawing_at_mouse() - if drawing.pending.mode == 'freehand' then - drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y) - elseif drawing.pending.mode == 'line' then - -- do nothing - elseif drawing.pending.mode == 'polygon' then - drawing.pending.p1 = drawing.pending.vertices[1] - elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then - drawing.pending.p1 = drawing.pending.center - end - drawing.pending.mode = 'manhattan' - elseif chord == 'C-m' and not love.mouse.isDown('1') then - Current_drawing_mode = 'manhattan' - local drawing,_,shape = Drawing.select_shape_at_mouse() - if drawing then - convert_horvert(drawing, shape) - end - elseif chord == 'C-s' and not love.mouse.isDown('1') then - local drawing,_,shape = Drawing.select_shape_at_mouse() - if drawing then - smoothen(shape) - end - elseif chord == 'C-v' and not love.mouse.isDown('1') then - local drawing,_,p = Drawing.select_point_at_mouse() - if drawing then - Previous_drawing_mode = Current_drawing_mode - Current_drawing_mode = 'move' - drawing.pending = {mode=Current_drawing_mode, target_point=p} - Lines.current = drawing - end - elseif love.mouse.isDown('1') and chord == 'v' then - local drawing,_,p = Drawing.select_point_at_mouse() - if drawing then - Previous_drawing_mode = Current_drawing_mode - Current_drawing_mode = 'move' - drawing.pending = {mode=Current_drawing_mode, target_point=p} - Lines.current = drawing - end - elseif chord == 'C-d' and not love.mouse.isDown('1') then - local drawing,i,p = Drawing.select_point_at_mouse() - if drawing then - for _,shape in ipairs(drawing.shapes) do - if Drawing.contains_point(shape, i) then - if shape.mode == 'polygon' then - local idx = table.find(shape.vertices, i) - assert(idx) - table.remove(shape.vertices, idx) - if #shape.vertices < 3 then - shape.mode = 'deleted' - end - else - shape.mode = 'deleted' - end - end - end - drawing.points[i].deleted = true - end - local drawing,_,shape = Drawing.select_shape_at_mouse() - if drawing then - shape.mode = 'deleted' - end - elseif chord == 'C-h' and not love.mouse.isDown('1') then - local drawing = Drawing.select_drawing_at_mouse() - if drawing then - drawing.show_help = true - end - elseif chord == 'escape' and not love.mouse.isDown('1') then - for _,line in ipairs(Lines) do - if line.mode == 'drawing' then - line.show_help = false - end - end + if love.mouse.isDown('1') or chord:sub(1,2) == 'C-' then + Drawing.keychord_pressed(chord) + else + Text.keychord_pressed(chord) end end function love.keyreleased(key, scancode) end - -function table.find(h, x) - for k,v in pairs(h) do - if v == x then - return k - end - end -end diff --git a/text.lua b/text.lua index a9cfcbd..d46edca 100644 --- a/text.lua +++ b/text.lua @@ -1,6 +1,8 @@ -- primitives for editing text Text = {} +local utf8 = require 'utf8' + function Text.draw(line, line_index, cursor_line, y, cursor_pos) love.graphics.setColor(0,0,0) local love_text = love.graphics.newText(love.graphics.getFont(), line.data) @@ -11,6 +13,136 @@ function Text.draw(line, line_index, cursor_line, y, cursor_pos) end end +function love.textinput(t) + if love.mouse.isDown('1') then return end + if Lines[Cursor_line].mode == 'drawing' then return end + local byte_offset + if Cursor_pos > 1 then + byte_offset = utf8.offset(Lines[Cursor_line].data, Cursor_pos-1) + else + byte_offset = 0 + end + Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_offset)..t..string.sub(Lines[Cursor_line].data, byte_offset+1) + Cursor_pos = Cursor_pos+1 + save_to_disk(Lines, Filename) +end + +-- Don't handle any keys here that would trigger love.textinput above. +function Text.keychord_pressed(chord) + if chord == 'return' then + local byte_offset = utf8.offset(Lines[Cursor_line].data, Cursor_pos) + table.insert(Lines, Cursor_line+1, {mode='text', data=string.sub(Lines[Cursor_line].data, byte_offset)}) + Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_offset-1) + Cursor_line = Cursor_line+1 + Cursor_pos = 1 + save_to_disk(Lines, Filename) + elseif chord == 'left' then + assert(Lines[Cursor_line].mode == 'text') + if Cursor_pos > 1 then + Cursor_pos = Cursor_pos-1 + else + local new_cursor_line = Cursor_line + while new_cursor_line > 1 do + new_cursor_line = new_cursor_line-1 + if Lines[new_cursor_line].mode == 'text' then + Cursor_line = new_cursor_line + Cursor_pos = #Lines[Cursor_line].data+1 + break + end + end + end + elseif chord == 'right' then + assert(Lines[Cursor_line].mode == 'text') + if Cursor_pos <= #Lines[Cursor_line].data then + Cursor_pos = Cursor_pos+1 + else + local new_cursor_line = Cursor_line + while new_cursor_line <= #Lines-1 do + new_cursor_line = new_cursor_line+1 + if Lines[new_cursor_line].mode == 'text' then + Cursor_line = new_cursor_line + Cursor_pos = 1 + break + end + end + end + elseif chord == 'home' then + Cursor_pos = 1 + elseif chord == 'end' then + Cursor_pos = #Lines[Cursor_line].data+1 + elseif chord == 'backspace' then + if Cursor_pos > 1 then + local byte_start = utf8.offset(Lines[Cursor_line].data, Cursor_pos-1) + local byte_end = utf8.offset(Lines[Cursor_line].data, Cursor_pos) + if byte_start then + if byte_end then + Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1)..string.sub(Lines[Cursor_line].data, byte_end) + else + Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1) + end + Cursor_pos = Cursor_pos-1 + end + elseif Cursor_line > 1 then + if Lines[Cursor_line-1].mode == 'drawing' then + table.remove(Lines, Cursor_line-1) + else + -- join lines + Cursor_pos = utf8.len(Lines[Cursor_line-1].data)+1 + Lines[Cursor_line-1].data = Lines[Cursor_line-1].data..Lines[Cursor_line].data + table.remove(Lines, Cursor_line) + end + Cursor_line = Cursor_line-1 + end + save_to_disk(Lines, Filename) + elseif chord == 'delete' then + if Cursor_pos <= #Lines[Cursor_line].data then + local byte_start = utf8.offset(Lines[Cursor_line].data, Cursor_pos) + local byte_end = utf8.offset(Lines[Cursor_line].data, Cursor_pos+1) + if byte_start then + if byte_end then + Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1)..string.sub(Lines[Cursor_line].data, byte_end) + else + Lines[Cursor_line].data = string.sub(Lines[Cursor_line].data, 1, byte_start-1) + end + -- no change to Cursor_pos + end + elseif Cursor_line < #Lines then + if Lines[Cursor_line+1].mode == 'drawing' then + table.remove(Lines, Cursor_line+1) + else + -- join lines + Lines[Cursor_line].data = Lines[Cursor_line].data..Lines[Cursor_line+1].data + table.remove(Lines, Cursor_line+1) + end + end + save_to_disk(Lines, Filename) + elseif chord == 'up' then + assert(Lines[Cursor_line].mode == 'text') + local new_cursor_line = Cursor_line + while new_cursor_line > 1 do + new_cursor_line = new_cursor_line-1 + if Lines[new_cursor_line].mode == 'text' then + local old_x = Text.cursor_x(Lines[new_cursor_line].data, Cursor_pos) + Cursor_line = new_cursor_line + Cursor_pos = Text.nearest_cursor_pos(Lines[Cursor_line].data, old_x, Cursor_pos) + break + end + end + elseif chord == 'down' then + assert(Lines[Cursor_line].mode == 'text') + local new_cursor_line = Cursor_line + while new_cursor_line < #Lines do + new_cursor_line = new_cursor_line+1 + if Lines[new_cursor_line].mode == 'text' then + local old_x = Text.cursor_x(Lines[new_cursor_line].data, Cursor_pos) + Cursor_line = new_cursor_line + Cursor_pos = Text.nearest_cursor_pos(Lines[Cursor_line].data, old_x, Cursor_pos) + break + end + end + end +end + function Text.nearest_cursor_pos(line, x, hint) if x == 0 then return 1 -- cgit 1.4.1-2-gfad0