1088b4f5fSWarner Losh-- 2088b4f5fSWarner Losh-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org> 3df74a61fSKyle Evans-- Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org> 4088b4f5fSWarner Losh-- All rights reserved. 5088b4f5fSWarner Losh-- 6088b4f5fSWarner Losh-- Redistribution and use in source and binary forms, with or without 7088b4f5fSWarner Losh-- modification, are permitted provided that the following conditions 8088b4f5fSWarner Losh-- are met: 9088b4f5fSWarner Losh-- 1. Redistributions of source code must retain the above copyright 10088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer. 11088b4f5fSWarner Losh-- 2. Redistributions in binary form must reproduce the above copyright 12088b4f5fSWarner Losh-- notice, this list of conditions and the following disclaimer in the 13088b4f5fSWarner Losh-- documentation and/or other materials provided with the distribution. 14088b4f5fSWarner Losh-- 15088b4f5fSWarner Losh-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16088b4f5fSWarner Losh-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17088b4f5fSWarner Losh-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18088b4f5fSWarner Losh-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19088b4f5fSWarner Losh-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20088b4f5fSWarner Losh-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21088b4f5fSWarner Losh-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22088b4f5fSWarner Losh-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23088b4f5fSWarner Losh-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24088b4f5fSWarner Losh-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25088b4f5fSWarner Losh-- SUCH DAMAGE. 26088b4f5fSWarner Losh-- 27088b4f5fSWarner Losh-- $FreeBSD$ 28088b4f5fSWarner Losh-- 29088b4f5fSWarner Losh 30aedd6be5SKyle Evanslocal color = require("color") 31aedd6be5SKyle Evanslocal config = require("config") 32aedd6be5SKyle Evanslocal core = require("core") 33aedd6be5SKyle Evanslocal screen = require("screen") 34088b4f5fSWarner Losh 35aedd6be5SKyle Evanslocal drawer = {} 36c8518398SKyle Evans 37aedd6be5SKyle Evanslocal fbsd_logo 38aedd6be5SKyle Evanslocal beastie_color 39aedd6be5SKyle Evanslocal beastie 40aedd6be5SKyle Evanslocal fbsd_logo_v 41aedd6be5SKyle Evanslocal orb 42aedd6be5SKyle Evanslocal none 43aedd6be5SKyle Evanslocal none_shifted = false 4402122e53SKyle Evans 45e15abd1fSKyle Evanslocal menu_entry_name = function(drawing_menu, entry) 46aedd6be5SKyle Evans local name_handler = drawer.menu_name_handlers[entry.entry_type] 47e15abd1fSKyle Evans 489f71d421SKyle Evans if name_handler ~= nil then 49aedd6be5SKyle Evans return name_handler(drawing_menu, entry) 50e15abd1fSKyle Evans end 51aedd6be5SKyle Evans return entry.name() 52e15abd1fSKyle Evansend 53e15abd1fSKyle Evans 54e15abd1fSKyle Evanslocal shift_brand_text = function(shift) 55aedd6be5SKyle Evans drawer.brand_position.x = drawer.brand_position.x + shift.x 56aedd6be5SKyle Evans drawer.brand_position.y = drawer.brand_position.y + shift.y 57aedd6be5SKyle Evans drawer.menu_position.x = drawer.menu_position.x + shift.x 58aedd6be5SKyle Evans drawer.menu_position.y = drawer.menu_position.y + shift.y 59aedd6be5SKyle Evans drawer.box_pos_dim.x = drawer.box_pos_dim.x + shift.x 60aedd6be5SKyle Evans drawer.box_pos_dim.y = drawer.box_pos_dim.y + shift.y 61e15abd1fSKyle Evansend 62e15abd1fSKyle Evans 6302122e53SKyle Evansfbsd_logo = { 64088b4f5fSWarner Losh " ______ ____ _____ _____ ", 65088b4f5fSWarner Losh " | ____| | _ \\ / ____| __ \\ ", 66088b4f5fSWarner Losh " | |___ _ __ ___ ___ | |_) | (___ | | | |", 67088b4f5fSWarner Losh " | ___| '__/ _ \\/ _ \\| _ < \\___ \\| | | |", 68088b4f5fSWarner Losh " | | | | | __/ __/| |_) |____) | |__| |", 69088b4f5fSWarner Losh " | | | | | | || | | |", 70088b4f5fSWarner Losh " |_| |_| \\___|\\___||____/|_____/|_____/ " 71aedd6be5SKyle Evans} 72088b4f5fSWarner Losh 7302122e53SKyle Evansbeastie_color = { 74088b4f5fSWarner Losh " \027[31m, ,", 75088b4f5fSWarner Losh " /( )`", 76088b4f5fSWarner Losh " \\ \\___ / |", 77088b4f5fSWarner Losh " /- \027[37m_\027[31m `-/ '", 78088b4f5fSWarner Losh " (\027[37m/\\/ \\\027[31m \\ /\\", 79088b4f5fSWarner Losh " \027[37m/ / |\027[31m ` \\", 80088b4f5fSWarner Losh " \027[34mO O \027[37m) \027[31m/ |", 81088b4f5fSWarner Losh " \027[37m`-^--'\027[31m`< '", 82088b4f5fSWarner Losh " (_.) _ ) /", 83088b4f5fSWarner Losh " `.___/` /", 84088b4f5fSWarner Losh " `-----' /", 85088b4f5fSWarner Losh " \027[33m<----.\027[31m __ / __ \\", 86088b4f5fSWarner Losh " \027[33m<----|====\027[31mO)))\027[33m==\027[31m) \\) /\027[33m====|", 87088b4f5fSWarner Losh " \027[33m<----'\027[31m `--' `.__,' \\", 88088b4f5fSWarner Losh " | |", 89088b4f5fSWarner Losh " \\ / /\\", 90088b4f5fSWarner Losh " \027[36m______\027[31m( (_ / \\______/", 91088b4f5fSWarner Losh " \027[36m,' ,-----' |", 92088b4f5fSWarner Losh " `--{__________)\027[37m" 93aedd6be5SKyle Evans} 94088b4f5fSWarner Losh 9502122e53SKyle Evansbeastie = { 96088b4f5fSWarner Losh " , ,", 97088b4f5fSWarner Losh " /( )`", 98088b4f5fSWarner Losh " \\ \\___ / |", 99088b4f5fSWarner Losh " /- _ `-/ '", 100088b4f5fSWarner Losh " (/\\/ \\ \\ /\\", 101088b4f5fSWarner Losh " / / | ` \\", 102088b4f5fSWarner Losh " O O ) / |", 103088b4f5fSWarner Losh " `-^--'`< '", 104088b4f5fSWarner Losh " (_.) _ ) /", 105088b4f5fSWarner Losh " `.___/` /", 106088b4f5fSWarner Losh " `-----' /", 107088b4f5fSWarner Losh " <----. __ / __ \\", 108088b4f5fSWarner Losh " <----|====O)))==) \\) /====|", 109088b4f5fSWarner Losh " <----' `--' `.__,' \\", 110088b4f5fSWarner Losh " | |", 111088b4f5fSWarner Losh " \\ / /\\", 112088b4f5fSWarner Losh " ______( (_ / \\______/", 113088b4f5fSWarner Losh " ,' ,-----' |", 114088b4f5fSWarner Losh " `--{__________)" 115aedd6be5SKyle Evans} 116088b4f5fSWarner Losh 11702122e53SKyle Evansfbsd_logo_v = { 118088b4f5fSWarner Losh " ______", 119088b4f5fSWarner Losh " | ____| __ ___ ___ ", 120088b4f5fSWarner Losh " | |__ | '__/ _ \\/ _ \\", 121088b4f5fSWarner Losh " | __|| | | __/ __/", 122088b4f5fSWarner Losh " | | | | | | |", 123088b4f5fSWarner Losh " |_| |_| \\___|\\___|", 124088b4f5fSWarner Losh " ____ _____ _____", 125088b4f5fSWarner Losh " | _ \\ / ____| __ \\", 126088b4f5fSWarner Losh " | |_) | (___ | | | |", 127088b4f5fSWarner Losh " | _ < \\___ \\| | | |", 128088b4f5fSWarner Losh " | |_) |____) | |__| |", 129088b4f5fSWarner Losh " | | | |", 130088b4f5fSWarner Losh " |____/|_____/|_____/" 131aedd6be5SKyle Evans} 132088b4f5fSWarner Losh 13302122e53SKyle Evansorb_color = { 134088b4f5fSWarner Losh " \027[31m``` \027[31;1m`\027[31m", 135088b4f5fSWarner Losh " s` `.....---...\027[31;1m....--.``` -/\027[31m", 136088b4f5fSWarner Losh " +o .--` \027[31;1m/y:` +.\027[31m", 137088b4f5fSWarner Losh " yo`:. \027[31;1m:o `+-\027[31m", 138088b4f5fSWarner Losh " y/ \027[31;1m-/` -o/\027[31m", 139088b4f5fSWarner Losh " .- \027[31;1m::/sy+:.\027[31m", 140088b4f5fSWarner Losh " / \027[31;1m`-- /\027[31m", 141088b4f5fSWarner Losh " `: \027[31;1m:`\027[31m", 142088b4f5fSWarner Losh " `: \027[31;1m:`\027[31m", 143088b4f5fSWarner Losh " / \027[31;1m/\027[31m", 144088b4f5fSWarner Losh " .- \027[31;1m-.\027[31m", 145088b4f5fSWarner Losh " -- \027[31;1m-.\027[31m", 146088b4f5fSWarner Losh " `:` \027[31;1m`:`", 147088b4f5fSWarner Losh " \027[31;1m.-- `--.", 148088b4f5fSWarner Losh " .---.....----.\027[37m" 149aedd6be5SKyle Evans} 150088b4f5fSWarner Losh 15102122e53SKyle Evansorb = { 152088b4f5fSWarner Losh " ``` `", 153088b4f5fSWarner Losh " s` `.....---.......--.``` -/", 154088b4f5fSWarner Losh " +o .--` /y:` +.", 155088b4f5fSWarner Losh " yo`:. :o `+-", 156088b4f5fSWarner Losh " y/ -/` -o/", 157088b4f5fSWarner Losh " .- ::/sy+:.", 158088b4f5fSWarner Losh " / `-- /", 159088b4f5fSWarner Losh " `: :`", 160088b4f5fSWarner Losh " `: :`", 161088b4f5fSWarner Losh " / /", 162088b4f5fSWarner Losh " .- -.", 163088b4f5fSWarner Losh " -- -.", 164088b4f5fSWarner Losh " `:` `:`", 165088b4f5fSWarner Losh " .-- `--.", 166088b4f5fSWarner Losh " .---.....----." 167aedd6be5SKyle Evans} 168088b4f5fSWarner Losh 169aedd6be5SKyle Evansnone = {""} 170088b4f5fSWarner Losh 171b5746545SKyle Evans-- Module exports 172b5746545SKyle Evansdrawer.menu_name_handlers = { 173b5746545SKyle Evans -- Menu name handlers should take the menu being drawn and entry being 174b5746545SKyle Evans -- drawn as parameters, and return the name of the item. 175b5746545SKyle Evans -- This is designed so that everything, including menu separators, may 176b5746545SKyle Evans -- have their names derived differently. The default action for entry 177b5746545SKyle Evans -- types not specified here is to call and use entry.name(). 178*dd65496aSKyle Evans [core.MENU_SEPARATOR] = function(drawing_menu, entry) 179*dd65496aSKyle Evans if entry.name ~= nil then 180*dd65496aSKyle Evans return entry.name() 181*dd65496aSKyle Evans end 182*dd65496aSKyle Evans return "" 183*dd65496aSKyle Evans end, 184b5746545SKyle Evans [core.MENU_CAROUSEL_ENTRY] = function(drawing_menu, entry) 185aedd6be5SKyle Evans local carid = entry.carousel_id 186aedd6be5SKyle Evans local caridx = config.getCarouselIndex(carid) 187aedd6be5SKyle Evans local choices = entry.items() 188b5746545SKyle Evans 1899f71d421SKyle Evans if #choices < caridx then 190aedd6be5SKyle Evans caridx = 1 191b5746545SKyle Evans end 192aedd6be5SKyle Evans return entry.name(caridx, choices[caridx], choices) 193b5746545SKyle Evans end, 194aedd6be5SKyle Evans} 195b5746545SKyle Evans 196aedd6be5SKyle Evansdrawer.brand_position = {x = 2, y = 1} 197aedd6be5SKyle Evansdrawer.logo_position = {x = 46, y = 1} 198aedd6be5SKyle Evansdrawer.menu_position = {x = 6, y = 11} 199aedd6be5SKyle Evansdrawer.box_pos_dim = {x = 3, y = 10, w = 41, h = 11} 200b5746545SKyle Evans 20129aa5794SKyle Evansdrawer.branddefs = { 202699578a6SKyle Evans -- Indexed by valid values for loader_brand in loader.conf(5). Valid 203699578a6SKyle Evans -- keys are: graphic (table depicting graphic) 20429aa5794SKyle Evans ["fbsd"] = { 20529aa5794SKyle Evans graphic = fbsd_logo, 20629aa5794SKyle Evans }, 20729aa5794SKyle Evans ["none"] = { 20829aa5794SKyle Evans graphic = none, 20929aa5794SKyle Evans }, 210aedd6be5SKyle Evans} 21129aa5794SKyle Evans 212bb26c57dSKyle Evansdrawer.logodefs = { 213bb26c57dSKyle Evans -- Indexed by valid values for loader_logo in loader.conf(5). Valid keys 214752b2d40SKyle Evans -- are: requires_color (boolean), graphic (table depicting graphic), and 215bb26c57dSKyle Evans -- shift (table containing x and y). 216bb26c57dSKyle Evans ["beastie"] = { 217bb26c57dSKyle Evans requires_color = true, 218752b2d40SKyle Evans graphic = beastie_color, 219bb26c57dSKyle Evans }, 220bb26c57dSKyle Evans ["beastiebw"] = { 221752b2d40SKyle Evans graphic = beastie, 222bb26c57dSKyle Evans }, 223bb26c57dSKyle Evans ["fbsdbw"] = { 224752b2d40SKyle Evans graphic = fbsd_logo_v, 225bb26c57dSKyle Evans shift = {x = 5, y = 4}, 226bb26c57dSKyle Evans }, 227bb26c57dSKyle Evans ["orb"] = { 228bb26c57dSKyle Evans requires_color = true, 229752b2d40SKyle Evans graphic = orb_color, 230bb26c57dSKyle Evans shift = {x = 2, y = 4}, 231bb26c57dSKyle Evans }, 232bb26c57dSKyle Evans ["orbbw"] = { 233752b2d40SKyle Evans graphic = orb, 234bb26c57dSKyle Evans shift = {x = 2, y = 4}, 235bb26c57dSKyle Evans }, 236bb26c57dSKyle Evans ["tribute"] = { 237752b2d40SKyle Evans graphic = fbsd_logo, 238bb26c57dSKyle Evans }, 239bb26c57dSKyle Evans ["tributebw"] = { 240752b2d40SKyle Evans graphic = fbsd_logo, 241bb26c57dSKyle Evans }, 242bb26c57dSKyle Evans ["none"] = { 243752b2d40SKyle Evans graphic = none, 244bb26c57dSKyle Evans shift = {x = 17, y = 0}, 245bb26c57dSKyle Evans }, 246aedd6be5SKyle Evans} 247bb26c57dSKyle Evans 248088b4f5fSWarner Loshfunction drawer.drawscreen(menu_opts) 249088b4f5fSWarner Losh -- drawlogo() must go first. 250088b4f5fSWarner Losh -- it determines the positions of other elements 251aedd6be5SKyle Evans drawer.drawlogo() 252aedd6be5SKyle Evans drawer.drawbrand() 253aedd6be5SKyle Evans drawer.drawbox() 254aedd6be5SKyle Evans return drawer.drawmenu(menu_opts) 255088b4f5fSWarner Loshend 256088b4f5fSWarner Losh 257088b4f5fSWarner Loshfunction drawer.drawmenu(m) 258aedd6be5SKyle Evans x = drawer.menu_position.x 259aedd6be5SKyle Evans y = drawer.menu_position.y 260088b4f5fSWarner Losh 261088b4f5fSWarner Losh -- print the menu and build the alias table 262aedd6be5SKyle Evans local alias_table = {} 263aedd6be5SKyle Evans local entry_num = 0 264aedd6be5SKyle Evans local menu_entries = m.entries 2659f71d421SKyle Evans if type(menu_entries) == "function" then 266aedd6be5SKyle Evans menu_entries = menu_entries() 2672e716cecSKyle Evans end 268d8757746SKyle Evans for line_num, e in ipairs(menu_entries) do 2694a4fb4f8SKyle Evans -- Allow menu items to be conditionally visible by specifying 2704a4fb4f8SKyle Evans -- a visible function. 2719f71d421SKyle Evans if e.visible ~= nil and not e.visible() then 272aedd6be5SKyle Evans goto continue 2734a4fb4f8SKyle Evans end 2749f71d421SKyle Evans if e.entry_type ~= core.MENU_SEPARATOR then 275aedd6be5SKyle Evans entry_num = entry_num + 1 276aedd6be5SKyle Evans screen.setcursor(x, y + line_num) 277ada26c4aSKyle Evans 278aedd6be5SKyle Evans print(entry_num .. ". " .. menu_entry_name(m, e)) 279088b4f5fSWarner Losh 280088b4f5fSWarner Losh -- fill the alias table 281aedd6be5SKyle Evans alias_table[tostring(entry_num)] = e 2829f71d421SKyle Evans if e.alias ~= nil then 283088b4f5fSWarner Losh for n, a in ipairs(e.alias) do 284aedd6be5SKyle Evans alias_table[a] = e 285088b4f5fSWarner Losh end 286196ba166SKyle Evans end 287088b4f5fSWarner Losh else 288aedd6be5SKyle Evans screen.setcursor(x, y + line_num) 289aedd6be5SKyle Evans print(menu_entry_name(m, e)) 290088b4f5fSWarner Losh end 2914a4fb4f8SKyle Evans ::continue:: 292088b4f5fSWarner Losh end 293aedd6be5SKyle Evans return alias_table 294088b4f5fSWarner Loshend 295088b4f5fSWarner Losh 296088b4f5fSWarner Losh 297088b4f5fSWarner Loshfunction drawer.drawbox() 298aedd6be5SKyle Evans x = drawer.box_pos_dim.x 299aedd6be5SKyle Evans y = drawer.box_pos_dim.y 300aedd6be5SKyle Evans w = drawer.box_pos_dim.w 301aedd6be5SKyle Evans h = drawer.box_pos_dim.h 302088b4f5fSWarner Losh 303aedd6be5SKyle Evans local hl = string.char(0xCD) 304aedd6be5SKyle Evans local vl = string.char(0xBA) 305088b4f5fSWarner Losh 306aedd6be5SKyle Evans local tl = string.char(0xC9) 307aedd6be5SKyle Evans local bl = string.char(0xC8) 308aedd6be5SKyle Evans local tr = string.char(0xBB) 309aedd6be5SKyle Evans local br = string.char(0xBC) 310088b4f5fSWarner Losh 311aedd6be5SKyle Evans screen.setcursor(x, y); print(tl) 312aedd6be5SKyle Evans screen.setcursor(x, y+h); print(bl) 313aedd6be5SKyle Evans screen.setcursor(x+w, y); print(tr) 314aedd6be5SKyle Evans screen.setcursor(x+w, y+h); print(br) 315088b4f5fSWarner Losh 316088b4f5fSWarner Losh for i = 1, w-1 do 317aedd6be5SKyle Evans screen.setcursor(x+i, y) 318aedd6be5SKyle Evans print(hl) 319aedd6be5SKyle Evans screen.setcursor(x+i, y+h) 320aedd6be5SKyle Evans print(hl) 321088b4f5fSWarner Losh end 322088b4f5fSWarner Losh 323088b4f5fSWarner Losh for i = 1, h-1 do 324aedd6be5SKyle Evans screen.setcursor(x, y+i) 325aedd6be5SKyle Evans print(vl) 326aedd6be5SKyle Evans screen.setcursor(x+w, y+i) 327aedd6be5SKyle Evans print(vl) 328088b4f5fSWarner Losh end 329088b4f5fSWarner Losh 330aedd6be5SKyle Evans screen.setcursor(x+(w/2)-9, y) 331aedd6be5SKyle Evans print("Welcome to FreeBSD") 332088b4f5fSWarner Loshend 333088b4f5fSWarner Losh 334088b4f5fSWarner Loshfunction drawer.draw(x, y, logo) 335088b4f5fSWarner Losh for i = 1, #logo do 336aedd6be5SKyle Evans screen.setcursor(x, y + i) 337aedd6be5SKyle Evans print(logo[i]) 338088b4f5fSWarner Losh end 339088b4f5fSWarner Loshend 340088b4f5fSWarner Losh 341088b4f5fSWarner Loshfunction drawer.drawbrand() 34224a1bd54SKyle Evans local x = tonumber(loader.getenv("loader_brand_x")) or 343aedd6be5SKyle Evans drawer.brand_position.x 34424a1bd54SKyle Evans local y = tonumber(loader.getenv("loader_brand_y")) or 345aedd6be5SKyle Evans drawer.brand_position.y 346088b4f5fSWarner Losh 347aedd6be5SKyle Evans local graphic = drawer.branddefs[loader.getenv("loader_brand")] 3489f71d421SKyle Evans if graphic == nil then 349aedd6be5SKyle Evans graphic = fbsd_logo 35029aa5794SKyle Evans end 351aedd6be5SKyle Evans drawer.draw(x, y, graphic) 352088b4f5fSWarner Loshend 353088b4f5fSWarner Losh 354088b4f5fSWarner Loshfunction drawer.drawlogo() 35524a1bd54SKyle Evans local x = tonumber(loader.getenv("loader_logo_x")) or 356aedd6be5SKyle Evans drawer.logo_position.x 35724a1bd54SKyle Evans local y = tonumber(loader.getenv("loader_logo_y")) or 358aedd6be5SKyle Evans drawer.logo_position.y 359088b4f5fSWarner Losh 360aedd6be5SKyle Evans local logo = loader.getenv("loader_logo") 361aedd6be5SKyle Evans local colored = color.isEnabled() 362088b4f5fSWarner Losh 363bb26c57dSKyle Evans -- Lookup 364aedd6be5SKyle Evans local logodef = drawer.logodefs[logo] 365bb26c57dSKyle Evans 3669f71d421SKyle Evans if logodef ~= nil and logodef.graphic == none then 367088b4f5fSWarner Losh -- centre brand and text if no logo 3689f71d421SKyle Evans if not none_shifted then 369aedd6be5SKyle Evans shift_brand_text(logodef.shift) 370aedd6be5SKyle Evans none_shifted = true 371088b4f5fSWarner Losh end 3729f71d421SKyle Evans elseif logodef == nil or logodef.graphic == nil or 3739f71d421SKyle Evans (not colored and logodef.requires_color) then 374bb26c57dSKyle Evans -- Choose a sensible default 3759f71d421SKyle Evans if colored then 376aedd6be5SKyle Evans logodef = drawer.logodefs["orb"] 377088b4f5fSWarner Losh else 378aedd6be5SKyle Evans logodef = drawer.logodefs["orbbw"] 379088b4f5fSWarner Losh end 380088b4f5fSWarner Losh end 3819f71d421SKyle Evans if logodef.shift ~= nil then 382aedd6be5SKyle Evans x = x + logodef.shift.x 383aedd6be5SKyle Evans y = y + logodef.shift.y 384bb26c57dSKyle Evans end 385aedd6be5SKyle Evans drawer.draw(x, y, logodef.graphic) 386088b4f5fSWarner Loshend 387088b4f5fSWarner Losh 388aedd6be5SKyle Evansreturn drawer 389