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