xref: /freebsd/stand/lua/drawer.lua (revision 6697f577d1216a312dd6ed27aa30f8a5d0d587d4)
1088b4f5fSWarner Losh--
272e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
372e39d71SKyle Evans--
4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
5df74a61fSKyle Evans-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
6088b4f5fSWarner Losh-- All rights reserved.
7088b4f5fSWarner Losh--
8088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without
9088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions
10088b4f5fSWarner Losh-- are met:
11088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright
12088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer.
13088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright
14088b4f5fSWarner Losh--    notice, this list of conditions and the following disclaimer in the
15088b4f5fSWarner Losh--    documentation and/or other materials provided with the distribution.
16088b4f5fSWarner Losh--
17088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20088b4f5fSWarner Losh-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27088b4f5fSWarner Losh-- SUCH DAMAGE.
28088b4f5fSWarner Losh--
29088b4f5fSWarner Losh-- $FreeBSD$
30088b4f5fSWarner Losh--
31088b4f5fSWarner Losh
32aedd6be5SKyle Evanslocal color = require("color")
33aedd6be5SKyle Evanslocal config = require("config")
34aedd6be5SKyle Evanslocal core = require("core")
35aedd6be5SKyle Evanslocal screen = require("screen")
36088b4f5fSWarner Losh
37aedd6be5SKyle Evanslocal drawer = {}
38c8518398SKyle Evans
391091c8feSKyle Evanslocal fbsd_brand
40aedd6be5SKyle Evanslocal none
4102122e53SKyle Evans
42a9edc01bSKyle Evanslocal menu_name_handlers
43a9edc01bSKyle Evanslocal branddefs
44a9edc01bSKyle Evanslocal logodefs
45a9edc01bSKyle Evanslocal brand_position
46a9edc01bSKyle Evanslocal logo_position
47a9edc01bSKyle Evanslocal menu_position
48a9edc01bSKyle Evanslocal frame_size
49a9edc01bSKyle Evanslocal default_shift
50a9edc01bSKyle Evanslocal shift
51a9edc01bSKyle Evans
52322a2dddSKyle Evanslocal function menuEntryName(drawing_menu, entry)
53a9edc01bSKyle Evans	local name_handler = menu_name_handlers[entry.entry_type]
54e15abd1fSKyle Evans
559f71d421SKyle Evans	if name_handler ~= nil then
56aedd6be5SKyle Evans		return name_handler(drawing_menu, entry)
57e15abd1fSKyle Evans	end
58a51f9f0cSKyle Evans	if type(entry.name) == "function" then
59aedd6be5SKyle Evans		return entry.name()
60e15abd1fSKyle Evans	end
61a51f9f0cSKyle Evans	return entry.name
62a51f9f0cSKyle Evansend
63e15abd1fSKyle Evans
64e21e1dbeSKyle Evanslocal function getBranddef(brand)
65e21e1dbeSKyle Evans	if brand == nil then
66e21e1dbeSKyle Evans		return nil
67e21e1dbeSKyle Evans	end
68e21e1dbeSKyle Evans	-- Look it up
69a9edc01bSKyle Evans	local branddef = branddefs[brand]
70e21e1dbeSKyle Evans
71e21e1dbeSKyle Evans	-- Try to pull it in
72e21e1dbeSKyle Evans	if branddef == nil then
73e21e1dbeSKyle Evans		try_include('brand-' .. brand)
74a9edc01bSKyle Evans		branddef = branddefs[brand]
75e21e1dbeSKyle Evans	end
76e21e1dbeSKyle Evans
77e21e1dbeSKyle Evans	return branddef
78e21e1dbeSKyle Evansend
79e21e1dbeSKyle Evans
801091c8feSKyle Evanslocal function getLogodef(logo)
81bbb516aeSKyle Evans	if logo == nil then
82bbb516aeSKyle Evans		return nil
83bbb516aeSKyle Evans	end
841091c8feSKyle Evans	-- Look it up
85a9edc01bSKyle Evans	local logodef = logodefs[logo]
861091c8feSKyle Evans
871091c8feSKyle Evans	-- Try to pull it in
881091c8feSKyle Evans	if logodef == nil then
891091c8feSKyle Evans		try_include('logo-' .. logo)
90a9edc01bSKyle Evans		logodef = logodefs[logo]
911091c8feSKyle Evans	end
921091c8feSKyle Evans
931091c8feSKyle Evans	return logodef
941091c8feSKyle Evansend
951091c8feSKyle Evans
966112ee09SKyle Evanslocal function draw(x, y, logo)
976112ee09SKyle Evans	for i = 1, #logo do
986112ee09SKyle Evans		screen.setcursor(x, y + i - 1)
996112ee09SKyle Evans		printc(logo[i])
1006112ee09SKyle Evans	end
1016112ee09SKyle Evansend
1026112ee09SKyle Evans
10312eaa305SKyle Evanslocal function drawmenu(menudef)
104a9edc01bSKyle Evans	local x = menu_position.x
105a9edc01bSKyle Evans	local y = menu_position.y
10612eaa305SKyle Evans
107a9edc01bSKyle Evans	x = x + shift.x
108a9edc01bSKyle Evans	y = y + shift.y
10912eaa305SKyle Evans
11012eaa305SKyle Evans	-- print the menu and build the alias table
11112eaa305SKyle Evans	local alias_table = {}
11212eaa305SKyle Evans	local entry_num = 0
11312eaa305SKyle Evans	local menu_entries = menudef.entries
11412eaa305SKyle Evans	local effective_line_num = 0
11512eaa305SKyle Evans	if type(menu_entries) == "function" then
11612eaa305SKyle Evans		menu_entries = menu_entries()
11712eaa305SKyle Evans	end
11812eaa305SKyle Evans	for _, e in ipairs(menu_entries) do
11912eaa305SKyle Evans		-- Allow menu items to be conditionally visible by specifying
12012eaa305SKyle Evans		-- a visible function.
12112eaa305SKyle Evans		if e.visible ~= nil and not e.visible() then
12212eaa305SKyle Evans			goto continue
12312eaa305SKyle Evans		end
12412eaa305SKyle Evans		effective_line_num = effective_line_num + 1
12512eaa305SKyle Evans		if e.entry_type ~= core.MENU_SEPARATOR then
12612eaa305SKyle Evans			entry_num = entry_num + 1
12712eaa305SKyle Evans			screen.setcursor(x, y + effective_line_num)
12812eaa305SKyle Evans
12912eaa305SKyle Evans			printc(entry_num .. ". " .. menuEntryName(menudef, e))
13012eaa305SKyle Evans
13112eaa305SKyle Evans			-- fill the alias table
13212eaa305SKyle Evans			alias_table[tostring(entry_num)] = e
13312eaa305SKyle Evans			if e.alias ~= nil then
13412eaa305SKyle Evans				for _, a in ipairs(e.alias) do
13512eaa305SKyle Evans					alias_table[a] = e
13612eaa305SKyle Evans				end
13712eaa305SKyle Evans			end
13812eaa305SKyle Evans		else
13912eaa305SKyle Evans			screen.setcursor(x, y + effective_line_num)
14012eaa305SKyle Evans			printc(menuEntryName(menudef, e))
14112eaa305SKyle Evans		end
14212eaa305SKyle Evans		::continue::
14312eaa305SKyle Evans	end
14412eaa305SKyle Evans	return alias_table
14512eaa305SKyle Evansend
14612eaa305SKyle Evans
14790a25417SKyle Evanslocal function defaultframe()
14890a25417SKyle Evans	if core.isSerialConsole() then
14990a25417SKyle Evans		return "ascii"
15090a25417SKyle Evans	end
15190a25417SKyle Evans	return "double"
15290a25417SKyle Evansend
15390a25417SKyle Evans
15412eaa305SKyle Evanslocal function drawbox()
155a9edc01bSKyle Evans	local x = menu_position.x - 3
156a9edc01bSKyle Evans	local y = menu_position.y - 1
157a9edc01bSKyle Evans	local w = frame_size.w
158a9edc01bSKyle Evans	local h = frame_size.h
15912eaa305SKyle Evans
16090a25417SKyle Evans	local framestyle = loader.getenv("loader_menu_frame") or defaultframe()
16112eaa305SKyle Evans	local framespec = drawer.frame_styles[framestyle]
16212eaa305SKyle Evans	-- If we don't have a framespec for the current frame style, just don't
16312eaa305SKyle Evans	-- draw a box.
16412eaa305SKyle Evans	if framespec == nil then
16512eaa305SKyle Evans		return
16612eaa305SKyle Evans	end
16712eaa305SKyle Evans
16812eaa305SKyle Evans	local hl = framespec.horizontal
16912eaa305SKyle Evans	local vl = framespec.vertical
17012eaa305SKyle Evans
17112eaa305SKyle Evans	local tl = framespec.top_left
17212eaa305SKyle Evans	local bl = framespec.bottom_left
17312eaa305SKyle Evans	local tr = framespec.top_right
17412eaa305SKyle Evans	local br = framespec.bottom_right
17512eaa305SKyle Evans
176a9edc01bSKyle Evans	x = x + shift.x
177a9edc01bSKyle Evans	y = y + shift.y
17812eaa305SKyle Evans
17912eaa305SKyle Evans	screen.setcursor(x, y); printc(tl)
18012eaa305SKyle Evans	screen.setcursor(x, y + h); printc(bl)
18112eaa305SKyle Evans	screen.setcursor(x + w, y); printc(tr)
18212eaa305SKyle Evans	screen.setcursor(x + w, y + h); printc(br)
18312eaa305SKyle Evans
18412eaa305SKyle Evans	screen.setcursor(x + 1, y)
18512eaa305SKyle Evans	for _ = 1, w - 1 do
18612eaa305SKyle Evans		printc(hl)
18712eaa305SKyle Evans	end
18812eaa305SKyle Evans
18912eaa305SKyle Evans	screen.setcursor(x + 1, y + h)
19012eaa305SKyle Evans	for _ = 1, w - 1 do
19112eaa305SKyle Evans		printc(hl)
19212eaa305SKyle Evans	end
19312eaa305SKyle Evans
19412eaa305SKyle Evans	for i = 1, h - 1 do
19512eaa305SKyle Evans		screen.setcursor(x, y + i)
19612eaa305SKyle Evans		printc(vl)
19712eaa305SKyle Evans		screen.setcursor(x + w, y + i)
19812eaa305SKyle Evans		printc(vl)
19912eaa305SKyle Evans	end
20012eaa305SKyle Evans
20112eaa305SKyle Evans	local menu_header = loader.getenv("loader_menu_title") or
20212eaa305SKyle Evans	    "Welcome to FreeBSD"
20312eaa305SKyle Evans	local menu_header_align = loader.getenv("loader_menu_title_align")
20412eaa305SKyle Evans	local menu_header_x
20512eaa305SKyle Evans
20612eaa305SKyle Evans	if menu_header_align ~= nil then
20712eaa305SKyle Evans		menu_header_align = menu_header_align:lower()
20812eaa305SKyle Evans		if menu_header_align == "left" then
20912eaa305SKyle Evans			-- Just inside the left border on top
21012eaa305SKyle Evans			menu_header_x = x + 1
21112eaa305SKyle Evans		elseif menu_header_align == "right" then
21212eaa305SKyle Evans			-- Just inside the right border on top
21312eaa305SKyle Evans			menu_header_x = x + w - #menu_header
21412eaa305SKyle Evans		end
21512eaa305SKyle Evans	end
21612eaa305SKyle Evans	if menu_header_x == nil then
21712eaa305SKyle Evans		menu_header_x = x + (w / 2) - (#menu_header / 2)
21812eaa305SKyle Evans	end
21912eaa305SKyle Evans	screen.setcursor(menu_header_x, y)
22012eaa305SKyle Evans	printc(menu_header)
22112eaa305SKyle Evansend
22212eaa305SKyle Evans
22312eaa305SKyle Evanslocal function drawbrand()
22412eaa305SKyle Evans	local x = tonumber(loader.getenv("loader_brand_x")) or
225a9edc01bSKyle Evans	    brand_position.x
22612eaa305SKyle Evans	local y = tonumber(loader.getenv("loader_brand_y")) or
227a9edc01bSKyle Evans	    brand_position.y
22812eaa305SKyle Evans
22912eaa305SKyle Evans	local branddef = getBranddef(loader.getenv("loader_brand"))
23012eaa305SKyle Evans
23112eaa305SKyle Evans	if branddef == nil then
23212eaa305SKyle Evans		branddef = getBranddef(drawer.default_brand)
23312eaa305SKyle Evans	end
23412eaa305SKyle Evans
23512eaa305SKyle Evans	local graphic = branddef.graphic
23612eaa305SKyle Evans
237a9edc01bSKyle Evans	x = x + shift.x
238a9edc01bSKyle Evans	y = y + shift.y
23912eaa305SKyle Evans	draw(x, y, graphic)
24012eaa305SKyle Evansend
24112eaa305SKyle Evans
24212eaa305SKyle Evanslocal function drawlogo()
24312eaa305SKyle Evans	local x = tonumber(loader.getenv("loader_logo_x")) or
244a9edc01bSKyle Evans	    logo_position.x
24512eaa305SKyle Evans	local y = tonumber(loader.getenv("loader_logo_y")) or
246a9edc01bSKyle Evans	    logo_position.y
24712eaa305SKyle Evans
24812eaa305SKyle Evans	local logo = loader.getenv("loader_logo")
24912eaa305SKyle Evans	local colored = color.isEnabled()
25012eaa305SKyle Evans
25112eaa305SKyle Evans	local logodef = getLogodef(logo)
25212eaa305SKyle Evans
25312eaa305SKyle Evans	if logodef == nil or logodef.graphic == nil or
25412eaa305SKyle Evans	    (not colored and logodef.requires_color) then
25512eaa305SKyle Evans		-- Choose a sensible default
25612eaa305SKyle Evans		if colored then
2572c690e2aSKyle Evans			logodef = getLogodef(drawer.default_color_logodef)
25812eaa305SKyle Evans		else
2592c690e2aSKyle Evans			logodef = getLogodef(drawer.default_bw_logodef)
26012eaa305SKyle Evans		end
261*6697f577SKyle Evans
262*6697f577SKyle Evans		-- Something has gone terribly wrong.
263*6697f577SKyle Evans		if logodef == nil then
264*6697f577SKyle Evans			logodef = getLogodef(drawer.default_fallback_logodef)
265*6697f577SKyle Evans		end
26612eaa305SKyle Evans	end
26712eaa305SKyle Evans
26812eaa305SKyle Evans	if logodef ~= nil and logodef.graphic == none then
269a9edc01bSKyle Evans		shift = logodef.shift
27012eaa305SKyle Evans	else
271a9edc01bSKyle Evans		shift = default_shift
27212eaa305SKyle Evans	end
27312eaa305SKyle Evans
274a9edc01bSKyle Evans	x = x + shift.x
275a9edc01bSKyle Evans	y = y + shift.y
27612eaa305SKyle Evans
27712eaa305SKyle Evans	if logodef ~= nil and logodef.shift ~= nil then
27812eaa305SKyle Evans		x = x + logodef.shift.x
27912eaa305SKyle Evans		y = y + logodef.shift.y
28012eaa305SKyle Evans	end
28112eaa305SKyle Evans
28212eaa305SKyle Evans	draw(x, y, logodef.graphic)
28312eaa305SKyle Evansend
28412eaa305SKyle Evans
2851091c8feSKyle Evansfbsd_brand = {
286088b4f5fSWarner Losh"  ______               ____   _____ _____  ",
287088b4f5fSWarner Losh" |  ____|             |  _ \\ / ____|  __ \\ ",
288088b4f5fSWarner Losh" | |___ _ __ ___  ___ | |_) | (___ | |  | |",
289088b4f5fSWarner Losh" |  ___| '__/ _ \\/ _ \\|  _ < \\___ \\| |  | |",
290088b4f5fSWarner Losh" | |   | | |  __/  __/| |_) |____) | |__| |",
291088b4f5fSWarner Losh" | |   | | |    |    ||     |      |      |",
292088b4f5fSWarner Losh" |_|   |_|  \\___|\\___||____/|_____/|_____/ "
293aedd6be5SKyle Evans}
294aedd6be5SKyle Evansnone = {""}
295088b4f5fSWarner Losh
296a9edc01bSKyle Evansmenu_name_handlers = {
297b5746545SKyle Evans	-- Menu name handlers should take the menu being drawn and entry being
298b5746545SKyle Evans	-- drawn as parameters, and return the name of the item.
299b5746545SKyle Evans	-- This is designed so that everything, including menu separators, may
300b5746545SKyle Evans	-- have their names derived differently. The default action for entry
301a51f9f0cSKyle Evans	-- types not specified here is to use entry.name directly.
302e2df27e3SKyle Evans	[core.MENU_SEPARATOR] = function(_, entry)
303dd65496aSKyle Evans		if entry.name ~= nil then
304a51f9f0cSKyle Evans			if type(entry.name) == "function" then
305dd65496aSKyle Evans				return entry.name()
306dd65496aSKyle Evans			end
307a51f9f0cSKyle Evans			return entry.name
308a51f9f0cSKyle Evans		end
309dd65496aSKyle Evans		return ""
310dd65496aSKyle Evans	end,
311e2df27e3SKyle Evans	[core.MENU_CAROUSEL_ENTRY] = function(_, entry)
312aedd6be5SKyle Evans		local carid = entry.carousel_id
313aedd6be5SKyle Evans		local caridx = config.getCarouselIndex(carid)
3144f437f9eSKyle Evans		local choices = entry.items
3154f437f9eSKyle Evans		if type(choices) == "function" then
3164f437f9eSKyle Evans			choices = choices()
3174f437f9eSKyle Evans		end
3189f71d421SKyle Evans		if #choices < caridx then
319aedd6be5SKyle Evans			caridx = 1
320b5746545SKyle Evans		end
321aedd6be5SKyle Evans		return entry.name(caridx, choices[caridx], choices)
322b5746545SKyle Evans	end,
323aedd6be5SKyle Evans}
324b5746545SKyle Evans
325a9edc01bSKyle Evansbranddefs = {
326699578a6SKyle Evans	-- Indexed by valid values for loader_brand in loader.conf(5). Valid
327699578a6SKyle Evans	-- keys are: graphic (table depicting graphic)
32829aa5794SKyle Evans	["fbsd"] = {
3291091c8feSKyle Evans		graphic = fbsd_brand,
33029aa5794SKyle Evans	},
33129aa5794SKyle Evans	["none"] = {
33229aa5794SKyle Evans		graphic = none,
33329aa5794SKyle Evans	},
334aedd6be5SKyle Evans}
33529aa5794SKyle Evans
336a9edc01bSKyle Evanslogodefs = {
337bb26c57dSKyle Evans	-- Indexed by valid values for loader_logo in loader.conf(5). Valid keys
338752b2d40SKyle Evans	-- are: requires_color (boolean), graphic (table depicting graphic), and
339bb26c57dSKyle Evans	-- shift (table containing x and y).
340bb26c57dSKyle Evans	["tribute"] = {
3411091c8feSKyle Evans		graphic = fbsd_brand,
342bb26c57dSKyle Evans	},
343bb26c57dSKyle Evans	["tributebw"] = {
3441091c8feSKyle Evans		graphic = fbsd_brand,
345bb26c57dSKyle Evans	},
346bb26c57dSKyle Evans	["none"] = {
347752b2d40SKyle Evans		graphic = none,
348bb26c57dSKyle Evans		shift = {x = 17, y = 0},
349bb26c57dSKyle Evans	},
350aedd6be5SKyle Evans}
351bb26c57dSKyle Evans
352a9edc01bSKyle Evansbrand_position = {x = 2, y = 1}
353a9edc01bSKyle Evanslogo_position = {x = 46, y = 4}
354a9edc01bSKyle Evansmenu_position = {x = 5, y = 10}
355a9edc01bSKyle Evansframe_size = {w = 42, h = 13}
356a9edc01bSKyle Evansdefault_shift = {x = 0, y = 0}
357a9edc01bSKyle Evansshift = default_shift
358a9edc01bSKyle Evans
359a9edc01bSKyle Evans-- Module exports
360a9edc01bSKyle Evansdrawer.default_brand = 'fbsd'
3612c690e2aSKyle Evansdrawer.default_color_logodef = 'orb'
3622c690e2aSKyle Evansdrawer.default_bw_logodef = 'orbbw'
363*6697f577SKyle Evans-- For when things go terribly wrong; this def should be present here in the
364*6697f577SKyle Evans-- drawer module in case it's a filesystem issue.
365*6697f577SKyle Evansdrawer.default_fallback_logodef = 'none'
366a9edc01bSKyle Evans
367a9edc01bSKyle Evansfunction drawer.addBrand(name, def)
368a9edc01bSKyle Evans	branddefs[name] = def
369a9edc01bSKyle Evansend
370a9edc01bSKyle Evans
371a9edc01bSKyle Evansfunction drawer.addLogo(name, def)
372a9edc01bSKyle Evans	logodefs[name] = def
373a9edc01bSKyle Evansend
374a9edc01bSKyle Evans
375379e652eSKyle Evansdrawer.frame_styles = {
376379e652eSKyle Evans	-- Indexed by valid values for loader_menu_frame in loader.conf(5).
377379e652eSKyle Evans	-- All of the keys appearing below must be set for any menu frame style
378379e652eSKyle Evans	-- added to drawer.frame_styles.
379379e652eSKyle Evans	["ascii"] = {
380379e652eSKyle Evans		horizontal	= "-",
381379e652eSKyle Evans		vertical	= "|",
382379e652eSKyle Evans		top_left	= "+",
383379e652eSKyle Evans		bottom_left	= "+",
384379e652eSKyle Evans		top_right	= "+",
385379e652eSKyle Evans		bottom_right	= "+",
386379e652eSKyle Evans	},
387379e652eSKyle Evans	["single"] = {
38856758831SToomas Soome		horizontal	= "\xE2\x94\x80",
38956758831SToomas Soome		vertical	= "\xE2\x94\x82",
39056758831SToomas Soome		top_left	= "\xE2\x94\x8C",
39156758831SToomas Soome		bottom_left	= "\xE2\x94\x94",
39256758831SToomas Soome		top_right	= "\xE2\x94\x90",
39356758831SToomas Soome		bottom_right	= "\xE2\x94\x98",
394379e652eSKyle Evans	},
395379e652eSKyle Evans	["double"] = {
39656758831SToomas Soome		horizontal	= "\xE2\x95\x90",
39756758831SToomas Soome		vertical	= "\xE2\x95\x91",
39856758831SToomas Soome		top_left	= "\xE2\x95\x94",
39956758831SToomas Soome		bottom_left	= "\xE2\x95\x9A",
40056758831SToomas Soome		top_right	= "\xE2\x95\x97",
40156758831SToomas Soome		bottom_right	= "\xE2\x95\x9D",
402379e652eSKyle Evans	},
403379e652eSKyle Evans}
404379e652eSKyle Evans
40512eaa305SKyle Evansfunction drawer.drawscreen(menudef)
406088b4f5fSWarner Losh	-- drawlogo() must go first.
407088b4f5fSWarner Losh	-- it determines the positions of other elements
40812eaa305SKyle Evans	drawlogo()
40912eaa305SKyle Evans	drawbrand()
41012eaa305SKyle Evans	drawbox()
41112eaa305SKyle Evans	return drawmenu(menudef)
412088b4f5fSWarner Loshend
413088b4f5fSWarner Losh
414aedd6be5SKyle Evansreturn drawer
415