Client for playing 300 publicly available Sokoban puzzles on a computer or phone.
draw_file_dialog = function()
	-- border
	App.color{r=0.6, g=0.7, b=0.6}
	love.graphics.rectangle('line',
		Menu_left+5,
		Menu_top+5,
		Safe_width-Menu_left-10,
		Safe_height-Menu_top-10,
		5,5)
	-- ok/cancel buttons (but with wider names)
	local r = Safe_width-10
	r = right_justified_button('cancel', r, Menu_top+5+3, function()
		reset_file_dialog_state()
	end)
	r = right_justified_button('submit', r, Menu_top+5+3, function()
		File_dialog_callback(File_dialog_input_text)
		reset_file_dialog_state()
	end)
	File_dialog_input_right_margin = r
	-- input
	draw_file_dialog_input()
	-- filtered files
	App.color(Menu_background)
	love.graphics.rectangle('fill',
		Menu_left+5,
		Menu_bottom+5,
		Safe_width-Menu_left-10,
		Safe_height-Menu_bottom-10,
		5,5)
	if Directory_contents == nil then
		-- on the first frame after dialog is enabled
		Directory_contents = directory_contents(Directory)
	end
	local y = add_files_to_dialog(Menu_left+10, Menu_bottom+10)
	if Stash_directory_contents == nil then
		-- on the first frame after dialog is enabled
		Stash_directory_contents = directory_contents(Stash_directory)
	end
	if #Stash_directory_contents > 0 then
		y = y+Line_height+20
		App.color{r=1, g=1, b=1}
		g.print('stashed files:', Menu_left+10, y)
		y = y+Line_height+5
		y = add_stash_files_to_dialog(Menu_left+10, y)
	end
end