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 core = require("core"); 32local screen = require("screen"); 33 34local drawer = {}; 35 36local fbsd_logo; 37local beastie_color; 38local beastie; 39local fbsd_logo_v; 40local orb; 41local none; 42local none_shifted = false; 43 44drawer.menu_name_handlers = { 45 -- Menu name handlers should take the menu being drawn and entry being 46 -- drawn as parameters, and return the name of the item. 47 -- This is designed so that everything, including menu separators, may 48 -- have their names derived differently. The default action for entry 49 -- types not specified here is to call and use entry.name(). 50 [core.MENU_CAROUSEL_ENTRY] = function(drawing_menu, entry) 51 local carid = entry.carousel_id; 52 local caridx = menu.getCarouselIndex(carid); 53 local choices = entry.items(); 54 55 if (#choices < caridx) then 56 caridx = 1; 57 end 58 return entry.name(caridx, choices[caridx], choices); 59 end, 60}; 61 62drawer.brand_position = {x = 2, y = 1}; 63drawer.logo_position = {x = 46, y = 1}; 64drawer.menu_position = {x = 6, y = 11}; 65drawer.box_pos_dim = {x = 3, y = 10, w = 41, h = 11}; 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 175drawer.branddefs = { 176 -- Indexed by valid values for loader_brand in loader.conf(5). Valid 177 -- keys are: graphic (table depicting graphic) 178 ["fbsd"] = { 179 graphic = fbsd_logo, 180 }, 181 ["none"] = { 182 graphic = none, 183 }, 184}; 185 186drawer.logodefs = { 187 -- Indexed by valid values for loader_logo in loader.conf(5). Valid keys 188 -- are: requires_color (boolean), graphic (table depicting graphic), and 189 -- shift (table containing x and y). 190 ["beastie"] = { 191 requires_color = true, 192 graphic = beastie_color, 193 }, 194 ["beastiebw"] = { 195 graphic = beastie, 196 }, 197 ["fbsdbw"] = { 198 graphic = fbsd_logo_v, 199 shift = {x = 5, y = 4}, 200 }, 201 ["orb"] = { 202 requires_color = true, 203 graphic = orb_color, 204 shift = {x = 2, y = 4}, 205 }, 206 ["orbbw"] = { 207 graphic = orb, 208 shift = {x = 2, y = 4}, 209 }, 210 ["tribute"] = { 211 graphic = fbsd_logo, 212 }, 213 ["tributebw"] = { 214 graphic = fbsd_logo, 215 }, 216 ["none"] = { 217 graphic = none, 218 shift = {x = 17, y = 0}, 219 }, 220}; 221 222function drawer.drawscreen(menu_opts) 223 -- drawlogo() must go first. 224 -- it determines the positions of other elements 225 drawer.drawlogo(); 226 drawer.drawbrand(); 227 drawer.drawbox(); 228 return drawer.drawmenu(menu_opts); 229end 230 231function menu_entry_name(drawing_menu, entry) 232 local name_handler = drawer.menu_name_handlers[entry.entry_type]; 233 234 if (name_handler ~= nil) then 235 return name_handler(drawing_menu, entry); 236 end 237 return entry.name(); 238end 239 240function drawer.drawmenu(m) 241 x = drawer.menu_position.x; 242 y = drawer.menu_position.y; 243 244 -- print the menu and build the alias table 245 local alias_table = {}; 246 local entry_num = 0; 247 local menu_entries = m.entries; 248 if (type(menu_entries) == "function") then 249 menu_entries = menu_entries(); 250 end 251 for line_num, e in ipairs(menu_entries) do 252 -- Allow menu items to be conditionally visible by specifying 253 -- a visible function. 254 if (e.visible ~= nil) and (not e.visible()) then 255 goto continue; 256 end 257 if (e.entry_type ~= core.MENU_SEPARATOR) then 258 entry_num = entry_num + 1; 259 screen.setcursor(x, y + line_num); 260 261 print(entry_num .. ". " .. menu_entry_name(m, e)); 262 263 -- fill the alias table 264 alias_table[tostring(entry_num)] = e; 265 if (e.alias ~= nil) then 266 for n, a in ipairs(e.alias) do 267 alias_table[a] = e; 268 end 269 end 270 else 271 screen.setcursor(x, y + line_num); 272 print(menu_entry_name(m, e)); 273 end 274 ::continue:: 275 end 276 return alias_table; 277end 278 279 280function drawer.drawbox() 281 x = drawer.box_pos_dim.x; 282 y = drawer.box_pos_dim.y; 283 w = drawer.box_pos_dim.w; 284 h = drawer.box_pos_dim.h; 285 286 local hl = string.char(0xCD); 287 local vl = string.char(0xBA); 288 289 local tl = string.char(0xC9); 290 local bl = string.char(0xC8); 291 local tr = string.char(0xBB); 292 local br = string.char(0xBC); 293 294 screen.setcursor(x, y); print(tl); 295 screen.setcursor(x, y+h); print(bl); 296 screen.setcursor(x+w, y); print(tr); 297 screen.setcursor(x+w, y+h); print(br); 298 299 for i = 1, w-1 do 300 screen.setcursor(x+i, y); 301 print(hl); 302 screen.setcursor(x+i, y+h); 303 print(hl); 304 end 305 306 for i = 1, h-1 do 307 screen.setcursor(x, y+i); 308 print(vl); 309 screen.setcursor(x+w, y+i); 310 print(vl); 311 end 312 313 screen.setcursor(x+(w/2)-9, y); 314 print("Welcome to FreeBSD"); 315end 316 317function drawer.draw(x, y, logo) 318 for i = 1, #logo do 319 screen.setcursor(x, y + i); 320 print(logo[i]); 321 end 322end 323 324function drawer.drawbrand() 325 local x = tonumber(loader.getenv("loader_brand_x")) or 326 drawer.brand_position.x; 327 local y = tonumber(loader.getenv("loader_brand_y")) or 328 drawer.brand_position.y; 329 330 local graphic = drawer.branddefs[loader.getenv("loader_brand")]; 331 if (graphic == nil) then 332 graphic = fbsd_logo; 333 end 334 drawer.draw(x, y, graphic); 335end 336 337function shift_brand_text(shift) 338 drawer.brand_position.x = drawer.brand_position.x + shift.x; 339 drawer.brand_position.y = drawer.brand_position.y + shift.y; 340 drawer.menu_position.x = drawer.menu_position.x + shift.x; 341 drawer.menu_position.y = drawer.menu_position.y + shift.y; 342 drawer.box_pos_dim.x = drawer.box_pos_dim.x + shift.x; 343 drawer.box_pos_dim.y = drawer.box_pos_dim.y + shift.y; 344end 345 346function drawer.drawlogo() 347 local x = tonumber(loader.getenv("loader_logo_x")) or 348 drawer.logo_position.x; 349 local y = tonumber(loader.getenv("loader_logo_y")) or 350 drawer.logo_position.y; 351 352 local logo = loader.getenv("loader_logo"); 353 local colored = color.isEnabled(); 354 355 -- Lookup 356 local logodef = drawer.logodefs[logo]; 357 358 if (logodef ~= nil) and (logodef.graphic == none) then 359 -- centre brand and text if no logo 360 if (not none_shifted) then 361 shift_brand_text(logodef.shift); 362 none_shifted = true; 363 end 364 elseif (logodef == nil) or (logodef.graphic == nil) or 365 ((not colored) and logodef.requires_color) then 366 -- Choose a sensible default 367 if (colored) then 368 logodef = drawer.logodefs["orb"]; 369 else 370 logodef = drawer.logodefs["orbbw"]; 371 end 372 end 373 if (logodef.shift ~= nil) then 374 x = x + logodef.shift.x; 375 y = y + logodef.shift.y; 376 end 377 drawer.draw(x, y, logodef.graphic); 378end 379 380return drawer; 381