1088b4f5fSWarner Losh-- 272e39d71SKyle Evans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD 372e39d71SKyle Evans-- 4088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 5df74a61fSKyle Evans-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 6088b4f5fSWarner Losh-- All rights reserved. 7088b4f5fSWarner Losh-- 8088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 9088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 10088b4f5fSWarner Losh-- are met: 11088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 12088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 13088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 14088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 15088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 16088b4f5fSWarner Losh-- 17088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27088b4f5fSWarner Losh-- SUCH DAMAGE. 28088b4f5fSWarner Losh-- 29088b4f5fSWarner Losh-- $FreeBSD$ 30088b4f5fSWarner Losh-- 31088b4f5fSWarner Losh 32aedd6be5SKyle Evanslocal color = require("color") 33aedd6be5SKyle Evanslocal config = require("config") 34aedd6be5SKyle Evanslocal core = require("core") 35aedd6be5SKyle Evanslocal screen = require("screen") 36088b4f5fSWarner Losh 37aedd6be5SKyle Evanslocal drawer = {} 38c8518398SKyle Evans 391091c8feSKyle Evanslocal fbsd_brand 40aedd6be5SKyle Evanslocal none 4102122e53SKyle Evans 42322a2dddSKyle Evanslocal function menuEntryName(drawing_menu, entry) 43aedd6be5SKyle Evans local name_handler = drawer.menu_name_handlers[entry.entry_type] 44e15abd1fSKyle Evans 459f71d421SKyle Evans if name_handler ~= nil then 46aedd6be5SKyle Evans return name_handler(drawing_menu, entry) 47e15abd1fSKyle Evans end 48a51f9f0cSKyle Evans if type(entry.name) == "function" then 49aedd6be5SKyle Evans return entry.name() 50e15abd1fSKyle Evans end 51a51f9f0cSKyle Evans return entry.name 52a51f9f0cSKyle Evansend 53e15abd1fSKyle Evans 54*e21e1dbeSKyle Evanslocal function getBranddef(brand) 55*e21e1dbeSKyle Evans if brand == nil then 56*e21e1dbeSKyle Evans return nil 57*e21e1dbeSKyle Evans end 58*e21e1dbeSKyle Evans -- Look it up 59*e21e1dbeSKyle Evans local branddef = drawer.branddefs[brand] 60*e21e1dbeSKyle Evans 61*e21e1dbeSKyle Evans -- Try to pull it in 62*e21e1dbeSKyle Evans if branddef == nil then 63*e21e1dbeSKyle Evans try_include('brand-' .. brand) 64*e21e1dbeSKyle Evans branddef = drawer.branddefs[brand] 65*e21e1dbeSKyle Evans end 66*e21e1dbeSKyle Evans 67*e21e1dbeSKyle Evans return branddef 68*e21e1dbeSKyle Evansend 69*e21e1dbeSKyle Evans 701091c8feSKyle Evanslocal function getLogodef(logo) 71bbb516aeSKyle Evans if logo == nil then 72bbb516aeSKyle Evans return nil 73bbb516aeSKyle Evans end 741091c8feSKyle Evans -- Look it up 751091c8feSKyle Evans local logodef = drawer.logodefs[logo] 761091c8feSKyle Evans 771091c8feSKyle Evans -- Try to pull it in 781091c8feSKyle Evans if logodef == nil then 791091c8feSKyle Evans try_include('logo-' .. logo) 801091c8feSKyle Evans logodef = drawer.logodefs[logo] 811091c8feSKyle Evans end 821091c8feSKyle Evans 831091c8feSKyle Evans return logodef 841091c8feSKyle Evansend 851091c8feSKyle Evans 861091c8feSKyle Evansfbsd_brand = { 87088b4f5fSWarner Losh" ______ ____ _____ _____ ", 88088b4f5fSWarner Losh" | ____| | _ \\ / ____| __ \\ ", 89088b4f5fSWarner Losh" | |___ _ __ ___ ___ | |_) | (___ | | | |", 90088b4f5fSWarner Losh" | ___| '__/ _ \\/ _ \\| _ < \\___ \\| | | |", 91088b4f5fSWarner Losh" | | | | | __/ __/| |_) |____) | |__| |", 92088b4f5fSWarner Losh" | | | | | | || | | |", 93088b4f5fSWarner Losh" |_| |_| \\___|\\___||____/|_____/|_____/ " 94aedd6be5SKyle Evans} 95aedd6be5SKyle Evansnone = {""} 96088b4f5fSWarner Losh 97b5746545SKyle Evans-- Module exports 98*e21e1dbeSKyle Evansdrawer.default_brand = 'fbsd' 99*e21e1dbeSKyle Evans 100b5746545SKyle Evansdrawer.menu_name_handlers = { 101b5746545SKyle Evans -- Menu name handlers should take the menu being drawn and entry being 102b5746545SKyle Evans -- drawn as parameters, and return the name of the item. 103b5746545SKyle Evans -- This is designed so that everything, including menu separators, may 104b5746545SKyle Evans -- have their names derived differently. The default action for entry 105a51f9f0cSKyle Evans -- types not specified here is to use entry.name directly. 106e2df27e3SKyle Evans [core.MENU_SEPARATOR] = function(_, entry) 107dd65496aSKyle Evans if entry.name ~= nil then 108a51f9f0cSKyle Evans if type(entry.name) == "function" then 109dd65496aSKyle Evans return entry.name() 110dd65496aSKyle Evans end 111a51f9f0cSKyle Evans return entry.name 112a51f9f0cSKyle Evans end 113dd65496aSKyle Evans return "" 114dd65496aSKyle Evans end, 115e2df27e3SKyle Evans [core.MENU_CAROUSEL_ENTRY] = function(_, entry) 116aedd6be5SKyle Evans local carid = entry.carousel_id 117aedd6be5SKyle Evans local caridx = config.getCarouselIndex(carid) 1184f437f9eSKyle Evans local choices = entry.items 1194f437f9eSKyle Evans if type(choices) == "function" then 1204f437f9eSKyle Evans choices = choices() 1214f437f9eSKyle Evans end 1229f71d421SKyle Evans if #choices < caridx then 123aedd6be5SKyle Evans caridx = 1 124b5746545SKyle Evans end 125aedd6be5SKyle Evans return entry.name(caridx, choices[caridx], choices) 126b5746545SKyle Evans end, 127aedd6be5SKyle Evans} 128b5746545SKyle Evans 129aedd6be5SKyle Evansdrawer.brand_position = {x = 2, y = 1} 1301495c98fSKyle Evansdrawer.logo_position = {x = 46, y = 4} 1311495c98fSKyle Evansdrawer.menu_position = {x = 5, y = 10} 1321495c98fSKyle Evansdrawer.frame_size = {w = 42, h = 13} 1332d36799aSKyle Evansdrawer.default_shift = {x = 0, y = 0} 1342d36799aSKyle Evansdrawer.shift = drawer.default_shift 135b5746545SKyle Evans 13629aa5794SKyle Evansdrawer.branddefs = { 137699578a6SKyle Evans -- Indexed by valid values for loader_brand in loader.conf(5). Valid 138699578a6SKyle Evans -- keys are: graphic (table depicting graphic) 13929aa5794SKyle Evans ["fbsd"] = { 1401091c8feSKyle Evans graphic = fbsd_brand, 14129aa5794SKyle Evans }, 14229aa5794SKyle Evans ["none"] = { 14329aa5794SKyle Evans graphic = none, 14429aa5794SKyle Evans }, 145aedd6be5SKyle Evans} 14629aa5794SKyle Evans 1471091c8feSKyle Evansfunction drawer.addBrand(name, def) 1481091c8feSKyle Evans drawer.branddefs[name] = def 1491091c8feSKyle Evansend 1501091c8feSKyle Evans 1511091c8feSKyle Evansfunction drawer.addLogo(name, def) 1521091c8feSKyle Evans drawer.logodefs[name] = def 1531091c8feSKyle Evansend 1541091c8feSKyle Evans 155bb26c57dSKyle Evansdrawer.logodefs = { 156bb26c57dSKyle Evans -- Indexed by valid values for loader_logo in loader.conf(5). Valid keys 157752b2d40SKyle Evans -- are: requires_color (boolean), graphic (table depicting graphic), and 158bb26c57dSKyle Evans -- shift (table containing x and y). 159bb26c57dSKyle Evans ["tribute"] = { 1601091c8feSKyle Evans graphic = fbsd_brand, 161bb26c57dSKyle Evans }, 162bb26c57dSKyle Evans ["tributebw"] = { 1631091c8feSKyle Evans graphic = fbsd_brand, 164bb26c57dSKyle Evans }, 165bb26c57dSKyle Evans ["none"] = { 166752b2d40SKyle Evans graphic = none, 167bb26c57dSKyle Evans shift = {x = 17, y = 0}, 168bb26c57dSKyle Evans }, 169aedd6be5SKyle Evans} 170bb26c57dSKyle Evans 171379e652eSKyle Evansdrawer.frame_styles = { 172379e652eSKyle Evans -- Indexed by valid values for loader_menu_frame in loader.conf(5). 173379e652eSKyle Evans -- All of the keys appearing below must be set for any menu frame style 174379e652eSKyle Evans -- added to drawer.frame_styles. 175379e652eSKyle Evans ["ascii"] = { 176379e652eSKyle Evans horizontal = "-", 177379e652eSKyle Evans vertical = "|", 178379e652eSKyle Evans top_left = "+", 179379e652eSKyle Evans bottom_left = "+", 180379e652eSKyle Evans top_right = "+", 181379e652eSKyle Evans bottom_right = "+", 182379e652eSKyle Evans }, 183379e652eSKyle Evans ["single"] = { 184379e652eSKyle Evans horizontal = "\xC4", 185379e652eSKyle Evans vertical = "\xB3", 186379e652eSKyle Evans top_left = "\xDA", 187379e652eSKyle Evans bottom_left = "\xC0", 188379e652eSKyle Evans top_right = "\xBF", 189379e652eSKyle Evans bottom_right = "\xD9", 190379e652eSKyle Evans }, 191379e652eSKyle Evans ["double"] = { 192379e652eSKyle Evans horizontal = "\xCD", 193379e652eSKyle Evans vertical = "\xBA", 194379e652eSKyle Evans top_left = "\xC9", 195379e652eSKyle Evans bottom_left = "\xC8", 196379e652eSKyle Evans top_right = "\xBB", 197379e652eSKyle Evans bottom_right = "\xBC", 198379e652eSKyle Evans }, 199379e652eSKyle Evans} 200379e652eSKyle Evans 201088b4f5fSWarner Loshfunction drawer.drawscreen(menu_opts) 202088b4f5fSWarner Losh -- drawlogo() must go first. 203088b4f5fSWarner Losh -- it determines the positions of other elements 204aedd6be5SKyle Evans drawer.drawlogo() 205aedd6be5SKyle Evans drawer.drawbrand() 206aedd6be5SKyle Evans drawer.drawbox() 207aedd6be5SKyle Evans return drawer.drawmenu(menu_opts) 208088b4f5fSWarner Loshend 209088b4f5fSWarner Losh 21004af4229SKyle Evansfunction drawer.drawmenu(menudef) 211e2df27e3SKyle Evans local x = drawer.menu_position.x 212e2df27e3SKyle Evans local y = drawer.menu_position.y 213088b4f5fSWarner Losh 2142d36799aSKyle Evans x = x + drawer.shift.x 2152d36799aSKyle Evans y = y + drawer.shift.y 2162d36799aSKyle Evans 217088b4f5fSWarner Losh -- print the menu and build the alias table 218aedd6be5SKyle Evans local alias_table = {} 219aedd6be5SKyle Evans local entry_num = 0 22004af4229SKyle Evans local menu_entries = menudef.entries 2211afbc37aSKyle Evans local effective_line_num = 0 2229f71d421SKyle Evans if type(menu_entries) == "function" then 223aedd6be5SKyle Evans menu_entries = menu_entries() 2242e716cecSKyle Evans end 225d709f254SKyle Evans for _, e in ipairs(menu_entries) do 2264a4fb4f8SKyle Evans -- Allow menu items to be conditionally visible by specifying 2274a4fb4f8SKyle Evans -- a visible function. 2289f71d421SKyle Evans if e.visible ~= nil and not e.visible() then 229aedd6be5SKyle Evans goto continue 2304a4fb4f8SKyle Evans end 2311afbc37aSKyle Evans effective_line_num = effective_line_num + 1 2329f71d421SKyle Evans if e.entry_type ~= core.MENU_SEPARATOR then 233aedd6be5SKyle Evans entry_num = entry_num + 1 2341afbc37aSKyle Evans screen.setcursor(x, y + effective_line_num) 235ada26c4aSKyle Evans 2369895e5d4SKyle Evans printc(entry_num .. ". " .. menuEntryName(menudef, e)) 237088b4f5fSWarner Losh 238088b4f5fSWarner Losh -- fill the alias table 239aedd6be5SKyle Evans alias_table[tostring(entry_num)] = e 2409f71d421SKyle Evans if e.alias ~= nil then 241e2df27e3SKyle Evans for _, a in ipairs(e.alias) do 242aedd6be5SKyle Evans alias_table[a] = e 243088b4f5fSWarner Losh end 244196ba166SKyle Evans end 245088b4f5fSWarner Losh else 2461afbc37aSKyle Evans screen.setcursor(x, y + effective_line_num) 2479895e5d4SKyle Evans printc(menuEntryName(menudef, e)) 248088b4f5fSWarner Losh end 2494a4fb4f8SKyle Evans ::continue:: 250088b4f5fSWarner Losh end 251aedd6be5SKyle Evans return alias_table 252088b4f5fSWarner Loshend 253088b4f5fSWarner Losh 254088b4f5fSWarner Loshfunction drawer.drawbox() 2551495c98fSKyle Evans local x = drawer.menu_position.x - 3 2561495c98fSKyle Evans local y = drawer.menu_position.y - 1 2571495c98fSKyle Evans local w = drawer.frame_size.w 2581495c98fSKyle Evans local h = drawer.frame_size.h 259088b4f5fSWarner Losh 260379e652eSKyle Evans local framestyle = loader.getenv("loader_menu_frame") or "double" 261379e652eSKyle Evans local framespec = drawer.frame_styles[framestyle] 262379e652eSKyle Evans -- If we don't have a framespec for the current frame style, just don't 263379e652eSKyle Evans -- draw a box. 264379e652eSKyle Evans if framespec == nil then 265379e652eSKyle Evans return 266379e652eSKyle Evans end 267088b4f5fSWarner Losh 268379e652eSKyle Evans local hl = framespec.horizontal 269379e652eSKyle Evans local vl = framespec.vertical 270088b4f5fSWarner Losh 271379e652eSKyle Evans local tl = framespec.top_left 272379e652eSKyle Evans local bl = framespec.bottom_left 273379e652eSKyle Evans local tr = framespec.top_right 274379e652eSKyle Evans local br = framespec.bottom_right 275088b4f5fSWarner Losh 2762d36799aSKyle Evans x = x + drawer.shift.x 2772d36799aSKyle Evans y = y + drawer.shift.y 2782d36799aSKyle Evans 279223e9874SKyle Evans screen.setcursor(x, y); printc(tl) 280223e9874SKyle Evans screen.setcursor(x, y + h); printc(bl) 281223e9874SKyle Evans screen.setcursor(x + w, y); printc(tr) 282223e9874SKyle Evans screen.setcursor(x + w, y + h); printc(br) 283379e652eSKyle Evans 284379e652eSKyle Evans screen.setcursor(x + 1, y) 285379e652eSKyle Evans for _ = 1, w - 1 do 286223e9874SKyle Evans printc(hl) 287379e652eSKyle Evans end 288379e652eSKyle Evans 289379e652eSKyle Evans screen.setcursor(x + 1, y + h) 290379e652eSKyle Evans for _ = 1, w - 1 do 291223e9874SKyle Evans printc(hl) 292088b4f5fSWarner Losh end 293088b4f5fSWarner Losh 294088b4f5fSWarner Losh for i = 1, h - 1 do 295aedd6be5SKyle Evans screen.setcursor(x, y + i) 296223e9874SKyle Evans printc(vl) 297aedd6be5SKyle Evans screen.setcursor(x + w, y + i) 298223e9874SKyle Evans printc(vl) 299088b4f5fSWarner Losh end 300088b4f5fSWarner Losh 301953d8937SKyle Evans local menu_header = loader.getenv("loader_menu_title") or 302953d8937SKyle Evans "Welcome to FreeBSD" 303b4353326SKyle Evans local menu_header_align = loader.getenv("loader_menu_title_align") 304953d8937SKyle Evans local menu_header_x 305953d8937SKyle Evans 306b4353326SKyle Evans if menu_header_align ~= nil then 307b4353326SKyle Evans menu_header_align = menu_header_align:lower() 308b4353326SKyle Evans if menu_header_align == "left" then 309b4353326SKyle Evans -- Just inside the left border on top 310b4353326SKyle Evans menu_header_x = x + 1 311b4353326SKyle Evans elseif menu_header_align == "right" then 312b4353326SKyle Evans -- Just inside the right border on top 313b4353326SKyle Evans menu_header_x = x + w - #menu_header 314b4353326SKyle Evans end 315b4353326SKyle Evans end 316b4353326SKyle Evans if menu_header_x == nil then 317953d8937SKyle Evans menu_header_x = x + (w / 2) - (#menu_header / 2) 318b4353326SKyle Evans end 319953d8937SKyle Evans screen.setcursor(menu_header_x, y) 320953d8937SKyle Evans printc(menu_header) 321088b4f5fSWarner Loshend 322088b4f5fSWarner Losh 323088b4f5fSWarner Loshfunction drawer.draw(x, y, logo) 324088b4f5fSWarner Losh for i = 1, #logo do 3251495c98fSKyle Evans screen.setcursor(x, y + i - 1) 3261495c98fSKyle Evans printc(logo[i]) 327088b4f5fSWarner Losh end 328088b4f5fSWarner Loshend 329088b4f5fSWarner Losh 330088b4f5fSWarner Loshfunction drawer.drawbrand() 33124a1bd54SKyle Evans local x = tonumber(loader.getenv("loader_brand_x")) or 332aedd6be5SKyle Evans drawer.brand_position.x 33324a1bd54SKyle Evans local y = tonumber(loader.getenv("loader_brand_y")) or 334aedd6be5SKyle Evans drawer.brand_position.y 335088b4f5fSWarner Losh 336*e21e1dbeSKyle Evans local branddef = getBranddef(loader.getenv("loader_brand")) 337*e21e1dbeSKyle Evans 338*e21e1dbeSKyle Evans if branddef == nil then 339*e21e1dbeSKyle Evans branddef = getBranddef(drawer.default_brand) 340*e21e1dbeSKyle Evans end 341*e21e1dbeSKyle Evans 342*e21e1dbeSKyle Evans local graphic = branddef.graphic 3432d36799aSKyle Evans 3442d36799aSKyle Evans x = x + drawer.shift.x 3452d36799aSKyle Evans y = y + drawer.shift.y 346aedd6be5SKyle Evans drawer.draw(x, y, graphic) 347088b4f5fSWarner Loshend 348088b4f5fSWarner Losh 349088b4f5fSWarner Loshfunction drawer.drawlogo() 35024a1bd54SKyle Evans local x = tonumber(loader.getenv("loader_logo_x")) or 351aedd6be5SKyle Evans drawer.logo_position.x 35224a1bd54SKyle Evans local y = tonumber(loader.getenv("loader_logo_y")) or 353aedd6be5SKyle Evans drawer.logo_position.y 354088b4f5fSWarner Losh 355aedd6be5SKyle Evans local logo = loader.getenv("loader_logo") 356aedd6be5SKyle Evans local colored = color.isEnabled() 357088b4f5fSWarner Losh 3581091c8feSKyle Evans local logodef = getLogodef(logo) 359bb26c57dSKyle Evans 3602d36799aSKyle Evans if logodef == nil or logodef.graphic == nil or 3619f71d421SKyle Evans (not colored and logodef.requires_color) then 362bb26c57dSKyle Evans -- Choose a sensible default 3639f71d421SKyle Evans if colored then 3641091c8feSKyle Evans logodef = getLogodef("orb") 365088b4f5fSWarner Losh else 3661091c8feSKyle Evans logodef = getLogodef("orbbw") 367088b4f5fSWarner Losh end 368088b4f5fSWarner Losh end 3692d36799aSKyle Evans 3702d36799aSKyle Evans if logodef ~= nil and logodef.graphic == none then 3712d36799aSKyle Evans drawer.shift = logodef.shift 3722d36799aSKyle Evans else 3732d36799aSKyle Evans drawer.shift = drawer.default_shift 3742d36799aSKyle Evans end 3752d36799aSKyle Evans 3762d36799aSKyle Evans x = x + drawer.shift.x 3772d36799aSKyle Evans y = y + drawer.shift.y 3782d36799aSKyle Evans 3792ed9eb5dSKyle Evans if logodef ~= nil and logodef.shift ~= nil then 380aedd6be5SKyle Evans x = x + logodef.shift.x 381aedd6be5SKyle Evans y = y + logodef.shift.y 382bb26c57dSKyle Evans end 3832d36799aSKyle Evans 384aedd6be5SKyle Evans drawer.draw(x, y, logodef.graphic) 385088b4f5fSWarner Loshend 386088b4f5fSWarner Losh 387aedd6be5SKyle Evansreturn drawer 388