start sketching out a scrollbar
Not quite ideal: the scrollbar computation only considers screen_bottom1.line and not screen_bottom1.pos, and so it always assumes the final line is at the bottom of the screen. I'm making a deeper change here that I might come to regret. I want to avoid creating new book-keeping for editor mutations, so I'm putting the work of computing scrollbar data into clear_screen_line_cache. But that implies the editor should never clear before updating data, and I caught one place that wasn't true before. A better name helps avoid this in future. Let's see how much toil this causes in resolving conflicts.
This commit is contained in:
parent
ff14bfd4ce
commit
3717d7868a
|
@ -3,6 +3,7 @@ on.draw = function()
|
|||
draw_editor_border()
|
||||
-- love.graphics.rectangle('line', 100-5-Line_number_padding,100-5, 300+Line_number_padding+10, 200+10, 5,5)
|
||||
edit.draw(Editor_state)
|
||||
draw_scrollbar(Editor_state)
|
||||
draw_output_border()
|
||||
draw_menu()
|
||||
end
|
|
@ -8,4 +8,4 @@ on.keychord_press = function(chord, key)
|
|||
else
|
||||
edit.keychord_press(Editor_state, chord, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
draw_scrollbar = function(Editor_state)
|
||||
App.color(Normal_color)
|
||||
love.graphics.line(Editor_state.right+30, Editor_state.top, Editor_state.right+30, Editor_state.bottom)
|
||||
love.graphics.line(Editor_state.right+25, Editor_state.top, Editor_state.right+35, Editor_state.top)
|
||||
love.graphics.line(Editor_state.right+25, Editor_state.bottom, Editor_state.right+35, Editor_state.bottom)
|
||||
local sbtop, sbbot = compute_scrollbar(Editor_state)
|
||||
local topy = Editor_state.top + sbtop*(Editor_state.bottom - Editor_state.top)
|
||||
local boty = Editor_state.top +sbbot*(Editor_state.bottom - Editor_state.top)
|
||||
App.color{r=0.6, g=0.6, b=0.8, a=0.5}
|
||||
love.graphics.rectangle('fill', Editor_state.right+20, topy, 20, boty-topy)
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
-- returns:
|
||||
-- * a float between 0 and 1 regarding the relative position of the top line on screen
|
||||
-- * a float between 0 and 1 regarding the relative position of the bottom line on screen
|
||||
compute_scrollbar = function(state)
|
||||
local top = state.line_cache[state.screen_top1.line].start_screen_line_index
|
||||
local bot = state.line_cache[state.screen_bottom1.line].start_screen_line_index
|
||||
return (top-1)/state.screen_line_count, bot/state.screen_line_count
|
||||
end
|
|
@ -13,6 +13,9 @@ Initializing settings:
|
|||
- where exactly the cursor is drawn to highlight a given character
|
||||
- analogously, how a shape precisely looks as you draw it
|
||||
|
||||
* Type out a wrapping line, select all using ctrl+a and delete. Editor does
|
||||
not crash.
|
||||
|
||||
### Protocol with driver; error-handling
|
||||
|
||||
* clone this repo to a new client app, clear its save dir[1], run it, run the
|
||||
|
|
1
edit.lua
1
edit.lua
|
@ -29,6 +29,7 @@ function edit.initialize_state(top, bottom, left, right, font_height, line_heigh
|
|||
-- starty, the y coord in pixels the line starts rendering from
|
||||
-- fragments: snippets of the line guaranteed to not straddle screen lines
|
||||
-- screen_line_starting_pos: optional array of grapheme indices if it wraps over more than one screen line
|
||||
-- start_screen_line_index: a count of the number of screen lines above this line
|
||||
line_cache = {},
|
||||
|
||||
-- Given wrapping, any potential location for the text cursor can be described in two ways:
|
||||
|
|
|
@ -117,12 +117,12 @@ function Text.delete_selection_without_undo(State)
|
|||
end
|
||||
State.selection1 = {}
|
||||
-- delete everything between min (inclusive) and max (exclusive)
|
||||
Text.clear_screen_line_cache(State, minl)
|
||||
local min_offset = Text.offset(State.lines[minl].data, minp)
|
||||
local max_offset = Text.offset(State.lines[maxl].data, maxp)
|
||||
if minl == maxl then
|
||||
--? print('minl == maxl')
|
||||
State.lines[minl].data = State.lines[minl].data:sub(1, min_offset-1)..State.lines[minl].data:sub(max_offset)
|
||||
Text.refresh_screen_line_cache(State, minl)
|
||||
return
|
||||
end
|
||||
assert(minl < maxl)
|
||||
|
@ -132,6 +132,7 @@ function Text.delete_selection_without_undo(State)
|
|||
table.remove(State.line_cache, i)
|
||||
end
|
||||
State.lines[minl].data = State.lines[minl].data:sub(1, min_offset-1)..rhs
|
||||
Text.refresh_screen_line_cache(State, minl)
|
||||
end
|
||||
|
||||
function Text.selection(State)
|
||||
|
|
40
text.lua
40
text.lua
|
@ -28,6 +28,7 @@ function Text.draw(State, line_index, y, startpos, fg, hide_cursor)
|
|||
-- render nothing
|
||||
else
|
||||
final_screen_line_starting_pos = pos
|
||||
--? print(i)
|
||||
local screen_line = Text.screen_line(line, line_cache, i)
|
||||
--? print('text.draw:', screen_line, 'at', line_index,pos, 'after', x,y)
|
||||
local frag_len = utf8.len(screen_line)
|
||||
|
@ -166,7 +167,7 @@ end
|
|||
function Text.insert_at_cursor(State, t)
|
||||
local byte_offset = Text.offset(State.lines[State.cursor1.line].data, State.cursor1.pos)
|
||||
State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_offset-1)..t..string.sub(State.lines[State.cursor1.line].data, byte_offset)
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
Text.refresh_screen_line_cache(State, State.cursor1.line)
|
||||
State.cursor1.pos = State.cursor1.pos+1
|
||||
end
|
||||
|
||||
|
@ -235,7 +236,7 @@ function Text.keychord_press(State, chord, readonly)
|
|||
}
|
||||
Text.redraw_all(State) -- if we're scrolling, reclaim all fragments to avoid memory leaks
|
||||
end
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
Text.refresh_screen_line_cache(State, State.cursor1.line)
|
||||
assert(Text.le1(State.screen_top1, State.cursor1))
|
||||
schedule_save(State)
|
||||
record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
|
||||
|
@ -268,7 +269,7 @@ function Text.keychord_press(State, chord, readonly)
|
|||
table.remove(State.lines, State.cursor1.line+1)
|
||||
table.remove(State.line_cache, State.cursor1.line+1)
|
||||
end
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
Text.refresh_screen_line_cache(State, State.cursor1.line)
|
||||
schedule_save(State)
|
||||
record_undo_event(State, {before=before, after=snapshot(State, State.cursor1.line)})
|
||||
end
|
||||
|
@ -363,7 +364,7 @@ function Text.insert_return(State)
|
|||
table.insert(State.lines, State.cursor1.line+1, {data=string.sub(State.lines[State.cursor1.line].data, byte_offset)})
|
||||
table.insert(State.line_cache, State.cursor1.line+1, {})
|
||||
State.lines[State.cursor1.line].data = string.sub(State.lines[State.cursor1.line].data, 1, byte_offset-1)
|
||||
Text.clear_screen_line_cache(State, State.cursor1.line)
|
||||
Text.refresh_screen_line_cache(State, State.cursor1.line)
|
||||
State.cursor1 = {line=State.cursor1.line+1, pos=1}
|
||||
end
|
||||
|
||||
|
@ -929,13 +930,42 @@ end
|
|||
function Text.redraw_all(State)
|
||||
--? print('clearing fragments')
|
||||
State.line_cache = {}
|
||||
local curr_screen_line_index = 1
|
||||
for i=1,#State.lines do
|
||||
State.line_cache[i] = {}
|
||||
State.line_cache[i].start_screen_line_index = curr_screen_line_index
|
||||
Text.populate_screen_line_starting_pos(State, i)
|
||||
curr_screen_line_index = curr_screen_line_index + #State.line_cache[i].screen_line_starting_pos
|
||||
end
|
||||
State.screen_line_count = curr_screen_line_index-1
|
||||
end
|
||||
|
||||
function Text.clear_screen_line_cache(State, line_index)
|
||||
function Text.refresh_scrollbar_data(State)
|
||||
--? print('clearing fragments')
|
||||
local curr_screen_line_index = 1
|
||||
local npopulated = 0
|
||||
for i=1,#State.lines do
|
||||
if State.line_cache[i] == nil then
|
||||
State.line_cache[i] = {}
|
||||
end
|
||||
if State.line_cache[i].screen_line_starting_pos == nil then
|
||||
--? print(('refresh_scrollbar_data: populating line %d'):format(i))
|
||||
Text.populate_screen_line_starting_pos(State, i)
|
||||
npopulated = npopulated+1
|
||||
end
|
||||
State.line_cache[i].start_screen_line_index = curr_screen_line_index
|
||||
curr_screen_line_index = curr_screen_line_index + #State.line_cache[i].screen_line_starting_pos
|
||||
end
|
||||
if npopulated > 1 then
|
||||
print(('refresh_scrollbar_data: had to populate %d lines'):format(npopulated))
|
||||
end
|
||||
State.screen_line_count = curr_screen_line_index-1
|
||||
end
|
||||
|
||||
function Text.refresh_screen_line_cache(State, line_index)
|
||||
State.line_cache[line_index].screen_line_starting_pos = nil
|
||||
Text.populate_screen_line_starting_pos(State, line_index)
|
||||
Text.refresh_scrollbar_data(State)
|
||||
end
|
||||
|
||||
function trim(s)
|
||||
|
|
Loading…
Reference in New Issue