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