No functionality yet, but its font size is independent of zoom.
I've pulled in all the commands from the previous driver, but they will require tuning for this repo. Lots of basic assumptions will differ.
GT3XZRTCVBWCSWUXAJ7N4OK2U2G5Y7EGSC5YE76KXZG7C4L53VTQC
OWBGSQM3PQWLWZ55GKXM6YA2B626GTCYKZTAUPQZ2F62KNFDJX2QC
MQMKQ2JO6E3KDJN3H6WACIETJI4C2APUS5N4YQZDM75ZIZDSC4XAC
OTIBCAUJ3KDQJLVDN3A536DLZGNRYMGJLORZVR3WLCGXGO6UGO6AC
RME4YP33NNUXA7HCHKUMB7UTNVGUCBDU3AZW3TDUTYL2CFZMNGOQC
36Z442IVPXHZ7D2QI26YLN3TDDEMDRQ2GKBYQAD6NUHQZVCCY4VAC
OI4FPFINEROK6GNDEMOBTGSPYIULCLRGGT5W3H7VLM7VFH22GMWQC
R6GUSTBY5ZHR7E46DSIDQDNZDJI6QMZQDC7RPQMQWLGWQKXU6HVQC
LRDM35CEK3OHXOTB7TEFJRL7P6PQWO5ZG3F2BVA7DIDFHBPJQ7KAC
R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC
-- This app has some limited capability to juggle multiple fonts. Mostly we
-- want to keep everything at a single font size at any time. However,
-- there's also a notion of a "heads-up display" that's overlaid atop the
-- app, whose font size is even more fixed.
HUD_font_height = 20
HUD_line_height = math.floor(HUD_font_height*1.3)
Menu_bar_height = 5 + HUD_line_height + 5
-- a few text objects we can avoid recomputing unless the font changes
Text_cache = {}
-- commonly used text objects
HUD_font = nil
HUD_text_cache = {} -- fixed font, never recomputed
Text_cache = {} -- recompute when default font changes
Menu_background_color = {r=0.6, g=0.8, b=0.6}
Menu_border_color = {r=0.6, g=0.7, b=0.6}
Menu_command_color = {r=0.2, g=0.2, b=0.2}
Menu_highlight_color = {r=0.5, g=0.7, b=0.3}
function draw_menu_bar()
if App.run_tests then return end -- disable in tests
App.color(Menu_background_color)
love.graphics.rectangle('fill', 0,0, App.screen.width, Menu_bar_height)
App.color(Menu_border_color)
love.graphics.rectangle('line', 0,0, App.screen.width, Menu_bar_height)
App.color(Menu_command_color)
Menu_cursor = 5
if Show_manifest_navigator then
draw_manifest_navigator()
return
end
add_hotkey_to_menu('ctrl+l: load definition')
add_hotkey_to_menu('ctrl+d: delete definition')
add_hotkey_to_menu('ctrl+f: find')
add_hotkey_to_menu('ctrl+left ctrl+right: prev/next word')
add_hotkey_to_menu('ctrl+z ctrl+y: undo/redo')
add_hotkey_to_menu('ctrl+x ctrl+c ctrl+v: cut/copy/paste')
add_hotkey_to_menu('ctrl+= ctrl+- ctrl+0: zoom')
end
function add_hotkey_to_menu(s)
local s_text = to_hud_text(s)
local width = App.width(s_text)
if Menu_cursor > App.screen.width - 30 then
return
end
App.color(Menu_command_color)
App.screen.draw(s_text, Menu_cursor,5)
Menu_cursor = Menu_cursor + width + 30
end
function load_from_iterator(f)
local result = {}
local i,line,drawing = 0, ''
while true do
local line = f()
if line == nil then break end
table.insert(result, {data=line})
end
if #result == 0 then
table.insert(result, {data=''})
end
return result
end
function draw_manifest_navigator()
App.color(Menu_command_color)
local filter_text = to_hud_text(Manifest_navigator.filter)
App.screen.draw(filter_text, 5, 5)
draw_cursor(5 + App.width(filter_text), 5)
if Manifest_navigator.num_lines == nil then
Manifest_navigator.num_lines = num_lines_for_manifest_navigator(Manifest_navigator.candidates)
end
App.color(Menu_background_color)
-- inefficient that we're computing this on every frame
-- so look only in the topmost line
local current_definition = live.get_cmd_from_buffer(Editor_state.lines[1].data)
love.graphics.rectangle('fill', 0,Menu_bar_height, App.screen.width, Manifest_navigator.num_lines * (Editor_state.line_height + --[[highlight padding]]5) + --[[extra highlight padding for bottom]] 2)
local x,y = 5, Menu_bar_height
for i,definition in ipairs(Manifest_navigator.candidates) do
if definition == current_definition then
if not Editor_state.saved then
definition = definition..'*'
end
else
if Cached_definitions[definition] and not Cached_definitions[definition].saved then
definition = definition..'*'
end
end
x,y = add_def_to_menu(x,y, definition, i == Manifest_navigator.index)
if Menu_cursor >= App.screen.width - 5 then
break
end
end
Manifest_navigator.bottom_y = y + Editor_state.line_height + --[[highlight padding]] 5
end
function draw_cursor(x, y)
-- blink every 0.5s
if math.floor(Cursor_time*2)%2 == 0 then
App.color(Cursor_color)
love.graphics.rectangle('fill', x,y, 3,Editor_state.line_height)
end
end
function manifest_navigator_candidates()
if Manifest_navigator.filter == '' then
return Manifest
end
local result = {}
for _,def in ipairs(Manifest) do
if starts_with(def, Manifest_navigator.filter) then
table.insert(result, def)
end
end
return result
end
function num_lines_for_manifest_navigator(candidates)
local result = 1
local x = 5
for i,def in ipairs(candidates) do
local width = App.width(to_hud_text(def))
if x + width > App.screen.width - 5 then
result = result+1
x = 5 + width
else
x = x + width + 30
end
end
return result
end
function add_def_to_menu(x,y, s, cursor_highlight)
local s_text = to_hud_text(s)
local width = App.width(s_text)
if x + width > App.screen.width - 5 then
y = y + Editor_state.line_height + --[[highlight padding]] 5
x = 5
end
local color = Menu_background_color
if cursor_highlight then
color = Menu_highlight_color
end
button(Editor_state, 'menu', {x=x-5, y=y-2, w=width+5*2, h=Editor_state.line_height+2*2, color=colortable(color),
onpress1 = function()
load_definition(s)
end
})
App.color(Menu_command_color)
App.screen.draw(s_text, x,y)
x = x + width + 30
return x,y
end
function reset_manifest_navigator()
Show_manifest_navigator = false
Manifest_navigator.index = 1
Manifest_navigator.filter = ''
Manifest_navigator.candidates = Manifest
Manifest_navigator.num_lines = num_lines_for_manifest_navigator(Manifest_navigator.candidates)
end
function keychord_press_on_manifest_navigator(chord, key)
if chord == 'escape' then
reset_manifest_navigator()
elseif chord == 'return' then
if Manifest_navigator.delete then
delete_definition(Manifest_navigator.candidates[Manifest_navigator.index])
else
load_definition(Manifest_navigator.candidates[Manifest_navigator.index])
end
elseif chord == 'backspace' then
local len = utf8.len(Manifest_navigator.filter)
local byte_offset = Text.offset(Manifest_navigator.filter, len)
Manifest_navigator.filter = string.sub(Manifest_navigator.filter, 1, byte_offset-1)
Manifest_navigator.index = 1
Manifest_navigator.candidates = manifest_navigator_candidates()
elseif chord == 'left' then
if Manifest_navigator.index > 1 then
Manifest_navigator.index = Manifest_navigator.index-1
end
elseif chord == 'right' then
if Manifest_navigator.index < #Manifest_navigator.candidates then
Manifest_navigator.index = Manifest_navigator.index+1
end
elseif chord == 'down' then
manifest_navigator_down()
elseif chord == 'up' then
manifest_navigator_up()
end
end
function load_definition(name)
-- save current buffer locally
local old_buffer = live.definition_to_string(Editor_state)
if old_buffer:find('%s*%S') then
local old_definition_name = live.get_cmd_from_buffer(old_buffer)
Cached_definitions[old_definition_name] = {saved=Editor_state.saved, data=old_buffer}
end
--
if old_definition_name == name then return end -- don't clobber unsaved data
move_candidate_to_front_of_manifest(name)
-- load new buffer
Editor_state = edit.initialize_state(Menu_bar_height + Margin_top, Margin_left+Line_number_width, App.screen.width-Margin_right)
local definition_string, saved
if Cached_definitions[name] == nil then
-- from app
definition_string, saved = get_definition_from_app(name), true
else
-- from local store
definition_string, saved = Cached_definitions[name].data, Cached_definitions[name].saved
end
Editor_state.lines = load_from_iterator(definition_string:gmatch("[^\r\n]+"))
Editor_state.saved = saved
Text.redraw_all(Editor_state)
Editor_state.font_height = Font_height
Editor_state.line_height = Line_height
Editor_state.em = em
reset_manifest_navigator()
end
function get_definition_from_app(name)
live.send_to_app('GET '..name)
local response_string
repeat
love.timer.sleep(0.01)
response_string = live.receive_from_app()
until response_string
return response_string
end
function move_candidate_to_front_of_manifest(name)
local index = array.find(Manifest, name)
if index then
table.remove(Manifest, index)
table.insert(Manifest, 1, name)
end
end
function delete_definition(name)
live.send_to_app('DELETE '..name)
Reload_manifest = true
reset_manifest_navigator()
end
function manifest_navigator_up()
local y, x, width = manifest_coord(Manifest_navigator.index)
local index = manifest_index(y-Editor_state.line_height, x, width)
if index then
Manifest_navigator.index = index
end
end
function manifest_navigator_down()
local y, x, width = manifest_coord(Manifest_navigator.index)
local index = manifest_index(y+Editor_state.line_height, x, width)
if index then
Manifest_navigator.index = index
end
end
function manifest_coord(index)
local y,x = Menu_bar_height, 5
for i,definition in ipairs(Manifest_navigator.candidates) do
local width = App.width(to_hud_text(definition))
if x + width > App.screen.width - 5 then
y = y + Editor_state.line_height
x = 5
end
if i == index then
return y, x, width
end
x = x + width + 30
end
end
function manifest_index(fy, fx, fwidth)
local y,x = Menu_bar_height, 5
local best_guess, best_guess_x, best_guess_width
for i,definition in ipairs(Manifest_navigator.candidates) do
local width = App.width(to_hud_text(definition))
if x + width > App.screen.width - 5 then
y = y + Editor_state.line_height
x = 5
end
if y == fy then
if best_guess == nil then
best_guess = i
best_guess_x = x
best_guess_width = width
elseif math.abs(fx + fwidth/2 - x - width/2) < math.abs(fx + fwidth/2 - best_guess_x - best_guess_width/2) then
best_guess = i
best_guess_x = x
best_guess_width = width
end
end
x = x + width + 30
end
return best_guess
end
function text_input_on_manifest_navigator(t)
Manifest_navigator.filter = Manifest_navigator.filter..t
Manifest_navigator.candidates = manifest_navigator_candidates()
Manifest_navigator.index = 1
end
on.draw = function()
love.graphics.setColor(1,0,0)
for _,obj in ipairs(Surface) do
love.graphics.setColor(obj.r or 0, obj.g or 0, obj.b or 0)
if obj.type == 'rectangle' then
love.graphics.rectangle(obj.drawmode or 'fill', vx(obj.x),vy(obj.y), scale(obj.w),scale(obj.h))
elseif obj.type == 'line' then
love.graphics.line(unpack(obj.zdata))
elseif obj.type == 'circle' then
love.graphics.circle(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radius))
elseif obj.type == 'arc' then
love.graphics.arc(obj.drawmode or 'line', obj.arctype or 'open', vx(obj.x), vy(obj.y), scale(obj.radius), obj.angle1, obj.angle2, obj.segments)
elseif obj.type == 'ellipse' then
love.graphics.ellipse(obj.drawmode or 'fill', vx(obj.x), vy(obj.y), scale(obj.radiusx), scale(obj.radiusy))
elseif obj.type == 'bezier' then
love.graphics.line(unpack(obj.zdata))
elseif obj.type == 'text' then
if obj.w == nil then
love.graphics.draw(obj.text, vx(obj.x), vy(obj.y))
else
edit.draw(obj.editor, obj.fg, not obj.show_cursor)
end
end
end
draw_menu_bar()
end
{"line_height":365,"y_of_schema1":364,"on":1,"Page":444,"Surface":422,"parent":451,"add_thick_line":400,"A":433,"copy_shape":396,"font":353,"on.mouse_release":367,"on.text_input":388,"Cursor_node":172,"box_height":345,"on.initialize":350,"Viewport":439,"B":379,"initialize_editor":450,"to_text":180,"on.draw":452,"vx":5,"vy":448,"compute_layout":385,"update_editor_box":451,"on.mouse_press":179,"schema1_of_y":366,"on.code_change":306,"on.update":368,"scale":7,"on.keychord_press":391}