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