xref: /freebsd-12.1/stand/lua/drawer.lua (revision 94b8a54a)
1--
2-- Copyright (c) 2015 Pedro Souza <[email protected]>
3-- Copyright (c) 2018 Kyle Evans <[email protected]>
4-- All rights reserved.
5--
6-- Redistribution and use in source and binary forms, with or without
7-- modification, are permitted provided that the following conditions
8-- are met:
9-- 1. Redistributions of source code must retain the above copyright
10--    notice, this list of conditions and the following disclaimer.
11-- 2. Redistributions in binary form must reproduce the above copyright
12--    notice, this list of conditions and the following disclaimer in the
13--    documentation and/or other materials provided with the distribution.
14--
15-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25-- SUCH DAMAGE.
26--
27-- $FreeBSD$
28--
29
30local color = require("color")
31local config = require("config")
32local core = require("core")
33local screen = require("screen")
34
35local drawer = {}
36
37local fbsd_logo
38local beastie_color
39local beastie
40local fbsd_logo_v
41local orb_color
42local orb
43local none
44local none_shifted = false
45
46local menu_entry_name = function(drawing_menu, entry)
47	local name_handler = drawer.menu_name_handlers[entry.entry_type]
48
49	if name_handler ~= nil then
50		return name_handler(drawing_menu, entry)
51	end
52	if type(entry.name) == "function" then
53		return entry.name()
54	end
55	return entry.name
56end
57
58local shift_brand_text = function(shift)
59	drawer.brand_position.x = drawer.brand_position.x + shift.x
60	drawer.brand_position.y = drawer.brand_position.y + shift.y
61	drawer.menu_position.x = drawer.menu_position.x + shift.x
62	drawer.menu_position.y = drawer.menu_position.y + shift.y
63	drawer.box_pos_dim.x = drawer.box_pos_dim.x + shift.x
64	drawer.box_pos_dim.y = drawer.box_pos_dim.y + shift.y
65end
66
67fbsd_logo = {
68	"  ______               ____   _____ _____  ",
69	" |  ____|             |  _ \\ / ____|  __ \\ ",
70	" | |___ _ __ ___  ___ | |_) | (___ | |  | |",
71	" |  ___| '__/ _ \\/ _ \\|  _ < \\___ \\| |  | |",
72	" | |   | | |  __/  __/| |_) |____) | |__| |",
73	" | |   | | |    |    ||     |      |      |",
74	" |_|   |_|  \\___|\\___||____/|_____/|_____/ "
75}
76
77beastie_color = {
78	"               \027[31m,        ,",
79	"              /(        )`",
80	"              \\ \\___   / |",
81	"              /- \027[37m_\027[31m  `-/  '",
82	"             (\027[37m/\\/ \\\027[31m \\   /\\",
83	"             \027[37m/ /   |\027[31m `    \\",
84	"             \027[34mO O   \027[37m) \027[31m/    |",
85	"             \027[37m`-^--'\027[31m`<     '",
86	"            (_.)  _  )   /",
87	"             `.___/`    /",
88	"               `-----' /",
89	"  \027[33m<----.\027[31m     __ / __   \\",
90	"  \027[33m<----|====\027[31mO)))\027[33m==\027[31m) \\) /\027[33m====|",
91	"  \027[33m<----'\027[31m    `--' `.__,' \\",
92	"               |        |",
93	"                \\       /       /\\",
94	"           \027[36m______\027[31m( (_  / \\______/",
95	"         \027[36m,'  ,-----'   |",
96	"         `--{__________)\027[37m"
97}
98
99beastie = {
100	"               ,        ,",
101	"              /(        )`",
102	"              \\ \\___   / |",
103	"              /- _  `-/  '",
104	"             (/\\/ \\ \\   /\\",
105	"             / /   | `    \\",
106	"             O O   ) /    |",
107	"             `-^--'`<     '",
108	"            (_.)  _  )   /",
109	"             `.___/`    /",
110	"               `-----' /",
111	"  <----.     __ / __   \\",
112	"  <----|====O)))==) \\) /====|",
113	"  <----'    `--' `.__,' \\",
114	"               |        |",
115	"                \\       /       /\\",
116	"           ______( (_  / \\______/",
117	"         ,'  ,-----'   |",
118	"         `--{__________)"
119}
120
121fbsd_logo_v = {
122	"  ______",
123	" |  ____| __ ___  ___ ",
124	" | |__ | '__/ _ \\/ _ \\",
125	" |  __|| | |  __/  __/",
126	" | |   | | |    |    |",
127	" |_|   |_|  \\___|\\___|",
128	"  ____   _____ _____",
129	" |  _ \\ / ____|  __ \\",
130	" | |_) | (___ | |  | |",
131	" |  _ < \\___ \\| |  | |",
132	" | |_) |____) | |__| |",
133	" |     |      |      |",
134	" |____/|_____/|_____/"
135}
136
137orb_color = {
138	"  \027[31m```                        \027[31;1m`\027[31m",
139	" s` `.....---...\027[31;1m....--.```   -/\027[31m",
140	" +o   .--`         \027[31;1m/y:`      +.\027[31m",
141	"  yo`:.            \027[31;1m:o      `+-\027[31m",
142	"   y/               \027[31;1m-/`   -o/\027[31m",
143	"  .-                  \027[31;1m::/sy+:.\027[31m",
144	"  /                     \027[31;1m`--  /\027[31m",
145	" `:                          \027[31;1m:`\027[31m",
146	" `:                          \027[31;1m:`\027[31m",
147	"  /                          \027[31;1m/\027[31m",
148	"  .-                        \027[31;1m-.\027[31m",
149	"   --                      \027[31;1m-.\027[31m",
150	"    `:`                  \027[31;1m`:`",
151	"      \027[31;1m.--             `--.",
152	"         .---.....----.\027[37m"
153}
154
155orb = {
156	"  ```                        `",
157	" s` `.....---.......--.```   -/",
158	" +o   .--`         /y:`      +.",
159	"  yo`:.            :o      `+-",
160	"   y/               -/`   -o/",
161	"  .-                  ::/sy+:.",
162	"  /                     `--  /",
163	" `:                          :`",
164	" `:                          :`",
165	"  /                          /",
166	"  .-                        -.",
167	"   --                      -.",
168	"    `:`                  `:`",
169	"      .--             `--.",
170	"         .---.....----."
171}
172
173none = {""}
174
175-- Module exports
176drawer.menu_name_handlers = {
177	-- Menu name handlers should take the menu being drawn and entry being
178	-- drawn as parameters, and return the name of the item.
179	-- This is designed so that everything, including menu separators, may
180	-- have their names derived differently. The default action for entry
181	-- types not specified here is to use entry.name directly.
182	[core.MENU_SEPARATOR] = function(_, entry)
183		if entry.name ~= nil then
184			if type(entry.name) == "function" then
185				return entry.name()
186			end
187			return entry.name
188		end
189		return ""
190	end,
191	[core.MENU_CAROUSEL_ENTRY] = function(_, entry)
192		local carid = entry.carousel_id
193		local caridx = config.getCarouselIndex(carid)
194		local choices = entry.items
195		if type(choices) == "function" then
196			choices = choices()
197		end
198		if #choices < caridx then
199			caridx = 1
200		end
201		return entry.name(caridx, choices[caridx], choices)
202	end,
203}
204
205drawer.brand_position = {x = 2, y = 1}
206drawer.logo_position = {x = 46, y = 1}
207drawer.menu_position = {x = 6, y = 11}
208drawer.box_pos_dim = {x = 3, y = 10, w = 41, h = 11}
209
210drawer.branddefs = {
211	-- Indexed by valid values for loader_brand in loader.conf(5). Valid
212	-- keys are: graphic (table depicting graphic)
213	["fbsd"] = {
214		graphic = fbsd_logo,
215	},
216	["none"] = {
217		graphic = none,
218	},
219}
220
221drawer.logodefs = {
222	-- Indexed by valid values for loader_logo in loader.conf(5). Valid keys
223	-- are: requires_color (boolean), graphic (table depicting graphic), and
224	-- shift (table containing x and y).
225	["beastie"] = {
226		requires_color = true,
227		graphic = beastie_color,
228	},
229	["beastiebw"] = {
230		graphic = beastie,
231	},
232	["fbsdbw"] = {
233		graphic = fbsd_logo_v,
234		shift = {x = 5, y = 4},
235	},
236	["orb"] = {
237		requires_color = true,
238		graphic = orb_color,
239		shift = {x = 2, y = 4},
240	},
241	["orbbw"] = {
242		graphic = orb,
243		shift = {x = 2, y = 4},
244	},
245	["tribute"] = {
246		graphic = fbsd_logo,
247	},
248	["tributebw"] = {
249		graphic = fbsd_logo,
250	},
251	["none"] = {
252		graphic = none,
253		shift = {x = 17, y = 0},
254	},
255}
256
257function drawer.drawscreen(menu_opts)
258	-- drawlogo() must go first.
259	-- it determines the positions of other elements
260	drawer.drawlogo()
261	drawer.drawbrand()
262	drawer.drawbox()
263	return drawer.drawmenu(menu_opts)
264end
265
266function drawer.drawmenu(m)
267	local x = drawer.menu_position.x
268	local y = drawer.menu_position.y
269
270	-- print the menu and build the alias table
271	local alias_table = {}
272	local entry_num = 0
273	local menu_entries = m.entries
274	if type(menu_entries) == "function" then
275		menu_entries = menu_entries()
276	end
277	for line_num, e in ipairs(menu_entries) do
278		-- Allow menu items to be conditionally visible by specifying
279		-- a visible function.
280		if e.visible ~= nil and not e.visible() then
281			goto continue
282		end
283		if e.entry_type ~= core.MENU_SEPARATOR then
284			entry_num = entry_num + 1
285			screen.setcursor(x, y + line_num)
286
287			print(entry_num .. ". " .. menu_entry_name(m, e))
288
289			-- fill the alias table
290			alias_table[tostring(entry_num)] = e
291			if e.alias ~= nil then
292				for _, a in ipairs(e.alias) do
293					alias_table[a] = e
294				end
295			end
296		else
297			screen.setcursor(x, y + line_num)
298			print(menu_entry_name(m, e))
299		end
300		::continue::
301	end
302	return alias_table
303end
304
305
306function drawer.drawbox()
307	local x = drawer.box_pos_dim.x
308	local y = drawer.box_pos_dim.y
309	local w = drawer.box_pos_dim.w
310	local h = drawer.box_pos_dim.h
311
312	local hl = string.char(0xCD)
313	local vl = string.char(0xBA)
314
315	local tl = string.char(0xC9)
316	local bl = string.char(0xC8)
317	local tr = string.char(0xBB)
318	local br = string.char(0xBC)
319
320	screen.setcursor(x, y); print(tl)
321	screen.setcursor(x, y+h); print(bl)
322	screen.setcursor(x+w, y); print(tr)
323	screen.setcursor(x+w, y+h); print(br)
324
325	for i = 1, w-1 do
326		screen.setcursor(x+i, y)
327		print(hl)
328		screen.setcursor(x+i, y+h)
329		print(hl)
330	end
331
332	for i = 1, h-1 do
333		screen.setcursor(x, y+i)
334		print(vl)
335		screen.setcursor(x+w, y+i)
336		print(vl)
337	end
338
339	screen.setcursor(x+(w/2)-9, y)
340	print("Welcome to FreeBSD")
341end
342
343function drawer.draw(x, y, logo)
344	for i = 1, #logo do
345		screen.setcursor(x, y + i)
346		print(logo[i])
347	end
348end
349
350function drawer.drawbrand()
351	local x = tonumber(loader.getenv("loader_brand_x")) or
352	    drawer.brand_position.x
353	local y = tonumber(loader.getenv("loader_brand_y")) or
354	    drawer.brand_position.y
355
356	local graphic = drawer.branddefs[loader.getenv("loader_brand")]
357	if graphic == nil then
358		graphic = fbsd_logo
359	end
360	drawer.draw(x, y, graphic)
361end
362
363function drawer.drawlogo()
364	local x = tonumber(loader.getenv("loader_logo_x")) or
365	    drawer.logo_position.x
366	local y = tonumber(loader.getenv("loader_logo_y")) or
367	    drawer.logo_position.y
368
369	local logo = loader.getenv("loader_logo")
370	local colored = color.isEnabled()
371
372	-- Lookup
373	local logodef = drawer.logodefs[logo]
374
375	if logodef ~= nil and logodef.graphic == none then
376		-- centre brand and text if no logo
377		if not none_shifted then
378			shift_brand_text(logodef.shift)
379			none_shifted = true
380		end
381	elseif logodef == nil or logodef.graphic == nil or
382	    (not colored and logodef.requires_color) then
383		-- Choose a sensible default
384		if colored then
385			logodef = drawer.logodefs["orb"]
386		else
387			logodef = drawer.logodefs["orbbw"]
388		end
389	end
390	if logodef.shift ~= nil then
391		x = x + logodef.shift.x
392		y = y + logodef.shift.y
393	end
394	drawer.draw(x, y, logodef.graphic)
395end
396
397return drawer
398