H2KZUAWHQXTRUFDPDH4AUG6EP3OR5U3GGFPVGTCY2XJB3WOEO7TQC
GUC42UKF6E736AB63KKLZ67VGO4CA422A6ECFU3ZX676XCHLNJUAC
BP42JEWWJTJBVEMHQHRA7EP5NHFGDM2N7MAEEA426X24AIFEPQSAC
TEY2M55SZ72OVJ6263EYWFXBHHMR7GPGBNNOGBFIOQPGGHAXSMJQC
GIRNP3AO4J4U6ROFJTRHU4UNBPBNK5GIQMW73CYJCTNW6QCZRVWAC
BBUGJKNA5HKOOX6KH5CGRVWJ76E2HPFLXGCTWSQZYRCP3KPXEBEAC
K6ZDYZKXSLTLCCHWYK6K6WOCNXBZOXEDKDVNNJVCZUFOLLSUO5UAC
R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC
PPVABNGQTQMPYILHDNSNXBI5IOCBSIYO45NIHUR4LYPABQZE6PAQC
25UHVUGNT3ANOGCQLL6GG6NNV4SLWLAMPME45JHWLLC2KK4GJO2QC
V2R4643AZLA2QHR6C6ADAOOQXK5ZKZCR4NMKWPPZHMYTOIOIYJDAC
HNXNAK7AIBISKZTTBA3RGXWXMS6UMM5656EK7EGQQIMNCUZRV3DAC
QDN3KO6L3ILGTUUVTJGQ2BF4AXAIQYAXJNPOGCG7CYLDNJAJVADQC
GE5W6MDN57RSM7XW5WZGTH7PP3ADB25QD2UY6R7WAANZPFOKF76AC
IYJ2W4KLBV65OP73D5SMFOMTDH2NDDK2REXRKXAWBCVJPWMXT4PQC
TBPJ5WSRM5IKQH7FTAVYTWWUBWW7G2CLT5M6FN7CMPLD6Y77YIWQC
TTMMK6S6ILBQ6YN6H2DR5I5PH4ZUITWAGG72AJWLKLKGO5AATT2AC
N5J7ZUXO45VS6GANQ4UWQTXMMQGSPRNDG4C2MG4NYVIZX5XMEB7AC
365TKW44IOQWIHK5LF4YXKM446QM5DCY4AF7DWK2O7LETPXZOIEAC
43JQEFRZ5SSMEOFHUGGB6NFJ5ZESGG27YZ3QU6AJQ7D3FK543MRQC
OCEUBINPW3PZBKNQKZBZH2CHZ3YOWTHQETPS2544IOCV76CDEOYAC
V2DSGKQSRTM72CG7TJSBYB3XOGVYNGWIUWKMW5GMJQJRAIF2WLZQC
4TL2FLYP36JS4K6QBXZBCFCTIBMIT7OAF7KMAAFGPAF5OWSP4QFAC
OLCKKDVSDTIBX5U3IRCLRL6KQMG2RDWKGDN4OTPI3WMN4FSX6ROQC
NP3LZH44LOWL2RPT7MOXWX5HJADZRFT7YFZKXSTEQ4JMFQDZPE7QC
5QTU3ODSGFLRWALAUDR27QYRB6UVDZD3Y3UJMZXISEFA7TRDI6BAC
NEKDLX527DBB62P6OYFMSYAMTLRHNBRDNXNEVFT6UR4JLNOJXWKQC
6AJGWL32GZFO5CSSNKXMI24SB27I65K6LQDWWX5WVL5Z7ES4VUUQC
O5F2HG2RYJ4L623VRQBXXJHTMTEAO3ZSUJYY3L7ECVD63TYVKO6AC
2S2CK2OMHYTYFRDHPXEZTWPF4CVUPR6VTNZIOVMUQVYIGM2PLXIQC
HMH2GYB6BLH4HE7N6J6ZK57RKFICWXSU3KJL7EGYTXJ5DC5XHBIQC
YVMVWYMCOOJPFUZRKSDMNDNY66OMJ47E3DVGSQAJ26SVPDCEKHMAC
LRDM35CEK3OHXOTB7TEFJRL7P6PQWO5ZG3F2BVA7DIDFHBPJQ7KAC
TLFRUXVL6JC3E5EGO3COZ2EBYTOL23A6SYKID7PT6HC7GJY3SKLAC
GDBDGLRHJSMN527PHXGZVSGF55EYT4X3GFNF4LF6363JE2FGBQXQC
FS2ITYYHBLFT66YUC3ENPFYI2HOYHOVEPQIN7NQR6KF5MEK4NKZAC
PH6I237WRZLPA3Q3RHWITJNGIXI42PRSIQ6R5JJ6CXNTGQ3VIICAC
EZHO4TSWIYYUE73S6XQWIEF3HA3H7MKCNJOT27NTWTVSPVS2SL5QC
2DVVKKVA6PJ7VKYLGPQ22AXUB6ZWFMPWB445PRDZJDNLURUFDNDQC
XQZO4DUY3GDV2W6JNWDKCVIDGX7YBIONJC2V3BQEQY7XCIXREBEAC
D4FEFHQCSILZFQ5VLWNXAIRZNUMCDNGJSM4UJ6T6FDMMIWYRYILQC
F3NPUCCMFNMXVD2XJ5FMJ5M5FP3XICQHJRD6WFNB6OUK6LBL2TXQC
E6APMVLDASF7PNTSFYKTNOJJUUQPOZN66AVYHEA4PMLYMA4THYCQC
JIBCE66ZTWM5WEHEHNKKTRWBJQSQWBDDWPMOJIJR5Q676OSHYCNAC
BF7TW3EKRIDYC6J2Q2J4YOBAVQF55Y3H6KGZIHNXMH4N72MR6GXQC
ZQMQVMFWZIGWBRCB455IKHPTAOUYPLYCSC44NBPPET557RGVRX3AC
FBDRJ53NJ5BWDQGU2GWZ6NEYHKCCRD7RODMIG7QQZBRFUB4HR7OAC
J4UN4JK4DGKXKNB65JNAHYZDYP4TKRNFFDZLUAVK7SLFIQYHIFEQC
X7HYGAL2QVKG7M5EMZ2VSH37UYWGE3EPUXYQBJOVL6IGJFZ2I5AAC
4WW67KAXORLJFOJVWV3CP4VNHTEIJY5WQMSDMXMFKRWSI5EEHTRAC
DXFOMHQIWZ6EAUIDZQLY3ZRRDWJRB2VQHJXHBBNXQYCYCABIMJ5QC
XCEP7G5GRX6WQGCROJDNZRTLSITGAETL7EFCFTR74S36VXK32HBQC
Page2 = {
x=500, y=300,
-- page
type='text',
data={
"Call me Ishmael. Some years ago--never mind how long precisely--having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off--then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me."
},
width=400, bg={r=0,g=0.8,b=0}
}
A = function(preserve_screen_top_of_cursor_node)
-- translate Page to Surface
while #Surface > 3 do table.remove(Surface) end -- HACK
local red = false
for x=-1000,2000,300 do
for y=-10000,10000,200 do
add_thick_line({type='line', data={x,y, x+200,y+200, x,y+400}, r=red and 1 or 0,g=red and 0 or 0.5,b=0}, 10)
red = not red
end
end
compute_layout(Page, Page.x,Page.y, Surface, preserve_screen_top_of_cursor_node)
compute_layout(Page2, Page2.x,Page2.y, Surface, preserve_screen_top_of_cursor_node)
-- continue the pipeline
B(preserve_screen_top_of_cursor_node)
-- TODO: ugly that we're manipulating editor objects twice
end
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url)
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url)
Cursor_node = Nodes[node_id]
else
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
end
end
on.initialize = function(arg)
Input_filename = arg[1]
A(Input_filename)
Cursor_node = Root
if #arg >= 1 then
if #arg >= 2 then
local initial_id = arg[2]
if Nodes[initial_id] then
Cursor_node = Nodes[initial_id]
end
end
ensure_cursor_node_within_viewport()
end
end
on.initialize = function(arg)
Input_filename = arg[1]
A(Input_filename)
Cursor_node = Root
if #arg >= 2 then
local initial_id = arg[2]
if Nodes[initial_id] then
Cursor_node = Nodes[initial_id]
end
end
ensure_cursor_node_within_viewport()
end
on.initialize = function(arg)
if #arg == 0 then
error('Please pass in a file containing a Mastodon thread, and optionally an id within it to start out focused on.\n\nThis app currently needs to be invoked from a terminal.')
end
Input_filename = arg[1]
A(Input_filename)
Cursor_node = Root
if #arg >= 1 then
if #arg >= 2 then
local initial_id = arg[2]
if Nodes[initial_id] then
Cursor_node = Nodes[initial_id]
end
end
ensure_cursor_node_within_viewport()
end
end
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
if curr.children == nil or #curr.children == 0 then
return xlo
end
if #curr.children == 1 then
return xposition(Nodes[curr.children[1]], xlo, xhi)
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#curr.children-1 do
local child_id = curr.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local centerx = total_boundaries / (#curr.children-1)
return centerx - 620/2
end
compute_layout = function(node, x,y, nodes_to_render, preserve_screen_top_of_cursor_node)
-- append to nodes_to_render flattened instructions to render a hierarchy of nodes
-- return x,y rendered until (surface coordinates)
if node.type == 'text' then
-- leaf node containing raw text
node.x = x
node.y = y
-- render background if necessary
local node_to_render
if node.bg then
node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
table.insert(nodes_to_render, node_to_render)
end
-- render contents
if node.width then
node.w = node.width
else
node.w = 0
for i,s in ipairs(node.data) do
local text = love.graphics.newText(font(20), node.data)
local width = text:getWidth()
if node.w < width then node.w = width end
end
end
if node.editor == nil then
initialize_editor(node)
else
update_editor_box(node, preserve_screen_top_of_cursor_node)
end
node.h = box_height(node)
table.insert(nodes_to_render, node)
if node_to_render then
node_to_render.w = node.w
node_to_render.h = node.h
end
elseif node.type == 'rows' then
node.x = x
node.y = y
local node_to_render
if node.bg then
node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
table.insert(nodes_to_render, node_to_render)
end
-- lay out children top to bottom
local subx,suby = x,y
local w,h = 0,0
local subnodes
for _,child in ipairs(node.data) do
if child.margin then
suby = suby+child.margin
h = h+child.margin
end
if not child.width then
child.width = node.width -- HACK: should we set child.w or child.width? Neither is quite satisfactory.
end
subx,suby = compute_layout(child, x,suby, nodes_to_render)
if w < child.w then
w = child.w
end
h = h+child.h
end
node.w = w
node.h = h
if node_to_render then
node_to_render.w = w
node_to_render.h = h
end
elseif node.type == 'cols' then
node.x = x
node.y = y
-- lay out children left to right
local node_to_render
if node.bg then
node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
table.insert(nodes_to_render, node_to_render)
end
local subx,suby = x,y
local w,h = 0,0
for _,child in ipairs(node.data) do
if child.margin then
subx = subx+child.margin
w = w+child.margin
end
subx,suby = compute_layout(child, subx,y, nodes_to_render)
w = w + child.w
if h < child.h then
h = child.h
end
end
node.w = w
node.h = h
if node_to_render then
node_to_render.w = w
node_to_render.h = h
end
end
return x+node.w,y+node.h
end
Page = {
-- page
type='cols', x=0, y=0,
width=800, data={
-- editor covering left side
{
type='text',
name='editor',
doc='prose goes here, on the left half of the window',
margin=Margin_left,
data={
"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
'1',
'2',
'3',
'mno',
'Acb',
'g',
'hij',
'klm',
'nop',
},
width=400, bg={r=1,g=1,b=0}
},
-- a table on the right
{ type='rows', name='searches', margin=50, data={
{ type='text', data={''},},
{ type='cols', data={
{ type='text', data={'search:'},},
{ type='text', name='search', bg={r=0.8,g=0.8,b=0.8}, data={''}, width=90,},
}},
{ type='text', data={'table:'},},
{ type='cols', bg={r=0.8,g=0.8,b=0.8}, data={
{ type='rows', width=90, data={
{type='text', data={'abc'},},
{type='text', data={'abc'},},
}},
{ type='rows', width=90, data={
{type='text', data={'def'},},
{type='text', data={'def'},},
}},
}},
}},
},
}
{"box_height":345,"compute_layout":385,"ntracks":505,"B":379,"compute_ntracks":519,"Input_filename":436,"Surface":588,"on.draw":418,"vx":5,"Viewport":303,"on.text_input":587,"initialize_editor":338,"render_thread_to_surface":583,"dehtml":456,"on.mouse_press":585,"add_thick_line":400,"on.mouse_release":586,"copy_shape":396,"on.update":368,"to_text":180,"on.keychord_press":584,"load_from_iterator":463,"split_lines":469,"on.code_change":578,"scale":7,"A":582,"vy":8,"Cursor_node":172,"font":353,"add_edge":575,"y_of_schema1":364,"schema1_of_y":366,"update_editor_box":430,"line_height":365,"add_node":576,"fw_parent":587,"on":1,"fw_app":"mastodon-luaML","render_node_and_descendants":579,"on.initialize":446}
{"initialize_editor":338,"A":582,"to_text":180,"on.text_input":587,"split_lines":469,"B":379,"scale":7,"ensure_cursor_node_within_viewport":643,"add_node":650,"on.mouse_press":618,"Viewport":303,"render_node_and_descendants":646,"Cursor_node":172,"header":651,"add_thick_line":400,"box_height":345,"copy_shape":396,"compute_layout":619,"add_edge":575,"Root":654,"on.code_change":578,"Nodes":593,"Input_filename":436,"font":353,"update_editor_box":430,"fw_parent":657,"vx":5,"fw_app":"mastodon-unfurl","on.update":368,"to_node":611,"on.keychord_press":644,"vy":8,"load_from_iterator":463,"ntracks":600,"schema1_of_y":366,"y_of_schema1":364,"on.initialize":657,"render_thread_to_surface":655,"on.draw":632,"on.mouse_release":586,"dehtml":658,"compute_ntracks":598,"Surface":588,"line_height":365,"on":1}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":663,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":662,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"Surface":588,"Input_filename":436,"to_text":180,"on.draw":632,"line_height":365,"ensure_cursor_node_within_viewport":643,"initialize_editor":338,"ntracks":600,"on.text_input":587,"on.mouse_press":618,"render_thread_to_surface":655,"on.mouse_release":586,"dehtml":663,"Nodes":593,"Root":654,"copy_shape":396,"A":582,"B":666,"load_from_iterator":463,"to_node":611,"add_thick_line":400,"vx":5,"on.keychord_press":644,"fw_app":"mastodon-unfurl","on.initialize":665,"scale":7,"compute_layout":619,"compute_ntracks":598,"update_editor_box":430,"vy":8,"header":651,"on":1,"schema1_of_y":366,"add_node":650,"on.update":368,"box_height":345,"y_of_schema1":364,"render_node_and_descendants":646,"Cursor_node":172,"split_lines":469,"on.code_change":578,"add_edge":575,"Viewport":303,"fw_parent":665,"font":353}
{"compute_ntracks":598,"render_thread_to_surface":655,"on.initialize":665,"A":582,"dehtml":663,"B":666,"fw_app":"mastodon-unfurl","scale":7,"compute_layout":619,"add_edge":575,"vx":5,"load_from_iterator":463,"vy":8,"add_thick_line":400,"Surface":588,"copy_shape":396,"on.draw":632,"Cursor_node":172,"add_node":650,"on.text_input":587,"on.mouse_press":618,"render_node_and_descendants":646,"on.mouse_release":586,"update_editor_box":430,"on.update":368,"font":353,"on.keychord_press":644,"fw_parent":666,"Viewport":303,"on.code_change":578,"on":1,"split_lines":469,"Input_filename":436,"box_height":667,"line_height":365,"schema1_of_y":366,"header":651,"y_of_schema1":364,"Root":654,"initialize_editor":338,"to_node":611,"ensure_cursor_node_within_viewport":643,"Nodes":593,"ntracks":600,"to_text":180}
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":578,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":576,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":577,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":577,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":612,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":611,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"schema1_of_y":366,"box_height":667,"to_node":611,"compute_layout":619,"dehtml":663,"on.text_input":587,"A":582,"add_edge":575,"B":666,"Surface":588,"on.draw":632,"Viewport":303,"ntracks":600,"split_lines":469,"scale":7,"font":353,"vy":8,"on.mouse_release":586,"initialize_editor":338,"on.update":368,"to_text":180,"on.keychord_press":644,"add_node":650,"Cursor_node":172,"add_thick_line":400,"on":1,"render_node_and_descendants":670,"render_thread_to_surface":655,"compute_ntracks":598,"ensure_cursor_node_within_viewport":643,"fw_parent":675,"Input_filename":436,"on.mouse_press":676,"load_from_iterator":463,"on.code_change":578,"header":651,"update_editor_box":430,"line_height":365,"copy_shape":396,"vx":5,"fw_app":"mastodon-unfurl","Nodes":593,"Root":654,"y_of_schema1":364,"xposition":675,"on.initialize":665}
{"split_lines":469,"on.initialize":664,"A":582,"on.mouse_release":586,"initialize_editor":338,"on.update":368,"on.keychord_press":644,"dehtml":663,"add_thick_line":400,"line_height":365,"ensure_cursor_node_within_viewport":643,"on":1,"ntracks":600,"Cursor_node":172,"copy_shape":396,"scale":7,"Root":654,"fw_parent":663,"font":353,"on.mouse_press":618,"to_text":180,"schema1_of_y":366,"box_height":345,"B":379,"compute_layout":619,"y_of_schema1":364,"fw_app":"mastodon-unfurl","on.code_change":578,"Nodes":593,"add_node":650,"Viewport":303,"update_editor_box":430,"render_thread_to_surface":655,"vy":8,"Surface":588,"on.text_input":587,"header":651,"on.draw":632,"vx":5,"Input_filename":436,"to_node":611,"load_from_iterator":463,"add_edge":575,"compute_ntracks":598,"render_node_and_descendants":646}
print('code changed')
A() -- just in case we edited Page
end
on.code_change = function()
dehtml = function(s)
return s:gsub('<p>', '\n\n')
:gsub('<br>', '\n')
:gsub('<br/>', '\n')
-- hacky
:gsub('<[^>]*>', '')
:gsub(''', "'")
:gsub(''', "'")
:gsub('"', '"')
:gsub('“', '"')
:gsub('”', '"')
:gsub('<', '<')
:gsub('>', '>')
:gsub('&', '&')
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"copy_shape":396,"Surface":588,"on.draw":632,"add_node":650,"to_node":611,"render_node_and_descendants":646,"vy":8,"add_edge":575,"update_editor_box":430,"on.mouse_press":618,"box_height":345,"on.mouse_release":586,"line_height":365,"on.code_change":578,"Input_filename":436,"on.keychord_press":644,"schema1_of_y":366,"initialize_editor":338,"on.initialize":657,"y_of_schema1":364,"A":582,"ntracks":600,"compute_ntracks":598,"B":379,"render_thread_to_surface":655,"dehtml":456,"on":1,"on.text_input":587,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"scale":7,"to_text":180,"load_from_iterator":463,"compute_layout":619,"header":651,"Viewport":303,"vx":5,"fw_parent":656,"font":353,"split_lines":469,"Nodes":593,"Root":654,"on.update":368,"add_thick_line":400,"Cursor_node":172}
to_node = function(x,y)
for _,node in ipairs(Surface) do
if node.type == 'text' then
if x >= vx(node.x) and node.w and x < vx(node.x + node.w) then
if y >= vy(node.y) and node.h and y < vy(node.y + node.h) then
return node.toot_id
end
end
end
end
end
{"dehtml":663,"schema1_of_y":366,"Viewport":303,"Cursor_node":172,"y_of_schema1":364,"on.initialize":665,"line_height":365,"A":582,"on.text_input":587,"split_lines":469,"B":379,"on.mouse_press":618,"initialize_editor":338,"on.update":368,"fw_parent":664,"box_height":345,"fw_app":"mastodon-unfurl","add_node":650,"render_node_and_descendants":646,"ensure_cursor_node_within_viewport":643,"add_thick_line":400,"to_text":180,"copy_shape":396,"scale":7,"add_edge":575,"load_from_iterator":463,"Root":654,"font":353,"Input_filename":436,"Nodes":593,"on.mouse_release":586,"vx":5,"on.draw":632,"on.keychord_press":644,"header":651,"Surface":588,"vy":8,"update_editor_box":430,"ntracks":600,"render_thread_to_surface":655,"compute_ntracks":598,"to_node":611,"compute_layout":619,"on":1,"on.code_change":578}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
parent.surface_node = add_node(xlo, y, parent.content, parent.id, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
parent.surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent.surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
ensure_cursor_node_within_viewport()
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
ensure_cursor_node_within_viewport()
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
ensure_cursor_node_within_viewport()
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
ensure_cursor_node_within_viewport()
end
end
end
end
end
{"xposition":675,"on.mouse_press":618,"on.draw":632,"box_height":667,"line_height":365,"compute_layout":619,"Viewport":303,"dehtml":663,"update_editor_box":430,"Nodes":593,"vx":5,"on.text_input":587,"on.mouse_release":586,"schema1_of_y":366,"on.update":368,"on.keychord_press":644,"split_lines":469,"to_node":611,"y_of_schema1":364,"A":582,"add_node":650,"scale":7,"render_node_and_descendants":670,"initialize_editor":338,"add_edge":575,"ensure_cursor_node_within_viewport":643,"font":353,"Surface":588,"vy":8,"on.initialize":665,"to_text":180,"B":666,"fw_app":"mastodon-unfurl","Cursor_node":172,"Root":654,"add_thick_line":400,"ntracks":600,"copy_shape":396,"compute_ntracks":598,"fw_parent":674,"on.code_change":578,"load_from_iterator":463,"Input_filename":436,"header":651,"render_thread_to_surface":655,"on":1}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
N_edges = 2
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
box_height = function(node)
-- return the height of a node. The result is scaled.
local y = 0
for i=1,#node.editor.lines do
local line = node.editor.lines[i]
if node.editor.line_cache[i] == nil then
node.editor.line_cache[i] = {}
end
node.editor.line_cache[i].fragments = nil
node.editor.line_cache[i].screen_line_starting_pos = nil
Text.populate_screen_line_starting_pos(node.editor, i)
y = y + node.editor.line_height*#node.editor.line_cache[i].screen_line_starting_pos
Text.clear_screen_line_cache(node.editor, i)
end
-- font size never changes in this app
return y/Viewport.zoom
end
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":585,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":586,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":587,"on.mouse_release":586,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
B = function(preserve_screen_top_of_cursor_node)
-- recompute various aspects based on the current viewport settings
for _,obj in ipairs(Surface) do
if obj.type == 'line' then
obj.zdata = {}
for i=1,#obj.data,2 do
table.insert(obj.zdata, vx(obj.data[i]))
table.insert(obj.zdata, vy(obj.data[i+1]))
end
elseif obj.type == 'bezier' then
zdata = {}
for i=1,#obj.data,2 do
table.insert(zdata, vx(obj.data[i]))
table.insert(zdata, vy(obj.data[i+1]))
end
obj.zdata = love.math.newBezierCurve(zdata):render()
elseif obj.type == 'text' then
if obj.w then
update_editor_box(obj, preserve_screen_top_of_cursor_node)
else
obj.text = love.graphics.newText(love.graphics.getFont(), obj.data)
end
end
end
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
if Cursor_node.surface_node.y < Viewport.y then
Viewport.y = Cursor_node.surface_node.y - 50
B()
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
local snode = Cursor_node.surface_node
local limit = snode.y + box_height(snode)
if Viewport.y < limit - App.screen.height/Viewport.zoom then
Viewport.y = limit - (App.screen.height-50)/Viewport.zoom
B()
end
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
if Cursor_node.surface_node.x < Viewport.x then
Viewport.x = Cursor_node.surface_node.x - 50
B()
end
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
local snode = Cursor_node.surface_node
local limit = snode.x + 600
if Viewport.x < limit - App.screen.width/Viewport.zoom then
Viewport.x = limit - (App.screen.width-50)/Viewport.zoom
B()
end
end
end
end
end
end
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":662,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":661,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":631,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":630,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":610,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
print(curr.id, curr.children)
if #curr.children == 0 then
return xlo
end
if #curr.children == 1 then
return xposition(Nodes[curr.children[1]], xlo, xhi)
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#curr.children-1 do
local child_id = curr.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local centerx = total_boundaries / (#curr.children-1)
return centerx - 620/2
end
{"render_node_and_descendants":633,"compute_layout":619,"schema1_of_y":366,"render_thread_to_surface":626,"y_of_schema1":364,"dehtml":456,"Surface":588,"line_height":365,"on.draw":632,"load_from_iterator":463,"box_height":345,"on":1,"Viewport":303,"vx":5,"update_editor_box":430,"on.keychord_press":631,"Input_filename":436,"on.mouse_press":618,"add_thick_line":400,"on.mouse_release":586,"on.initialize":446,"on.text_input":587,"on.code_change":578,"fw_app":"mastodon-luaML","compute_ntracks":598,"Cursor_node":172,"fw_parent":632,"add_edge":575,"Nodes":593,"split_lines":469,"A":582,"to_text":180,"vy":8,"copy_shape":396,"scale":7,"add_node":590,"ntracks":600,"B":379,"initialize_editor":338,"on.update":368,"to_node":611,"font":353}
{"Surface":588,"vy":8,"on.draw":632,"Nodes":593,"add_node":590,"Viewport":303,"on.mouse_release":586,"on.initialize":446,"Input_filename":436,"on":1,"dehtml":456,"line_height":365,"ensure_cursor_node_within_viewport":643,"load_from_iterator":463,"add_edge":575,"compute_ntracks":598,"compute_layout":619,"render_thread_to_surface":626,"copy_shape":396,"on.keychord_press":644,"render_node_and_descendants":633,"Cursor_node":172,"add_thick_line":400,"ntracks":600,"update_editor_box":430,"scale":7,"y_of_schema1":364,"on.text_input":587,"on.update":368,"fw_parent":643,"initialize_editor":338,"schema1_of_y":366,"to_text":180,"box_height":345,"A":582,"font":353,"to_node":611,"fw_app":"mastodon-unfurl","on.code_change":578,"split_lines":469,"B":379,"on.mouse_press":618,"vx":5}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":655,"on.initialize":656,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"Root":654,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":655,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
{"compute_ntracks":519,"render_thread_to_surface":583,"Cursor_node":172,"dehtml":456,"add_thick_line":400,"copy_shape":396,"on.draw":418,"on.code_change":578,"A":582,"add_edge":575,"vy":8,"B":379,"font":353,"fw_app":"mastodon-luaML","on.mouse_release":367,"on.update":368,"to_text":180,"on.keychord_press":391,"schema1_of_y":366,"add_node":576,"y_of_schema1":364,"render_node_and_descendants":579,"scale":7,"vx":5,"on.initialize":446,"on.text_input":388,"Viewport":303,"Input_filename":436,"Surface":434,"on":1,"compute_layout":385,"box_height":345,"fw_parent":582,"load_from_iterator":463,"split_lines":469,"line_height":365,"on.mouse_press":179,"initialize_editor":338,"ntracks":505,"update_editor_box":430}
dehtml = function(s)
return s:gsub('<p>', '\n\n')
:gsub('<br>', '\n')
:gsub('<br/>', '\n')
:gsub('<[^>]*>', '')
:gsub(''', "'")
:gsub(''', "'")
:gsub('"', '"')
:gsub('“', '"')
:gsub('”', '"')
:gsub('<', '<')
:gsub('>', '>')
:gsub('&', '&')
end
to_node = function(x,y)
for _,node in ipairs(Surface) do
if node.type == 'text' then
if x >= vx(node.x) and node.w and x < vx(node.x + node.w) then
if y >= vy(node.y) and node.h and y < vy(node.y + node.h) then
print('bb', node.toot_id)
return node.toot_id
end
end
end
end
end
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":585,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":585,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":388,"on.mouse_release":586,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
on.mouse_press = function(x,y, mouse_button)
local node = to_text(x,y)
if node then
-- TODO: copy node's url
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":641,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":642,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
end
end
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":673,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":674,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":473,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":576,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":576,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":577,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
{"compute_ntracks":519,"render_thread_to_surface":571,"Cursor_node":172,"dehtml":456,"add_thick_line":400,"copy_shape":396,"on.draw":418,"on.code_change":578,"A":582,"add_edge":575,"vy":8,"B":379,"font":353,"fw_app":"mastodon-luaML","on.mouse_release":367,"on.update":368,"to_text":180,"on.keychord_press":391,"schema1_of_y":366,"add_node":576,"y_of_schema1":364,"render_node_and_descendants":579,"scale":7,"vx":5,"on.initialize":446,"on.text_input":388,"Viewport":303,"Input_filename":436,"Surface":434,"on":1,"compute_layout":385,"box_height":345,"fw_parent":581,"load_from_iterator":463,"split_lines":469,"line_height":365,"on.mouse_press":179,"initialize_editor":338,"ntracks":505,"update_editor_box":430}
{"Surface":588,"vy":8,"on.draw":632,"Nodes":593,"add_node":590,"Viewport":303,"on.mouse_release":586,"on.initialize":446,"Input_filename":436,"on":1,"dehtml":456,"line_height":365,"ensure_cursor_node_within_viewport":643,"load_from_iterator":463,"add_edge":575,"compute_ntracks":598,"compute_layout":619,"render_thread_to_surface":626,"copy_shape":396,"on.keychord_press":642,"render_node_and_descendants":633,"Cursor_node":172,"add_thick_line":400,"ntracks":600,"update_editor_box":430,"scale":7,"y_of_schema1":364,"on.text_input":587,"on.update":368,"fw_parent":642,"initialize_editor":338,"schema1_of_y":366,"to_text":180,"box_height":345,"A":582,"font":353,"to_node":611,"fw_app":"mastodon-unfurl","on.code_change":578,"split_lines":469,"B":379,"on.mouse_press":618,"vx":5}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":610,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":609,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":661,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":660,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
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
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.7, 0.7, 0, 0.4)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":585,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":584,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":388,"on.mouse_release":367,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
to_node = function(x,y)
for _,node in ipairs(Surface) do
if node.type == 'text' then
if x >= vx(node.x) and node.w and x < vx(node.x + node.w) then
if y >= vy(node.y) and node.h and y < vy(node.y + node.h) then
print('bb', node.id)
return node.id
end
end
end
end
end
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
print(curr.id, curr.children, #curr.children)
if #curr.children == 0 then
return xlo
end
if #curr.children == 1 then
return xposition(Nodes[curr.children[1]], xlo, xhi)
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#curr.children-1 do
local child_id = curr.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local centerx = total_boundaries / (#curr.children-1)
return centerx - 620/2
end
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":630,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":629,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
Root = thread_data
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= Root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(Root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * Root.ntracks)
end
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":473,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":576,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":575,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":565,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
end
end
ensure_cursor_node_within_viewport = function()
local snode = Cursor_node.surface_node
local dirty
-- check Viewport.y
if snode.y < Viewport.y then
Viewport.y = snode.y - 50
dirty = true
end
local limit = snode.y + box_height(snode)
if Viewport.y < limit - App.screen.height/Viewport.zoom then
Viewport.y = limit - (App.screen.height-50)/Viewport.zoom
dirty = true
end
-- check Viewport.x
if Cursor_node.surface_node.x < Viewport.x then
Viewport.x = Cursor_node.surface_node.x - 50
dirty = true
end
limit = snode.x + 600
if Viewport.x < limit - App.screen.width/Viewport.zoom then
Viewport.x = limit - (App.screen.width-50)/Viewport.zoom
dirty = true
end
-- refresh if necessary
if dirty then
B()
end
end
{"compute_ntracks":519,"render_thread_to_surface":571,"Cursor_node":172,"dehtml":456,"add_thick_line":400,"copy_shape":396,"on.draw":418,"on.code_change":578,"A":581,"add_edge":575,"vy":8,"B":379,"font":353,"fw_app":"mastodon-luaML","on.mouse_release":367,"on.update":368,"to_text":180,"on.keychord_press":391,"schema1_of_y":366,"add_node":576,"y_of_schema1":364,"render_node_and_descendants":579,"scale":7,"vx":5,"on.initialize":446,"on.text_input":388,"Viewport":303,"Input_filename":436,"Surface":434,"on":1,"compute_layout":385,"box_height":345,"fw_parent":580,"load_from_iterator":463,"split_lines":469,"line_height":365,"on.mouse_press":179,"initialize_editor":338,"ntracks":505,"update_editor_box":430}
add_node = function(x, y, text, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
{"render_node_and_descendants":614,"compute_layout":619,"schema1_of_y":366,"render_thread_to_surface":626,"y_of_schema1":364,"dehtml":456,"Surface":588,"line_height":365,"on.draw":632,"load_from_iterator":463,"box_height":345,"on":1,"Viewport":303,"vx":5,"update_editor_box":430,"on.keychord_press":631,"Input_filename":436,"on.mouse_press":618,"add_thick_line":400,"on.mouse_release":586,"on.initialize":446,"on.text_input":587,"on.code_change":578,"fw_app":"mastodon-luaML","compute_ntracks":598,"Cursor_node":172,"fw_parent":631,"add_edge":575,"Nodes":593,"split_lines":469,"A":582,"to_text":180,"vy":8,"copy_shape":396,"scale":7,"add_node":590,"ntracks":600,"B":379,"initialize_editor":338,"on.update":368,"to_node":611,"font":353}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":660,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":659,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":609,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":608,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
end
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
if Cursor_node.surface_node.y < Viewport.y then
Viewport.y = Cursor_node.surface_node.y - 50
B()
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
local snode = Cursor_node.surface_node
local limit = snode.y + box_height(snode)
if Viewport.y < limit - App.screen.height/Viewport.zoom then
Viewport.y = limit - (App.screen.height-50)/Viewport.zoom
B()
end
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
if Cursor_node.surface_node.x < Viewport.x then
Viewport.x = Cursor_node.surface_node.x - 50
B()
end
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"box_height":345,"compute_layout":385,"Input_filename":436,"on":1,"Surface":434,"on.draw":418,"vx":5,"schema1_of_y":366,"Viewport":303,"dehtml":456,"on.initialize":446,"y_of_schema1":364,"A":582,"to_text":180,"on.mouse_press":179,"on.code_change":578,"initialize_editor":338,"on.update":368,"on.keychord_press":584,"load_from_iterator":463,"fw_parent":583,"split_lines":469,"fw_app":"mastodon-luaML","font":353,"Cursor_node":172,"update_editor_box":430,"ntracks":505,"line_height":365,"copy_shape":396,"on.text_input":388,"on.mouse_release":367,"compute_ntracks":519,"add_node":576,"vy":8,"render_thread_to_surface":583,"add_thick_line":400,"render_node_and_descendants":579,"scale":7,"B":379,"add_edge":575}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":672,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":673,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":655,"on.initialize":446,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"Root":654,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":654,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
to_node = function(x,y)
for _,node in ipairs(Surface) do
if node.type == 'text' then
if x >= vx(node.x) and node.w and x < vx(node.x + node.w) then
if y >= vy(node.y) and node.h and y < vy(node.y + node.h) then
print('bb')
return node.id
end
end
end
end
end
{"font":353,"add_thick_line":400,"compute_ntracks":519,"Cursor_node":172,"Input_filename":436,"on.text_input":388,"ntracks":505,"box_height":345,"Surface":434,"compute_layout":385,"line_height":365,"on.code_change":473,"dehtml":456,"Viewport":303,"schema1_of_y":366,"add_node":574,"initialize_editor":338,"on.initialize":446,"to_text":180,"A":474,"load_from_iterator":463,"B":379,"fw_parent":574,"on.draw":418,"fw_app":"mastodon-luaML","on.mouse_press":179,"render_node_and_descendants":565,"scale":7,"vx":5,"y_of_schema1":364,"split_lines":469,"vy":8,"copy_shape":396,"add_edge":575,"render_thread_to_surface":571,"on":1,"on.mouse_release":367,"update_editor_box":430,"on.update":368,"on.keychord_press":391}
{"render_node_and_descendants":579,"add_edge":575,"initialize_editor":338,"Input_filename":436,"add_thick_line":400,"copy_shape":396,"box_height":345,"compute_layout":385,"on.code_change":578,"ntracks":505,"compute_ntracks":519,"render_thread_to_surface":571,"Surface":434,"dehtml":456,"on.draw":418,"to_text":180,"line_height":365,"vy":8,"fw_parent":579,"load_from_iterator":463,"fw_app":"mastodon-luaML","on.mouse_press":179,"y_of_schema1":364,"A":580,"font":353,"on.update":368,"split_lines":469,"B":379,"on.keychord_press":391,"update_editor_box":430,"on.mouse_release":367,"on":1,"Viewport":303,"scale":7,"Cursor_node":172,"on.text_input":388,"on.initialize":446,"add_node":576,"vx":5,"schema1_of_y":366}
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":629,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":628,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
if #curr.children == 0 then
return xlo
end
if #curr.children == 1 then
return xposition(Nodes[curr.children[1]], xlo, xhi)
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#curr.children-1 do
local child_id = curr.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local centerx = total_boundaries / (#curr.children-1)
return centerx - 620/2
end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":640,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":641,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on":1,"font":353,"y_of_schema1":364,"ensure_cursor_node_within_viewport":643,"header":651,"split_lines":469,"add_thick_line":400,"copy_shape":396,"Nodes":593,"Root":654,"initialize_editor":338,"box_height":345,"vx":5,"on.code_change":578,"render_node_and_descendants":646,"to_node":611,"fw_app":"mastodon-unfurl","Surface":588,"to_text":180,"line_height":365,"add_edge":575,"on.draw":632,"compute_ntracks":598,"dehtml":659,"on.mouse_release":586,"Viewport":303,"scale":7,"render_thread_to_surface":655,"on.initialize":657,"Cursor_node":172,"schema1_of_y":366,"ntracks":600,"load_from_iterator":463,"on.mouse_press":618,"on.text_input":587,"compute_layout":619,"fw_parent":658,"update_editor_box":430,"A":582,"on.keychord_press":644,"on.update":368,"add_node":650,"Input_filename":436,"B":379,"vy":8}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":608,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":607,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":653,"on.initialize":446,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"Root":654,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":653,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
end
end
end
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
print('aa', node_id, Nodes[node_id].url)
App.setClipboardText(Nodes[node_id].url)
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":573,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":574,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":573,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":671,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":672,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":628,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":627,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
add_node = function(x, y, text, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then -- and N_edges > 0 then
add_edge(surface_node, parent_surface_node)
N_edges = N_edges - 1
end
return surface_node
end
{"vy":8,"y_of_schema1":364,"A":582,"to_node":604,"on.mouse_press":607,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":606,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
if #curr.children <= 1 then
return xlo
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#curr.children-1 do
local child_id = curr.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local centerx = total_boundaries / (#curr.children-1)
return centerx - 620/2
end
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url)
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
if Cursor_node.surface_node.y < Viewport.y then
Viewport.y = Cursor_node.surface_node.y - 50
B()
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
local snode = Cursor_node.surface_node
local limit = snode.y + box_height(snode)
if Viewport.y < limit - App.screen.height/Viewport.zoom then
Viewport.y = limit - (App.screen.height-50)/Viewport.zoom
B()
end
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":572,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":573,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"render_node_and_descendants":579,"add_edge":575,"initialize_editor":338,"Input_filename":436,"add_thick_line":400,"copy_shape":396,"box_height":345,"compute_layout":385,"on.code_change":578,"ntracks":505,"compute_ntracks":519,"render_thread_to_surface":571,"Surface":434,"dehtml":456,"on.draw":418,"to_text":180,"line_height":365,"vy":8,"fw_parent":578,"load_from_iterator":463,"fw_app":"mastodon-luaML","on.mouse_press":179,"y_of_schema1":364,"A":474,"font":353,"on.update":368,"split_lines":469,"B":379,"on.keychord_press":391,"update_editor_box":430,"on.mouse_release":367,"on":1,"Viewport":303,"scale":7,"Cursor_node":172,"on.text_input":388,"on.initialize":446,"add_node":576,"vx":5,"schema1_of_y":366}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":670,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":671,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
add_edge = function(node, parent)
print('add edge', node.x, node.y, parent.x, parent.y)
local line = {
type='line',
data={
parent.x + 600/2, parent.y + box_height(parent),
node.x + 600/2, node.y,
},
}
print('add edge 2', line.data[2], line.data[4])
table.insert(Surface, line)
end
{"fw_parent":604,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":606,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"Surface":588,"line_height":365,"on.mouse_release":586,"to_text":180,"to_node":604,"render_thread_to_surface":602,"y_of_schema1":364,"schema1_of_y":366,"ntracks":600,"compute_layout":385,"on.code_change":578,"Cursor_node":172,"A":582,"on.initialize":446,"on":1,"on.keychord_press":584,"initialize_editor":338,"on.draw":418,"B":379,"box_height":345}
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
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.7, 0.7, 0, 0.4)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":639,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":640,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"Input_filename":436,"on.update":368,"scale":7,"on.keychord_press":644,"render_thread_to_surface":653,"on.initialize":446,"dehtml":456,"add_thick_line":400,"line_height":365,"initialize_editor":338,"copy_shape":396,"header":651,"load_from_iterator":463,"ntracks":600,"Nodes":593,"compute_ntracks":598,"split_lines":469,"on.text_input":587,"ensure_cursor_node_within_viewport":643,"on.code_change":578,"vy":8,"Surface":588,"Cursor_node":172,"update_editor_box":430,"to_node":611,"fw_parent":652,"B":379,"fw_app":"mastodon-unfurl","add_node":650,"on.draw":632,"A":582,"to_text":180,"render_node_and_descendants":646,"y_of_schema1":364,"vx":5,"Viewport":303,"box_height":345,"schema1_of_y":366,"compute_layout":619,"font":353,"on":1,"on.mouse_press":618,"add_edge":575,"on.mouse_release":586}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":571,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":572,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
parent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)
return
end
local parent_xlo = xposition(parent, xlo, xhi)
parent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node)
local parent_height = box_height(parent.surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"on.code_change":578,"line_height":365,"add_thick_line":400,"Surface":588,"on.keychord_press":584,"ntracks":600,"on.mouse_press":618,"A":582,"on.mouse_release":586,"on.text_input":587,"scale":7,"Nodes":593,"on":1,"schema1_of_y":366,"font":353,"to_node":611,"y_of_schema1":364,"add_edge":575,"on.draw":627,"render_thread_to_surface":626,"B":379,"box_height":345,"on.update":368,"dehtml":456,"copy_shape":396,"add_node":590,"Input_filename":436,"vy":8,"compute_layout":619,"Viewport":303,"load_from_iterator":463,"split_lines":469,"to_text":180,"on.initialize":446,"Cursor_node":172,"compute_ntracks":598,"fw_app":"mastodon-luaML","update_editor_box":430,"fw_parent":626,"initialize_editor":338,"vx":5,"render_node_and_descendants":614}
{"fw_parent":604,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":605,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"to_node":604,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
add_edge = function(node, parent)
print('add edge', node.x, node.y, parent.x, parent.y)
local line = {
type='line',
data={
parent.x + 600/2, parent.y + box_height(node),
node.x + 600/2, node.y,
},
}
print('add edge 2', line.data[2], line.data[4])
table.insert(Surface, line)
end
to_node = function(x,y)
for _,node in ipairs(Surface) do
if node.type == 'text' then
if x >= vx(node.x) and node.w and x < vx(node.x + node.w) then
if y >= vy(node.y) and node.h and y < vy(node.y + node.h) then
return node.id
end
end
end
end
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
if Cursor_node.surface_node.y < Viewport.y then
Viewport.y = Cursor_node.surface_node.y - 50
B()
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
local snode = Cursor_node.surface_node
local limit = snode.y + box_height(snode)
if Viewport.y < limit - App.screen.height/Viewport.zoom then
Viewport.y = limit - (App.screen.height-50)/Viewport.zoom
end
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":669,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":670,"xposition":669,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"fw_parent":603,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"to_node":604,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
if #node.children <= 1 then
return xlo
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
return parent_x - 620/2
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
Cursor_node = root
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
N_edges = 2
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":638,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":639,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":668,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":646,"xposition":669,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":625,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":625,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":626,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":571,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":570,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, parent.id, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
xposition = function(nodes, curr, xlo, xhi)
-- return the left margin to position a node at
if #node.children <= 1 then
return xlo
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
return parent_x - 620/2
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
if Cursor_node.surface_node.y < Viewport.y then
Viewport.y = Cursor_node.surface_node.y - 50
B()
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"fw_parent":602,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":603,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
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
print(obj.text_node)
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.7, 0.7, 0, 0.4)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"box_height":667,"B":666,"compute_layout":619,"ntracks":600,"on.code_change":578,"add_thick_line":400,"render_thread_to_surface":655,"dehtml":663,"on":1,"update_editor_box":430,"load_from_iterator":463,"fw_parent":667,"on.mouse_release":586,"split_lines":469,"on.update":368,"Surface":588,"on.keychord_press":644,"to_text":180,"ensure_cursor_node_within_viewport":643,"Nodes":593,"y_of_schema1":364,"to_node":611,"header":651,"initialize_editor":338,"Root":654,"add_node":650,"schema1_of_y":366,"Viewport":303,"copy_shape":396,"render_node_and_descendants":646,"xposition":668,"line_height":365,"vx":5,"Cursor_node":172,"scale":7,"on.mouse_press":618,"add_edge":575,"fw_app":"mastodon-unfurl","compute_ntracks":598,"on.draw":632,"Input_filename":436,"on.text_input":587,"on.initialize":665,"vy":8,"A":582,"font":353}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
N_edges = 1
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":637,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":638,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":624,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":625,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":570,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":569,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
print(Cursor_node.surface_node.y, Viewport.y)
if Cursor_node.surface_node.y < Viewport.y then
Viewport.y = Cursor_node.surface_node.y - 50
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"fw_parent":601,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":601,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":602,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
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
print(obj.text_node)
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.7, 0.7, 0, 0.1)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
N_edges = 2
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":636,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":637,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":623,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":624,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":569,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":568,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, parent.id, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(Nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
for k in pairs(Cursor_node) do
print(k)
end
print(Cursor_node.y, Viewport.y)
if Cursor_node.y < Viewport.y then
Viewport.y = Cursor_node.y - 50
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":567,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":567,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":568,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
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
print(obj.text_node)
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(1, 1, 0.4)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"fw_parent":600,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":601,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
add_node = function(x, y, text, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node and N_edges > 0 then
add_edge(surface_node, parent_surface_node)
N_edges = N_edges - 1
end
return surface_node
end
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":635,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":636,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":622,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":623,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"fw_parent":599,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":600,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
N_edges = 1
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
for k in pairs(Cursor_node) do
print(k)
end
print(Cursor_node.y, Viewport.y)
if Cursor_node.y < Viewport.y then
Viewport.y = Cursor_node.y - 50
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"fw_parent":598,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":599,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
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
print(obj.text_node)
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.8, 0.8, 0.4)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":567,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":566,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":634,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":635,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"fw_parent":597,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":598,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":621,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":622,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
compute_ntracks = function(parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
-- if we have a single child, it will slide into the same track. This is desirable.
local result = 0
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
result = result + ntracks(child)
end
return result
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
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
print(obj.text_node)
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.8, 0.8, 0)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
on.keychord_press = function(chord, key)
if chord == 'C-=' then
-- zoom in
Viewport.zoom = Viewport.zoom+0.1
B()
elseif chord == 'C--' then
-- zoom out
Viewport.zoom = Viewport.zoom-0.1
B()
elseif chord == 'C-0' then
-- reset zoom
Viewport.zoom = 1.0
B()
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
print(Cursor_node.y, Viewport.y)
if Cursor_node.y < Viewport.y then
Viewport.y = Cursor_node.y - 50
end
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
end
end
end
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
end
end
end
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":566,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":565,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(Nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":620,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":621,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.draw":632,"schema1_of_y":366,"vx":5,"Viewport":303,"on.initialize":446,"y_of_schema1":364,"A":582,"initialize_editor":338,"dehtml":456,"on.mouse_release":586,"box_height":345,"on.update":368,"render_thread_to_surface":626,"on.code_change":578,"Nodes":593,"line_height":365,"load_from_iterator":463,"split_lines":469,"to_node":611,"to_text":180,"scale":7,"fw_parent":633,"Input_filename":436,"add_node":590,"font":353,"Cursor_node":172,"B":379,"ntracks":600,"compute_ntracks":598,"on":1,"vy":8,"add_edge":575,"render_node_and_descendants":633,"on.text_input":587,"update_editor_box":430,"on.mouse_press":618,"on.keychord_press":634,"fw_app":"mastodon-unfurl","add_thick_line":400,"Surface":588,"copy_shape":396,"compute_layout":619}
{"fw_parent":596,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":596,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":597,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
print(id, parent_height)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
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
print(obj.text_node)
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(1, 1, 0)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"fw_parent":595,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":596,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":595,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
compute_ntracks = function(parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
-- if we have a single child, it will slide into the same track. This is desirable.
local result = 0
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
result = result + ntracks(Nodes, child)
end
return result
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":564,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":565,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":619,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":620,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
{"on.initialize":446,"font":353,"A":582,"to_text":180,"to_node":611,"split_lines":469,"add_edge":575,"fw_app":"mastodon-luaML","line_height":365,"compute_layout":619,"add_thick_line":400,"load_from_iterator":463,"Cursor_node":172,"render_node_and_descendants":614,"Surface":588,"box_height":345,"fw_parent":618,"on.code_change":578,"ntracks":600,"compute_ntracks":598,"on.draw":617,"update_editor_box":430,"schema1_of_y":366,"vx":5,"on.keychord_press":584,"render_thread_to_surface":602,"on.mouse_press":618,"initialize_editor":338,"on.mouse_release":586,"Viewport":303,"on":1,"dehtml":456,"vy":8,"add_node":590,"Input_filename":436,"on.text_input":587,"y_of_schema1":364,"Nodes":593,"copy_shape":396,"on.update":368,"scale":7,"B":379}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
print(id, parent_height)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(Nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(Nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":563,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":564,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"fw_parent":594,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":595,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":562,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":563,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":562,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(Nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(Nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url)
Cursor_node = Nodes[node_id]
print(Cursor_node)
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"fw_parent":593,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":594,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":618,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":617,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":617,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"fw_parent":592,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"Nodes":593,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":589,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":561,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":560,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":562,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
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
if obj.text_node and obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.7, 0.7, 0)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil or #parent.children <= 1 then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":616,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":617,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, parent.id, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":560,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":560,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":561,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"fw_parent":591,"fw_app":"mastodon-luaML","scale":7,"load_from_iterator":463,"on.text_input":587,"vx":5,"on.mouse_press":585,"Viewport":303,"split_lines":469,"vy":8,"compute_ntracks":519,"Input_filename":436,"on.update":368,"font":353,"add_node":590,"render_node_and_descendants":592,"dehtml":456,"add_edge":575,"add_thick_line":400,"copy_shape":396,"update_editor_box":430,"on.initialize":446,"line_height":365,"initialize_editor":338,"on":1,"on.code_change":578,"on.draw":418,"schema1_of_y":366,"box_height":345,"ntracks":505,"compute_layout":385,"Cursor_node":172,"A":582,"y_of_schema1":364,"render_thread_to_surface":589,"on.keychord_press":584,"to_text":180,"on.mouse_release":586,"B":379,"Surface":588}
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
if obj.text_node == Cursor_node.surface_node then
love.graphics.setColor(0.7, 0.7, 0)
end
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 or {r=0,g=0,b=0}, not obj.show_cursor)
end
end
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":559,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":560,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":615,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":616,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
add_node = function(x, y, text, parent_surface_node)
print('add node', x)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
print('aa 1', surface_node.x)
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
print('aa 2', surface_node.x)
if parent_surface_node then
print('aa', surface_node.x, parent_surface_node.x)
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
local parent_surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":614,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":615,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":558,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":559,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"vy":8,"Cursor_node":172,"on.update":368,"ntracks":505,"render_thread_to_surface":589,"dehtml":456,"add_thick_line":400,"copy_shape":396,"fw_parent":590,"fw_app":"mastodon-luaML","load_from_iterator":463,"on.code_change":578,"font":353,"box_height":345,"split_lines":469,"scale":7,"add_node":590,"on.draw":418,"vx":5,"Viewport":303,"schema1_of_y":366,"on.mouse_release":586,"update_editor_box":430,"to_text":180,"Surface":588,"render_node_and_descendants":591,"y_of_schema1":364,"compute_layout":385,"Input_filename":436,"compute_ntracks":519,"A":582,"B":379,"on.keychord_press":584,"add_edge":575,"on":1,"on.text_input":587,"on.mouse_press":585,"initialize_editor":338,"line_height":365,"on.initialize":446}
add_node = function(x, y, text, parent_surface_node)
print('add node', x)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
print('aa', surface_node.x, parent_surface_node.x)
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
{"vy":8,"Cursor_node":172,"on.update":368,"ntracks":505,"render_thread_to_surface":589,"dehtml":456,"add_thick_line":400,"copy_shape":396,"fw_parent":589,"fw_app":"mastodon-luaML","load_from_iterator":463,"on.code_change":578,"font":353,"box_height":345,"split_lines":469,"scale":7,"add_node":590,"on.draw":418,"vx":5,"Viewport":303,"schema1_of_y":366,"on.mouse_release":586,"update_editor_box":430,"to_text":180,"Surface":588,"render_node_and_descendants":579,"y_of_schema1":364,"compute_layout":385,"Input_filename":436,"compute_ntracks":519,"A":582,"B":379,"on.keychord_press":584,"add_edge":575,"on":1,"on.text_input":587,"on.mouse_press":585,"initialize_editor":338,"line_height":365,"on.initialize":446}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":557,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":557,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":558,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, id, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
toot_id=id,
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
add_edge = function(node, parent)
print('add edge', node.x, node.y, parent.x, parent.y)
local line = {
type='line',
data={
parent.x + 600/2, parent.y + box_height(node),
node.x + 600/2, node.y,
},
}
table.insert(Surface, line)
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":556,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":557,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":556,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
compute_layout = function(node, x,y, nodes_to_render, preserve_screen_top_of_cursor_node)
-- append to nodes_to_render flattened instructions to render a hierarchy of nodes
-- return x,y rendered until (surface coordinates)
if node.type == 'text' then
-- leaf node containing raw text
node.x = x
node.y = y
-- render background if necessary
local node_to_render
if node.bg then
node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
table.insert(nodes_to_render, node_to_render)
end
-- render contents
if node.width then
node.w = node.width
else
node.w = 0
for i,s in ipairs(node.data) do
local text = love.graphics.newText(font(20), node.data)
local width = text:getWidth()
if node.w < width then node.w = width end
end
end
if node.editor == nil then
initialize_editor(node)
else
update_editor_box(node, preserve_screen_top_of_cursor_node)
end
node.h = box_height(node)
table.insert(nodes_to_render, node)
if node_to_render then
node_to_render.w = node.w
node_to_render.h = node.h
end
elseif node.type == 'rows' then
node.x = x
node.y = y
local node_to_render
if node.bg then
node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y, text_node=node}
table.insert(nodes_to_render, node_to_render)
end
-- lay out children top to bottom
local subx,suby = x,y
local w,h = 0,0
local subnodes
for _,child in ipairs(node.data) do
if child.margin then
suby = suby+child.margin
h = h+child.margin
end
if not child.width then
child.width = node.width -- HACK: should we set child.w or child.width? Neither is quite satisfactory.
end
subx,suby = compute_layout(child, x,suby, nodes_to_render)
if w < child.w then
w = child.w
end
h = h+child.h
end
node.w = w
node.h = h
if node_to_render then
node_to_render.w = w
node_to_render.h = h
end
elseif node.type == 'cols' then
node.x = x
node.y = y
-- lay out children left to right
local node_to_render
if node.bg then
node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
table.insert(nodes_to_render, node_to_render)
end
local subx,suby = x,y
local w,h = 0,0
for _,child in ipairs(node.data) do
if child.margin then
subx = subx+child.margin
w = w+child.margin
end
subx,suby = compute_layout(child, subx,y, nodes_to_render)
w = w + child.w
if h < child.h then
h = child.h
end
end
node.w = w
node.h = h
if node_to_render then
node_to_render.w = w
node_to_render.h = h
end
end
return x+node.w,y+node.h
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":555,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":555,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":556,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"schema1_of_y":366,"ntracks":505,"compute_ntracks":519,"y_of_schema1":364,"A":582,"compute_layout":385,"render_node_and_descendants":579,"B":379,"line_height":365,"on.code_change":578,"Surface":588,"Input_filename":436,"on.draw":418,"vx":5,"scale":7,"Viewport":303,"Cursor_node":172,"vy":8,"to_text":180,"on.mouse_press":585,"render_thread_to_surface":589,"initialize_editor":338,"on.update":368,"dehtml":456,"on.keychord_press":584,"copy_shape":396,"on.initialize":446,"fw_app":"mastodon-luaML","on":1,"fw_parent":588,"add_node":576,"load_from_iterator":463,"on.text_input":587,"add_edge":575,"add_thick_line":400,"box_height":345,"update_editor_box":430,"on.mouse_release":586,"split_lines":469,"font":353}
add_edge = function(node, parent)
print('add edge', node.id, parent.id)
local line = {
type='line',
data={
parent.x + 600/2, parent.y + box_height(node),
node.x + 600/2, node.y,
},
}
table.insert(Surface, line)
end
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, parent.id, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
parent.surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent.surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":554,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":555,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent_surface_node)
print('add node')
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":613,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":614,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
on.mouse_press = function(x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url)
Cursor_node = Nodes[node_id]
else
end
end
Pan = {x=Viewport.x+x/Viewport.zoom, y=Viewport.y+y/Viewport.zoom}
{"vy":8,"y_of_schema1":364,"A":582,"to_node":611,"on.mouse_press":613,"B":379,"on.mouse_release":586,"on.update":368,"on.keychord_press":584,"Input_filename":436,"on.text_input":587,"fw_parent":612,"fw_app":"mastodon-luaML","Cursor_node":172,"compute_layout":385,"font":353,"line_height":365,"on.code_change":578,"add_thick_line":400,"render_node_and_descendants":603,"copy_shape":396,"add_edge":575,"load_from_iterator":463,"box_height":345,"scale":7,"on":1,"to_text":180,"Nodes":593,"update_editor_box":430,"initialize_editor":338,"on.initialize":446,"split_lines":469,"Surface":588,"add_node":590,"ntracks":600,"on.draw":418,"compute_ntracks":598,"schema1_of_y":366,"render_thread_to_surface":602,"Viewport":303,"vx":5,"dehtml":456}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent_surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":553,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":552,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":554,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent_surface_node)
return
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent_surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":552,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":552,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":553,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":551,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":552,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":547,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
add_node = function(x, y, text, parent)
print('add node')
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent then
add_edge(node, parent)
end
return surface_node
end
{"on.mouse_release":367,"on.update":368,"Cursor_node":172,"on.keychord_press":391,"on":1,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"add_thick_line":400,"to_text":180,"copy_shape":396,"fw_parent":550,"fw_app":"mastodon-luaML","initialize_editor":338,"line_height":365,"update_editor_box":430,"compute_layout":385,"on.code_change":473,"box_height":345,"load_from_iterator":463,"schema1_of_y":366,"split_lines":469,"A":474,"add_node":550,"font":353,"on.initialize":446,"ntracks":505,"render_node_and_descendants":547,"compute_ntracks":519,"Input_filename":436,"Viewport":303,"B":379,"Surface":434,"vy":8,"scale":7,"add_edge":551,"y_of_schema1":364,"on.draw":418,"on.mouse_press":179,"vx":5}
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":549,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":550,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"add_edge":548,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
add_node = function(x, y, text, parent)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent then
add_edge(node, parent)
end
return surface_node
end
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":548,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":549,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"add_edge":548,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
add_node = function(x, y, text, parent)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
add_edge(node, parent)
return surface_node
end
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":547,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":546,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"add_edge":548,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
render_node_and_descendants = function(nodes, id, y, xlo, xhi, grandparent)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content, grandparent)
return
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content, grandparent)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":546,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":546,"render_node_and_descendants":547,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
{"schema1_of_y":366,"on.keychord_press":391,"split_lines":469,"fw_parent":545,"y_of_schema1":364,"fw_app":"mastodon-luaML","add_node":546,"render_node_and_descendants":545,"Input_filename":436,"Cursor_node":172,"compute_layout":385,"to_text":180,"scale":7,"initialize_editor":338,"on.text_input":388,"ntracks":505,"copy_shape":396,"compute_ntracks":519,"render_thread_to_surface":525,"line_height":365,"Surface":434,"add_thick_line":400,"dehtml":456,"on.draw":418,"on":1,"vx":5,"B":379,"Viewport":303,"update_editor_box":430,"on.mouse_press":179,"vy":8,"font":353,"A":474,"on.initialize":446,"load_from_iterator":463,"box_height":345,"on.mouse_release":367,"on.code_change":473,"on.update":368}
add_node = function(x, y, text, grandparent)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
return surface_node
end
header = function(node)
local result = {}
if node.account == nil then
table.insert(result, node.user)
elseif node.account.display_name then
table.insert(result, node.account.display_name)
else
table.insert(result, node.account.username)
end
table.insert(result, node.created_at)
table.insert(result, '---')
return table.concat(result, '\n')
end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":651,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":650,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":650,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":649,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":650,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":649,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
add_node = function(x, y, node, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(header(node)..'\n'..dehtml(node.content)),
bg={r=0.7,g=0.7, b=1.0},
toot_id=node.id,
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
header = function(node)
local result = {}
assert(node.account)
if node.account.display_name then
table.insert(result, node.account.display_name)
else
table.insert(result, node.account.username)
end
table.insert(result, node.created_at)
table.insert(result, '---')
return table.concat(result, '\n')
end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":649,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":647,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":647,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
header = function(node)
local result = {}
assert(node.account)
if node.account.display_name then
table.insert(result, node.account.display_name)
else
table.insert(result, node.account.username)
end
table.insert(result, node.created_at
table.insert(result, '---')
return table.concat(result, '\n')
end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":648,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":647,"render_node_and_descendants":646,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":647,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":647,"render_node_and_descendants":646,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":646,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
add_node = function(x, y, node, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(node.content)),
bg={r=0.7,g=0.7, b=1.0},
toot_id=node.id,
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
parent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
parent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node)
local parent_height = box_height(parent.surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":590,"render_node_and_descendants":646,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":645,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
parent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)
return
end
local parent_xlo
if #parent.children <= 1 then
parent_xlo = xlo
else
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
parent_xlo = parent_x - 620/2
end
parent.surface_node = add_node(parent_xlo, y, parent.content, parent.id, grandparent_surface_node)
local parent_height = box_height(parent.surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"render_thread_to_surface":626,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.mouse_release":586,"on.update":368,"scale":7,"add_node":590,"render_node_and_descendants":645,"vx":5,"compute_layout":619,"ntracks":600,"vy":8,"Nodes":593,"add_thick_line":400,"ensure_cursor_node_within_viewport":643,"Input_filename":436,"on.initialize":446,"to_text":180,"A":582,"line_height":365,"box_height":345,"on.keychord_press":644,"B":379,"fw_parent":644,"to_node":611,"fw_app":"mastodon-unfurl","initialize_editor":338,"add_edge":575}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content)
return
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node) + 50, curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":544,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":545,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":543,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":543,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
if parent.children == nil then
add_node(xlo, y, parent.content)
return
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":542,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":542,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":543,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":541,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":542,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":541,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
center_x_above_children = function(nodes, parent, xlo, xhi)
-- given parent has n children, each of whom occupies various numbers of tracks, return the x of the center, somewhere between xlo and xhi
if parent.children == nil then
return (xlo+xhi)/2
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
return total_boundaries / (#parent.children-1)
end
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
local parent_x = center_x_above_children(nodes, parent, xlo, xhi)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":540,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":540,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":541,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":539,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"center_x_above_children":540,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":539,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
center_x_above_children = function(nodes, parent, xlo, xhi)
-- given parent has n children, each of whom occupies various numbers of tracks, return the x of the center, somewhere between xlo and xhi
if parent.children == nil then
return (xlo+xheight)/2
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
return total_boundaries / (#parent.children-1)
end
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
print(id)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":538,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":539,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = nodes[id]
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#parent.children-1 do
local child_id = parent.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#parent.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, parent.content)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(parent_surface_node), curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":537,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":538,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local node = nodes[id]
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#node.children-1 do
local child_id = node.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#node.children-1)
local parent_xlo = parent_x - 620/2
local parent_surface_node = add_node(parent_xlo, y, node.content)
local curr_boundary = xlo
for _,child_id in ipairs(node.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(node), curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":536,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":537,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":535,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":536,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":535,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
add_node = function(x, y, text)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(dehtml(text)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
return surface_node
end
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local node = nodes[id]
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#node.children-1 do
local child_id = node.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#node.children-1)
local parent_xlo = parent_x - 620/2
add_node(parent_xlo, y, node.content)
local curr_boundary = xlo
for _,child_id in ipairs(node.children) do
local child = nodes[child_id]
render_node_and_descendants(nodes, child_id, y + box_height(node), curr_boundary, curr_boundary + 620*child.ntracks)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
{"Input_filename":436,"fw_parent":534,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":480,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":535,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
render_node_and_descendants = function(nodes, id, y, xlo, xhi)
-- position the root between xlo and xhi to be closer to children with fewer tracks
local node = nodes[id]
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#node.children-1 do
local child_id = node.children[child_idx]
local child = nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local parent_x = total_boundaries / (#node.children-1)
local parent_xlo = parent_x - 620/2
add_node(parent_xlo, y, nodes[id].content)
end
{"Input_filename":436,"fw_parent":533,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":480,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":534,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"Input_filename":436,"fw_parent":532,"fw_app":"mastodon-luaML","initialize_editor":338,"update_editor_box":430,"ntracks":505,"compute_ntracks":519,"on.text_input":388,"render_thread_to_surface":525,"dehtml":456,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":474,"B":379,"scale":7,"Surface":434,"split_lines":469,"on":1,"vx":5,"box_height":345,"Viewport":303,"compute_layout":385,"font":353,"on.code_change":473,"vy":8,"line_height":365,"add_node":480,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"render_node_and_descendants":533,"on.update":368,"add_thick_line":400,"on.keychord_press":391,"Cursor_node":172,"on.draw":418,"copy_shape":396,"to_text":180}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":531,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":532,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":530,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":531,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":529,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":530,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":528,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":529,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":527,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":528,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":526,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":527,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":525,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":526,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":524,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":525,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":523,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":523,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":522,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":523,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(nodes, root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":521,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":522,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":520,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":521,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
print('aa', root.id, root.ntracks)
-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":519,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":520,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":518,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":518,"dehtml":456,"copy_shape":396,"compute_ntracks":519,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
-- if we have a single child, it will slide into the same track. This is desirable.
local result = 0
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
result = result + ntracks(nodes, child)
end
return result
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(nodes, x)
end
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
print('aa', root.id, root.ntracks)
-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":517,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":518,"dehtml":456,"copy_shape":396,"compute_ntracks":516,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
print('compute ntracks', x.id)
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
print('aa', root.id, root.ntracks)
-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":516,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":517,"dehtml":456,"copy_shape":396,"compute_ntracks":516,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":515,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":515,"dehtml":456,"copy_shape":396,"compute_ntracks":516,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
-- if we have a single child, it will slide into the same track. This is desirable.
local result = 0
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
result = result + ntracks(nodes, child)
end
return result
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
print('aa', root.id, root.ntracks)
-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":514,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":515,"dehtml":456,"copy_shape":396,"compute_ntracks":506,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
local root = thread_data
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
print('aa', root.ntracks)
-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":513,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":514,"dehtml":456,"copy_shape":396,"compute_ntracks":506,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
print('aa', thread_data.ntracks)
-- render_node_and_descendants(nodes, thread_data.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * thread_data.ntracks)
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"on.initialize":446,"vy":8,"fw_parent":511,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"Cursor_node":172,"vx":5,"Surface":434,"Viewport":303,"render_node_and_descendants":482,"add_thick_line":400,"render_thread_to_surface":513,"dehtml":456,"copy_shape":396,"compute_ntracks":506,"split_lines":469,"on.mouse_press":179,"load_from_iterator":463,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_node_and_descendants = function(node, descendants, id, y, xlo, xhi)
add_node(x, y, node[id].contents)
local nchildren = #descendants[id]
-- to render n children we require 600*n + 20*(n-1) px of width
local children = {}
for i,x in ipairs(descendants[id]) do
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":511,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":512,"on.initialize":446,"render_thread_to_surface":511,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":510,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":511,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = nodes[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":509,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":510,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
local c = node[y]
print(x.id, c.id, c.ntracks)
end
end
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":508,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":509,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
if x.children then
for _,y in pairs(x.children) do
print(x.id, y.id, y.ntracks)
end
end
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":507,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":508,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
for _,y in pairs(x.children) do
print(x.id, y.id, y.ntracks)
end
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":506,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":507,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":506,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":505,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":504,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
local result = 0
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
result = result + ntracks(nodes, child)
end
return result
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":505,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":503,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":504,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":504,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ntracks(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ntracks)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":502,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":503,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":503,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":504,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":502,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"compute_ntracks":503,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":502,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":501,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ntracks = function(nodes, parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
local result = 0
for _,child_id in ipairs(parent.children) do
local child = nodes[child_id]
result = result + ntracks(nodes, child)
end
return result
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"ntracks":502,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":501,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":501,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute number of tracks needed
for _,x in pairs(nodes) do
compute_ndescendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":500,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":501,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":500,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":499,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)
if parent.ndescendants then return parent.ndescendants end
local result = 0
if parent.children then
for _,child_id in ipairs(parent.children) do
local child = node[child_id]
result = result + compute_ndescendants(node, child) + 1
end
end
parent.ndescendants = result
return result
end
render_thread_to_surface = function(thread_data)
-- design constraints:
-- trees only, no graphs or DAGs
-- parents above children
-- a child shares its parent's column exactly only if it's an only child
-- parents can overlap columns with children and more distant descendants
-- siblings never share a column
-- siblings never overlap columns
-- siblings always occupy the same row
-- cousins/aunts/nephews never overlap columns
Surface = {}
-- we're going to be computing box heights
love.graphics.setFont(love.graphics.newFont(scale(20)))
-- compute mapping from ids to nodes
Nodes = {} -- id to object
Nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
Nodes[x.id] = x
end
local root = thread_data
Cursor_node = root
-- compute children
for _,x in pairs(Nodes) do
parent_id = x.in_reply_to_id
if x.id ~= root.id then
assert(parent_id)
local parent = Nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- sort children by time
for _,x in pairs(Nodes) do
if x.children then
table.sort(x.children)
end
end
-- compute number of tracks needed
for _,x in pairs(Nodes) do
if x.ntracks == nil then
x.ntracks = compute_ntracks(x)
end
end
-- prepare the tracks
-- each track is 600px + 20px of gutter between nodes
render_node_and_descendants(root.id, --[[y]] 0, --[[xlo]] 0, --[[xhi]] 620 * root.ntracks)
ensure_cursor_node_within_viewport()
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":499,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":498,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"render_thread_to_surface":652,"dehtml":456,"Cursor_node":172,"on.code_change":578,"copy_shape":396,"on.text_input":587,"header":651,"Surface":588,"update_editor_box":430,"load_from_iterator":463,"on.draw":632,"compute_ntracks":598,"on":1,"Viewport":303,"font":353,"split_lines":469,"schema1_of_y":366,"on.mouse_press":618,"y_of_schema1":364,"on.initialize":446,"on.update":368,"scale":7,"add_node":650,"render_node_and_descendants":646,"vx":5,"add_edge":575,"initialize_editor":338,"vy":8,"Nodes":593,"add_thick_line":400,"ntracks":600,"Input_filename":436,"compute_layout":619,"to_text":180,"A":582,"on.keychord_press":644,"box_height":345,"line_height":365,"B":379,"fw_parent":651,"to_node":611,"fw_app":"mastodon-unfurl","ensure_cursor_node_within_viewport":643,"on.mouse_release":586}
compute_ndescendants = function(node, parent)
if parent.ndescendants then return parent.ndescendants end
local result = 1
if parent.children then
for _,child_id in ipairs(parent.children) do
local child = node[child_id]
result = result + compute_ndescendants(node, child)
end
end
parent.ndescendants = result
return result
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":498,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":497,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)
if parent.ndescendants then return parent.ndescendants end
local result = 1
if parents.children then
for _,child_id in ipairs(parent.children) do
local child = node[child_id]
result = result + compute_ndescendants(node, child)
end
end
parent.ndescendants = result
return result
end
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute ndescendants
for _,x in pairs(nodes) do
compute_ndescendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":496,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":497,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute ndescendants
for _,x in pairs(nodes) do
compute_nescendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":495,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":496,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x.id ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute ndescendants
for _,x in pairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":494,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":495,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
if x ~= thread_data.id then
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
end
-- compute ndescendants
for _,x in pairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":493,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":494,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id or x.id == thread_data.id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in pairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":492,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":493,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in pairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in pairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in pairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":491,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":492,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
print(#nodes)
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in ipairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":490,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":491,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(nodes) do
compute_descendants(nodes, x)
end
print(#nodes)
for _,x in ipairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":489,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":490,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
print('aaa')
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in ipairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":488,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":489,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(nodes) do
compute_descendants(nodes, x)
end
for _,x in ipairs(nodes) do
print(x.id, x.in_reply_to_id, x.ndescendants)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":487,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":488,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":487,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":486,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":486,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)
if parent.ndescendants then return parent.ndescendants end
local result = 1
for _,child_id in ipairs(parent.children) do
local child = node[child_id]
result = result + compute_ndescendants(node, child)
end
parent.ndescendants = result
return result
end
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(nodes) do
compute_descendants(nodes, x)
end
-- render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":485,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":486,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local nodes = {} -- id to object
nodes[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
nodes[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = nodes[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(nodes) do
compute_descendants(nodes, x)
end
render_node_and_descendants(nodes, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":484,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":485,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
-- compute mapping from ids to nodes
local node = {} -- id to object
node[thread_data.id] = thread_data
for _,x in ipairs(thread_data.descendants) do
node[x.id] = x
end
-- compute children
for _,x in ipairs(nodes) do
parent_id = x.in_reply_to_id
assert(parent_id)
local parent = node[parent_id]
if parent.children == nil then
parent.children = {}
end
table.insert(parent.children, x.id)
end
-- compute ndescendants
for _,x in ipairs(node) do
compute_descendants(node, x)
end
render_node_and_descendants(node, descendants, thread_data.id, 0, 0)
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":483,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":484,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"compute_ndescendants":483,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":482,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":479,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
compute_ndescendants = function(node, parent)
if parent.ndescendants then return parent.ndescendants end
local result = 1
for _,child_id in ipairs(parent.children) do
local child = node[child_id]
result = result + compute_ndescendants(node, child)
end
return result
end
{"on.text_input":388,"update_editor_box":430,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"load_from_iterator":463,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"initialize_editor":338,"Surface":434,"on":1,"fw_app":"mastodon-luaML","on.draw":418,"fw_parent":480,"vx":5,"vy":8,"Viewport":303,"render_node_and_descendants":482,"on.initialize":446,"render_thread_to_surface":479,"dehtml":456,"copy_shape":396,"to_text":180,"split_lines":469,"on.mouse_press":179,"add_thick_line":400,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"render_node_and_descendants(node,":481,"on.text_input":388,"on.initialize":446,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"Surface":434,"update_editor_box":430,"fw_app":"mastodon-luaML","on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"split_lines":469,"load_from_iterator":463,"vy":8,"dehtml":456,"copy_shape":396,"fw_parent":480,"Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":479,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
{"on.text_input":388,"on.initialize":446,"A":474,"scale":7,"B":379,"line_height":365,"schema1_of_y":366,"y_of_schema1":364,"add_node":480,"to_text":180,"box_height":345,"font":353,"compute_layout":385,"on.code_change":473,"Surface":434,"update_editor_box":430,"fw_app":"mastodon-luaML","on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"split_lines":469,"load_from_iterator":463,"vy":8,"dehtml":456,"copy_shape":396,"fw_parent":479,"Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":479,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"Input_filename":436,"on.keychord_press":391}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=split_lines(dehtml(thread_data.content)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
local node = {} -- id to object
local descendants = {} -- node id to array of descendant ids
for i,x in ipairs(thread_data.descendants) do
print(i, x.id, x.in_reply_to_id)
node[x.id] = x
parent_id = x.in_reply_to_id
assert(parent_id)
if descendants[parent_id] == nil then
descendants[parent_id] = {}
end
table.insert(descendants[parent_id], x.id)
end
print('immediate children')
for i,x in ipairs(descendants[thread_data.id]) do
print(x)
end
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":478,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":479,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=split_lines(dehtml(thread_data.content)),
bg={r=0.7,g=0.7, b=1.0},
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
local node = {} -- id to object
local descendants = {} -- node id to array of descendant ids
for i,x in ipairs(thread_data.descendants) do
print(i, x.id, x.in_reply_to_id)
node[x.id] = x
parent_id = x.in_reply_to_id
assert(parent_id)
if descendants[parent_id] == nil then
descendants[parent_id] = {}
end
table.insert(descendants[parent_id], x.id)
end
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":477,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":478,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=split_lines(dehtml(thread_data.content))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
for i,x in ipairs(thread_data.descendants) do
print(i, x.id, x.in_reply_to_id)
end
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":476,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":477,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=split_lines(dehtml(thread_data.content))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
print(#thread_data.descendants)
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":475,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":476,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=split_lines(dehtml(thread_data.content))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
print(#tmp.descendants)
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":474,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":475,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":473,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":472,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":474,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":473,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":472,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":472,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=split_lines(dehtml(thread_data.content))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":471,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":472,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
w=600,
type='text',
data=split_lines(dehtml(thread_data.content))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":470,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":471,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
-- Surface = {}
local tmp = {
x=0, y=0,
w=600,
type='text',
data=split_lines(dehtml(thread_data.content))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
end
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":469,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":470,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
{"copy_shape":396,"font":353,"Input_filename":436,"update_editor_box":430,"to_text":180,"line_height":365,"box_height":345,"compute_layout":385,"schema1_of_y":366,"on.code_change":458,"y_of_schema1":364,"Surface":434,"B":379,"on.draw":418,"load_from_iterator":463,"Viewport":303,"scale":7,"fw_parent":468,"fw_app":"mastodon-luaML","Cursor_node":172,"on.mouse_press":179,"render_thread_to_surface":468,"on.mouse_release":367,"initialize_editor":338,"on.text_input":388,"on.keychord_press":391,"on.initialize":446,"on":1,"A":455,"split_lines":469,"vy":8,"vx":5,"on.update":368,"add_thick_line":400,"dehtml":456}
render_thread_to_surface = function(thread_data)
-- Surface = {}
local tmp = {
x=0, y=0,
w=600,
type='text',
data=load_from_iterator(
dehtml(thread_data.content)
:gmatch("[^\r\n]+"))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
end
{"on.initialize":446,"box_height":345,"A":455,"load_from_iterator":463,"B":379,"schema1_of_y":366,"font":353,"Surface":434,"y_of_schema1":364,"scale":7,"on.draw":418,"Cursor_node":172,"vx":5,"Viewport":303,"on.text_input":388,"Input_filename":436,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"on.keychord_press":391,"on":1,"render_thread_to_surface":468,"dehtml":456,"add_thick_line":400,"copy_shape":396,"fw_parent":467,"on.code_change":458,"fw_app":"mastodon-luaML","line_height":365,"to_text":180,"compute_layout":385,"vy":8,"update_editor_box":430}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
w=600,
type='text',
data=load_from_iterator(
dehtml(thread_data.content)
:gmatch("[^\r\n]+"))
}
compute_layout(tmp, tmp.x, tmp.y, Surface)
end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":467,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":466,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
w=600,
type='text',
data=load_from_iterator(
dehtml(thread_data.content)
:gmatch("[^\r\n]+"))
}
table.insert(Surface, tmp)
end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":466,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":465,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=load_from_iterator(
dehtml(thread_data.content)
:gmatch("[^\r\n]+"))
}
print(type(tmp.data), #tmp.data)
table.insert(Surface, tmp)
end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":465,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":464,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=load_from_iterator(
dehtml(thread_data.content)
:gmatch("[^\r\n]+"))
}
table.insert(Surface, tmp)
end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":464,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":463,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":462,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"load_from_iterator":463,"B":379,"fw_parent":462,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":462,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"B":379,"fw_parent":461,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
render_thread_to_surface = function(thread_data)
Surface = {}
local tmp = {
x=0, y=0,
width=600,
type='text',
data=dehtml(thread_data.content)
}
print('rerendering')
table.insert(Surface, tmp)
end
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":461,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"B":379,"fw_parent":460,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"Surface":434,"on.draw":418,"vx":5,"render_thread_to_surface":460,"Viewport":303,"add_thick_line":400,"vy":8,"copy_shape":396,"line_height":365,"to_text":180,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"on.update":368,"font":353,"on.keychord_press":391,"Cursor_node":172,"update_editor_box":430,"on.text_input":388,"schema1_of_y":366,"on.initialize":446,"y_of_schema1":364,"A":455,"B":379,"fw_parent":459,"box_height":345,"Input_filename":436,"compute_layout":385,"scale":7,"on":1,"fw_app":"mastodon-luaML","on.code_change":458,"dehtml":456}
{"vy":8,"fw_parent":458,"render_thread_to_surface":459,"on.mouse_press":179,"on.mouse_release":367,"initialize_editor":338,"add_thick_line":400,"on":1,"on.keychord_press":391,"scale":7,"update_editor_box":430,"on.initialize":446,"schema1_of_y":366,"B":379,"y_of_schema1":364,"line_height":365,"compute_layout":385,"Cursor_node":172,"on.code_change":458,"to_text":180,"font":353,"dehtml":456,"on.text_input":388,"Input_filename":436,"Surface":434,"A":455,"on.update":368,"on.draw":418,"copy_shape":396,"vx":5,"box_height":345,"Viewport":303,"fw_app":"mastodon-luaML"}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":456,"fw_parent":457,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":458,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":456,"fw_parent":456,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":457,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":456,"fw_parent":455,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":454,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":455,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
A = function(filename)
if filename then
print('reading', filename)
local f = io.open(filename)
assert(f)
local thread_data = json.decode(f:read('*a'))
render_thread_to_surface(thread_data)
end
B()
end
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":454,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":453,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":453,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":452,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"on.keychord_press":391,"render_thread_to_surface":451,"scale":7,"add_thick_line":400,"copy_shape":396,"to_text":180,"dehtml":452,"fw_parent":451,"fw_app":"mastodon-luaML","box_height":345,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"y_of_schema1":364,"B":379,"on.draw":418,"update_editor_box":430,"vx":5,"on":1,"Viewport":303,"on.text_input":388,"Surface":434,"vy":8,"on.initialize":446,"Input_filename":436,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"on.mouse_release":367,"initialize_editor":338}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"render_thread_to_surface":451,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":450,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"render_thread_to_surface":450,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":449,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":448,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":449,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"initialize_editor":338,"fw_parent":446,"on.text_input":388,"scale":7,"fw_app":"mastodon-luaML","y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"Input_filename":436,"on.mouse_release":367,"vy":8,"Surface":434,"on.initialize":446,"Cursor_node":172,"A":448,"on.mouse_press":179,"line_height":365,"update_editor_box":430,"B":379}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"on.text_input":388,"update_editor_box":430,"fw_app":"mastodon-luaML","scale":7,"B":379,"y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"on.initialize":446,"Surface":434,"vy":8,"on.mouse_release":367,"Input_filename":436,"Cursor_node":172,"A":447,"on.mouse_press":179,"line_height":365,"fw_parent":446,"initialize_editor":338}
{"on.update":368,"box_height":345,"on.keychord_press":391,"compute_layout":385,"font":353,"on.code_change":443,"schema1_of_y":366,"on.text_input":388,"update_editor_box":430,"fw_app":"mastodon-luaML","scale":7,"B":379,"y_of_schema1":364,"on":1,"copy_shape":396,"on.draw":418,"to_text":180,"vx":5,"add_thick_line":400,"Viewport":303,"on.initialize":446,"Surface":434,"vy":8,"on.mouse_release":367,"Input_filename":436,"Cursor_node":172,"A":444,"on.mouse_press":179,"line_height":365,"fw_parent":445,"initialize_editor":338}
{"on.mouse_press":179,"initialize_editor":338,"on.mouse_release":367,"box_height":345,"on.update":368,"compute_layout":385,"on.keychord_press":391,"on.text_input":388,"Input_filename":436,"y_of_schema1":364,"A":444,"copy_shape":396,"fw_parent":444,"line_height":365,"fw_app":"mastodon-luaML","on.code_change":443,"to_text":180,"Surface":434,"font":353,"on.initialize":445,"on.draw":418,"on":1,"vx":5,"add_thick_line":400,"Viewport":303,"B":379,"update_editor_box":430,"vy":8,"scale":7,"Cursor_node":172,"schema1_of_y":366}
{"A":444,"on.mouse_press":179,"Cursor_node":172,"y_of_schema1":364,"initialize_editor":338,"copy_shape":396,"scale":7,"box_height":345,"on.keychord_press":391,"compute_layout":385,"on.initialize":441,"B":379,"on.code_change":443,"schema1_of_y":366,"Input_filename":436,"fw_app":"mastodon-luaML","on.update":368,"fw_parent":443,"update_editor_box":430,"Surface":434,"add_thick_line":400,"on.mouse_release":367,"on.draw":418,"on":1,"vx":5,"on.text_input":388,"Viewport":303,"font":353,"to_text":180,"vy":8,"line_height":365}
{"A":438,"on.mouse_press":179,"Cursor_node":172,"y_of_schema1":364,"initialize_editor":338,"copy_shape":396,"scale":7,"box_height":345,"on.keychord_press":391,"compute_layout":385,"on.initialize":441,"B":379,"on.code_change":443,"schema1_of_y":366,"Input_filename":436,"fw_app":"mastodon-luaML","on.update":368,"fw_parent":442,"update_editor_box":430,"Surface":434,"add_thick_line":400,"on.mouse_release":367,"on.draw":418,"on":1,"vx":5,"on.text_input":388,"Viewport":303,"font":353,"to_text":180,"vy":8,"line_height":365}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":442,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":441,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":441,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":440,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":441,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":439,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":440,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":438,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":439,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":437,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":437,"on.mouse_press":179,"A":438}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":436,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":437,"on.mouse_press":179,"A":431}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"Input_filename":436,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":435,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":435,"on.mouse_press":179,"A":431}
{"on.mouse_release":367,"initialize_editor":338,"on.update":368,"y_of_schema1":364,"on.keychord_press":391,"compute_layout":385,"on.code_change":306,"box_height":345,"font":353,"Cursor_node":172,"line_height":365,"to_text":180,"copy_shape":396,"Surface":434,"scale":7,"on.text_input":388,"on.draw":418,"add_thick_line":400,"vx":5,"on":1,"Viewport":303,"update_editor_box":430,"fw_parent":434,"vy":8,"fw_app":"mastodon-luaML","B":379,"schema1_of_y":366,"on.initialize":435,"on.mouse_press":179,"A":431}
{"on.keychord_press":391,"schema1_of_y":366,"on.text_input":388,"initialize_editor":338,"on":1,"y_of_schema1":364,"A":431,"compute_layout":385,"to_text":180,"Surface":434,"B":379,"vy":8,"on.draw":418,"on.initialize":350,"vx":5,"line_height":365,"Viewport":303,"fw_parent":433,"update_editor_box":430,"fw_app":"mastodon-luaML","add_thick_line":400,"scale":7,"copy_shape":396,"on.code_change":306,"on.mouse_press":179,"on.update":368,"on.mouse_release":367,"Cursor_node":172,"font":353,"box_height":345}
Surface = {
-- test data
{type='line', data={0,-1000, 0,1000}},
{type='line', data={-10000,0, 10000,0}},
{type='rectangle', x=50,y=50, w=20,h=80, r=1,g=0,b=0},
{type='circle', x=300,y=200, radius=40, r=1,g=0,b=1},
{type='arc', x=0,y=0, radius=50, angle1=0, angle2=math.pi*2/3},
{type='ellipse', x=100,y=100, radiusx=10, radiusy=50},
{type='bezier', data={25,25, 25,125, 75,25, 125,25}},
}
{"A":431,"on.draw":418,"on.keychord_press":391,"vx":5,"B":379,"Viewport":303,"add_thick_line":400,"schema1_of_y":366,"copy_shape":396,"initialize_editor":338,"on":1,"box_height":345,"on.mouse_press":179,"font":353,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"on.code_change":306,"scale":7,"y_of_schema1":364,"on.initialize":350,"on.text_input":388,"update_editor_box":430,"fw_parent":432,"compute_layout":385,"fw_app":"mastodon-luaML","vy":8,"Surface":422,"to_text":180,"line_height":365}
{"A":431,"on.draw":418,"on.keychord_press":391,"vx":5,"B":379,"Viewport":303,"add_thick_line":400,"schema1_of_y":366,"copy_shape":396,"initialize_editor":338,"on":1,"box_height":345,"on.mouse_press":179,"font":353,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"on.code_change":306,"scale":7,"y_of_schema1":364,"on.initialize":350,"on.text_input":388,"update_editor_box":430,"fw_parent":431,"compute_layout":385,"fw_app":"mastodon-luaML","Page2":429,"vy":8,"Surface":422,"to_text":180,"line_height":365}
{"A":431,"on.draw":418,"on.keychord_press":391,"vx":5,"B":379,"Viewport":303,"add_thick_line":400,"schema1_of_y":366,"copy_shape":396,"Page":381,"initialize_editor":338,"on":1,"box_height":345,"on.mouse_press":179,"font":353,"on.mouse_release":367,"Cursor_node":172,"on.update":368,"on.code_change":306,"scale":7,"y_of_schema1":364,"on.initialize":350,"on.text_input":388,"update_editor_box":430,"fw_parent":430,"compute_layout":385,"fw_app":"mastodon-luaML","Page2":429,"vy":8,"Surface":422,"to_text":180,"line_height":365}
xposition = function(curr, xlo, xhi)
-- return the left margin to position a node at
if curr.children == nil or #curr.children == 0 then
return xlo
end
if #curr.children == 1 then
return xposition(Nodes[curr.children[1]], xlo, xhi)
end
local total_boundaries = 0
local curr_boundary = xlo
for child_idx = 1,#curr.children-1 do
local child_id = curr.children[child_idx]
local child = Nodes[child_id]
curr_boundary = curr_boundary + 620 * child.ntracks
total_boundaries = total_boundaries + curr_boundary
end
local centerx = total_boundaries / (#curr.children-1)
return centerx - 620/2
end
render_node_and_descendants = function(id, y, xlo, xhi, grandparent_surface_node)
-- draw a parent 'id' and its children
-- also draw an edge from grandparent to parent if provided
-- position the root between xlo and xhi to be closer to children with fewer tracks
local parent = Nodes[id]
if parent.children == nil then
parent.surface_node = add_node(xlo, y, parent, grandparent_surface_node)
return
end
local parent_xlo = xposition(parent, xlo, xhi)
parent.surface_node = add_node(parent_xlo, y, parent, grandparent_surface_node)
local parent_height = box_height(parent.surface_node)
local curr_boundary = xlo
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
render_node_and_descendants(child_id, y + parent_height + 50, curr_boundary, curr_boundary + 620*child.ntracks, parent.surface_node)
curr_boundary = curr_boundary + 620*child.ntracks
end
end
dehtml = function(s)
return s:gsub('<p>', '\n\n')
:gsub('<br>', '\n')
:gsub('<br/>', '\n')
-- hacky
:gsub('<[^>]*>', '')
:gsub(''', "'")
:gsub(''', "'")
:gsub('"', '"')
:gsub('“', '"')
:gsub('”', '"')
:gsub('<', '<')
:gsub('>', '>')
:gsub('&', '&')
end
Root = nil
header = function(node)
local result = {}
if node.account == nil then
table.insert(result, node.user)
elseif node.account.display_name then
table.insert(result, node.account.display_name)
else
table.insert(result, node.account.username)
end
table.insert(result, node.created_at)
table.insert(result, '---')
return table.concat(result, '\n')
end
add_node = function(x, y, node, parent_surface_node)
local surface_node = {
x=x, y=y,
width=600,
type='text',
data=split_lines(header(node)..'\n'..dehtml(node.content)),
bg={r=0.7,g=0.7, b=1.0},
toot_id=node.id,
}
compute_layout(surface_node, surface_node.x, surface_node.y, Surface)
if parent_surface_node then
add_edge(surface_node, parent_surface_node)
end
return surface_node
end
ensure_cursor_node_within_viewport = function()
local snode = Cursor_node.surface_node
local dirty
-- check Viewport.y
if snode.y < Viewport.y then
Viewport.y = snode.y - 50
dirty = true
end
local limit = snode.y + box_height(snode)
if Viewport.y < limit - App.screen.height/Viewport.zoom then
Viewport.y = limit - (App.screen.height-50)/Viewport.zoom
dirty = true
end
-- check Viewport.x
if Cursor_node.surface_node.x < Viewport.x then
Viewport.x = Cursor_node.surface_node.x - 50
dirty = true
end
limit = snode.x + 600
if Viewport.x < limit - App.screen.width/Viewport.zoom then
Viewport.x = limit - (App.screen.width-50)/Viewport.zoom
dirty = true
end
-- refresh if necessary
if dirty then
B()
end
end
to_node = function(x,y)
for _,node in ipairs(Surface) do
if node.type == 'text' then
if x >= vx(node.x) and node.w and x < vx(node.x + node.w) then
if y >= vy(node.y) and node.h and y < vy(node.y + node.h) then
return node.toot_id
end
end
end
end
end
compute_ntracks = function(parent)
-- leaf nodes need 1 track
if parent.children == nil then
return 1
end
-- otherwise add up the tracks needed by all children (parent will fit in among them)
-- if we have a single child, it will slide into the same track. This is desirable.
local result = 0
for _,child_id in ipairs(parent.children) do
local child = Nodes[child_id]
result = result + ntracks(child)
end
return result
end
Nodes = {}
-- test data
{type='line', data={0,-1000, 0,1000}},
{type='line', data={-10000,0, 10000,0}},
{type='text', data={'0'}, x=-20,y=-30},
{type='rectangle', x=50,y=50, w=20,h=80, r=1,g=0,b=0},
{type='text', data={'abc', 'def'}, x=150, y=50, w=50,h=50, fg={r=0,g=0.4, b=0.9}},
{type='circle', x=300,y=200, radius=40, r=1,g=0,b=1},
{type='arc', x=0,y=0, radius=50, angle1=0, angle2=math.pi*2/3},
{type='ellipse', x=100,y=100, radiusx=10, radiusy=50},
{type='bezier', data={25,25, 25,125, 75,25, 125,25}},
elseif Cursor_node then
local old_top = {line=Cursor_node.editor.screen_top1.line, pos=Cursor_node.editor.screen_top1.pos}
edit.keychord_press(Cursor_node.editor, chord, key)
if not eq(Cursor_node.editor.screen_top1, old_top) then
Viewport.y = Cursor_node.y + y_of_schema1(Cursor_node.editor, Cursor_node.editor.screen_top1)
elseif chord == 'C-up' then
if Cursor_node.in_reply_to_id then
Cursor_node = Nodes[Cursor_node.in_reply_to_id]
ensure_cursor_node_within_viewport()
end
elseif chord == 'C-down' then
if Cursor_node.children and #Cursor_node.children > 0 then
Cursor_node = Nodes[Cursor_node.children[1]]
ensure_cursor_node_within_viewport()
end
elseif chord == 'C-left' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx > 1 then
Cursor_node = Nodes[parent.children[idx-1]]
ensure_cursor_node_within_viewport()
end
end
A(--[[preserve screen_top of cursor node]] true)
else
if chord == 'up' then
Viewport.y = Viewport.y - scale(20)
B()
elseif chord == 'down' then
Viewport.y = Viewport.y + scale(20)
B()
elseif chord == 'left' then
Viewport.x = Viewport.x - scale(50)
B()
elseif chord == 'right' then
Viewport.x = Viewport.x + scale(50)
B()
elseif chord == 'pageup' then
Viewport.y = Viewport.y - App.screen.height/Viewport.zoom
B()
elseif chord == 'S-up' then
Viewport.y = Viewport.y - App.screen.height/Viewport.zoom
B()
elseif chord == 'pagedown' then
Viewport.y = Viewport.y + App.screen.height/Viewport.zoom
B()
elseif chord == 'S-down' then
Viewport.y = Viewport.y + App.screen.height/Viewport.zoom
B()
elseif chord == 'S-left' then
Viewport.x = Viewport.x - App.screen.width/Viewport.zoom
B()
elseif chord == 'S-right' then
Viewport.x = Viewport.x + App.screen.width/Viewport.zoom
B()
elseif chord == 'C-right' then
if Cursor_node.in_reply_to_id then
local parent = Nodes[Cursor_node.in_reply_to_id]
assert(parent.children)
if #parent.children > 1 then
local idx = array.find(parent.children, Cursor_node.id)
if idx < #parent.children then
Cursor_node = Nodes[parent.children[idx+1]]
ensure_cursor_node_within_viewport()
end
end
if Cursor_node then
local old_top = {line=Cursor_node.editor.screen_top1.line, pos=Cursor_node.editor.screen_top1.pos}
edit.text_input(Cursor_node.editor, t)
if not eq(Cursor_node.editor.screen_top1, old_top) then
Viewport.y = Cursor_node.y + y_of_schema1(Cursor_node.editor, Cursor_node.editor.screen_top1)
end
A(--[[preserve screen_top of cursor node]] true)
end
on.initialize = function()
A()
end
on.initialize = function(arg)
if #arg == 0 then
error('Please pass in a file containing a Mastodon thread, and optionally an id within it to start out focused on.\n\nThis app currently needs to be invoked from a terminal.')
end
Input_filename = arg[1]
A(Input_filename)
Cursor_node = Root
if #arg >= 1 then
if #arg >= 2 then
local initial_id = arg[2]
if Nodes[initial_id] then
Cursor_node = Nodes[initial_id]
end
end
ensure_cursor_node_within_viewport()
end
end
if Cursor_node then
Cursor_node.show_cursor = nil
Cursor_node = nil
end
local node = to_text(x,y)
if node then
Cursor_node = node
edit.mouse_press(node.editor, x,y, mouse_button)
local node_id = to_node(x,y)
if node_id then
App.setClipboardText(Nodes[node_id].url)
Cursor_node = Nodes[node_id]