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