data flow is starting to get more rigorous

On any event we might update the cursor pane's screen top (if it's
editable) or the viewport.

Updating the cursor pane's screen top will modify the viewport.

We then update all pane bounds based on the viewport.
Pane bounds include screen top. If that was updated already in the event
we skip it for that pane.

Still not perfect. Scrolling is jerky in the editable cursor pane.
This commit is contained in:
Kartik K. Agaram 2022-07-23 11:48:38 -07:00
parent 363d837606
commit e1d2e90cd9
3 changed files with 62 additions and 21 deletions

View File

@ -122,7 +122,14 @@ function edit.draw(State)
App.color(Text_color)
--? print(State.screen_top1.line, State.screen_top1.pos, State.cursor1.line, State.cursor1.pos)
assert(#State.lines == #State.line_cache)
assert(Text.le1(State.screen_top1, State.cursor1))
if State.show_cursor then
if not Text.le1(State.screen_top1, State.cursor1) then
print('assertion failure: cursor is above screen top')
print('screen top', State.screen_top1.line, State.screen_top1.pos)
print('cursor', State.cursor1.line, State.cursor1.pos)
assert(false)
end
end
State.cursor_y = -1
local y = State.top
--? print('== draw')

View File

@ -46,8 +46,7 @@ function App.initialize_globals()
Display_settings = {
mode=nil,
y=0,
x=0,
x=0, y=0, -- <==== Top-left corner of the viewport into the surface
column_width=400,
palette='',
palette_text=App.newText(love.graphics.getFont(), ''),
@ -129,6 +128,8 @@ function App.initialize(arg)
table.insert(column, initialize_pane_with_placeholder_coordinates('foo'))
table.insert(Surface, column)
update_pane_bounds()
if rawget(_G, 'jit') then
jit.off()
jit.flush()
@ -149,9 +150,9 @@ function initialize_window_geometry()
end
function App.resize(w, h)
Surface.dirty = true
App.screen.width, App.screen.height = w, h
Last_resize_time = App.getTime()
update_pane_bounds()
end
function initialize_file(file)
@ -190,6 +191,38 @@ function initialize_pane_with_placeholder_coordinates(id)
return result
end
function update_pane_bounds(options)
local sx = Padding_horizontal + Margin_left
for column_index, column in ipairs(Surface) do
if overlap(sx, sx+Display_settings.column_width, Display_settings.x, Display_settings.x + App.screen.width) then
local sy = Margin_top
for pane_index, pane in ipairs(column) do
if overlap(sy, sy + Margin_above + Cache[pane.id].height + Margin_below, Display_settings.y, Display_settings.y + App.screen.height) then
if column_index == Cursor_pane.col and pane_index == Cursor_pane.row then
-- update the cursor pane either if it's not editable, or
-- if it was explicitly requested
if not pane.show_cursor or options == nil or not options.ignore_editable_cursor_pane then
if sy < Display_settings.y then
pane.screen_top1 = schema1_of_y(pane, Display_settings.y - Margin_top)
else
pane.screen_top1 = {line=1, pos=1}
end
end
end
--? print(('%d,%d: adjusting pane top %d; screen_top is at line %d (max %d)'):format(column_index, pane_index, pane.top, pane.screen_top1.line, #pane.lines))
pane.top = sy - Display_settings.y + Margin_above
--? print(('pane top is %d'):format(pane.top))
pane.left = sx - Display_settings.x
pane.right = pane.left + Display_settings.column_width
pane.width = pane.right - pane.left
end
sy = sy + Margin_above + Cache[pane.id].height + Margin_below + Padding_vertical
end
end
sx = sx + Margin_right + Display_settings.column_width + Padding_horizontal + Margin_left
end
end
-- Since the editor deals with potentially changing data, it tries to maintain
-- just a screen's worth of screen-line data.
-- Since the larger note-taking app mostly deals with read-only data, it
@ -203,27 +236,14 @@ end
function App.draw()
Button_handlers = {}
-- top > Margin_top or Screen_top.line > 1
local sx = Padding_horizontal + Margin_left
--? if Surface.dirty then
--? print(('draw from surface y of %d'):format(Display_settings.y))
--? end
for column_index, column in ipairs(Surface) do
if overlap(sx, sx+Display_settings.column_width, Display_settings.x, Display_settings.x + App.screen.width) then
--? print('draw column')
local sy = Margin_top
for pane_index, pane in ipairs(column) do
if overlap(sy, sy + Margin_above + Cache[pane.id].height + Margin_below, Display_settings.y, Display_settings.y + App.screen.height) then
--? print('draw pane')
if Surface.dirty then
--? print(('%d,%d: adjusting pane top %d; screen_top is at line %d (max %d)'):format(column_index, pane_index, pane.top, pane.screen_top1.line, #pane.lines))
pane.top = sy - Display_settings.y + Margin_above
--? print(('pane top is %d'):format(pane.top))
pane.left = sx - Display_settings.x
pane.right = pane.left + Display_settings.column_width
pane.width = pane.right - pane.left
end
--? print(column_index, pane_index, pane.cursor1.line, pane.cursor1.pos, pane.selection1.line, pane.selection1.pos)
--? print('draw pane', column_index, pane_index, pane.cursor1.line, pane.cursor1.pos, pane.selection1.line, pane.selection1.pos)
edit.draw(pane)
if column_index == Cursor_pane.col and pane_index == Cursor_pane.row then
App.color(Cursor_pane_background_color)
@ -245,7 +265,6 @@ function App.draw()
if Display_settings.mode == 'palette' then
draw_command_palette()
end
Surface.dirty = false
end
function overlap(lo1,hi1, lo2,hi2)
@ -297,7 +316,7 @@ function App.update(dt)
edit.update(pane, dt)
end
if App.mouse_down(1) then
Surface.dirty = true
update_pane_bounds()
end
end
@ -425,7 +444,6 @@ end
function App.keychord_pressed(chord, key)
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
Surface.dirty = true
if Display_settings.mode == nil then
handle_normal_mode_keychord(chord, key)
elseif Display_settings.mode == 'palette' then
@ -434,6 +452,8 @@ function App.keychord_pressed(chord, key)
print(Display_settings.mode)
assert(false)
end
-- editable cursor pane will have already updated its screen_top, so don't clobber it here
update_pane_bounds{ignore_editable_cursor_pane=true}
end
function handle_command_palette_keychord(chord, key)
@ -633,6 +653,19 @@ end
-- - let loc, y_offset = schema1_of_y(pane, y)
-- y - y_offset == y_of_schema1(pane, loc)
function schema1_of_y(pane, y)
local y_offset = y
local line,pos_index = 1,1
Text.populate_screen_line_starting_pos(pane, line)
while y_offset >= Line_height do
pos_index = pos_index + 1
if pos_index > #pane.line_cache[line].screen_line_starting_pos then
line = line+1
pos_index = 1
Text.populate_screen_line_starting_pos(pane, line)
end
y_offset = y_offset - Line_height
end
return {line=line, pos=pane.line_cache[line].screen_line_starting_pos[pos_index]}, y_offset
end
function line_height(State, line_index, left, right)

View File

@ -936,6 +936,7 @@ function Text.populate_screen_line_starting_pos(State, line_index)
local frag, frag_text = f.data, f.text
-- render fragment
local frag_width = App.width(frag_text)
--? print('', '', frag, 'comparing', x, frag_width, State.right)
if x + frag_width > State.right then
x = State.left
table.insert(line_cache.screen_line_starting_pos, pos)