Created
April 14, 2013 20:34
Revisions
-
devilstower created this gist
Apr 14, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,849 @@ --# UIElement UIElement = class() CONTROLTYPE = 0 LABELTYPE = 1 BUTTONTYPE = 2 TEXTBOXTYPE = 3 SWITCHTYPE = 4 SLIDERTYPE = 5 DROPLISTTYPE = 6 MULTIBUTTONTYPE = 7 CHECKBOXTYPE = 8 NOTCHSLIDERTYPE = 9 ICONBUTTONTYPE = 10 DIALTYPE = 11 DOUGHNUTTYPE = 12 SELECTLISTTYPE = 13 TABBARTYPE = 14 function UIElement:init(type, text, left, bottom, right, top, tab) self.type = type self.element = nil self.tab = tab self.source = 1 if type == CONTROLTYPE then self.element = Control(text, left, bottom, right, top) self.name = "control" elseif type == LABELTYPE then self.element = Label(text, left, bottom, right, top) self.name = "label" elseif type == BUTTONTYPE then self.element = TextButton(text, left, bottom, right, top) self.name = "button" elseif type == TEXTBOXTYPE then self.element = TextBox(text, left, bottom, right, top) self.name = "textBox" elseif type == SWITCHTYPE then self.element = Switch(text, left, bottom, right, top) self.name = "switch" elseif type == SLIDERTYPE then self.element = Slider(text, left, bottom, right, top, 0, 100, 50) self.name = "slider" elseif type == DROPLISTTYPE then self.element = DropList(text, left, bottom, right, top) self.name = "dropList" elseif type == MULTIBUTTONTYPE then self.element = MultiButton(text, left, bottom, right, top) self.name = "multiButton" elseif type == CHECKBOXTYPE then self.element = CheckBox(text, left, bottom, right, top) self.name = "checkBox" elseif type == NOTCHSLIDERTYPE then self.element = NotchSlider(text, left, bottom, right, top) self.name = "notchSlider" elseif type == ICONBUTTONTYPE then self.element = IconButton(text, left, bottom, right, top, "Cargo Bot:Crate Goal Red") self.name = "iconButton" elseif type == DIALTYPE then self.element = Dial(text, left, bottom, right, top, 0, 100, 35) self.name = "dial" elseif type == DOUGHNUTTYPE then self.element = Doughnut(text, left, bottom, right, top, 0, 100, 35) self.name = "doughnut" elseif type == SELECTLISTTYPE then self.element = SelectList(text, left, bottom, right, top, true) self.name = "list" elseif type == TABBARTYPE then self.element = TabBar(text, left, bottom, right, top, true) self.name = "tabbar" end end function UIElement:draw() self.element:draw() end function UIElement:printInit() local s s = " "..self.name.." = "..self.element:initString("test").."\n" if self.element.fontSize ~= 16 then s = s.." "..self.name..".fontSize = "..self.element.fontSize .."\n" end if self.element.font ~= "HelveticaNeue-Bold" then s = s.." "..self.name..".font = '"..self.element.font.."'\n" end return s end function UIElement:printDraw() return " "..self.name..":draw()\n" end function UIElement:printTouched() return " "..self.name..":touched(touch)\n" end function UIElement:touched(touch) return self.element:ptIn(touch.x, touch.y) end --# Main -- Cider -- an interactive interface builder for Codea -- version 1.6 -- 14 April 2013 -- Mark Sumner -- [email protected] -- 1.6 added SelectList and TabBar, changes in most controls -- revised control tray with tabs -- 1.5 revised for Codea 1.5 code output -- 1.35 adds visible grid, size display -- 1.3 adds CheckBox, bug fixes, code refactoring -- 1.2 adds CCActiveTextBox to help simplify and manage text boxes displayMode(FULLSCREEN) minSize = 30 function setup() setInstructionLimit(0) dragIndex = 0 activeTextBox = nil controlCount = 1000 trayOpen = false trayTab = Frame(WIDTH - 25, HEIGHT / 2 - 30, WIDTH + 25, HEIGHT / 2 + 30) trayWidth = 0 trayMaxWidth = 250 trayFrame = Frame(WIDTH - trayWidth, 0, trayMaxWidth, HEIGHT) elements = {} trayElement = {} traySpeed = 50 tabbar = TabBar("Simple;Complex;Display",0, HEIGHT-35,trayMaxWidth,HEIGHT) trayElement[1] = UIElement(0, "Control Panel", 10, HEIGHT - 120, 200, HEIGHT - 50, 1) trayElement[2] = UIElement(1, "Text Label", 40, HEIGHT - 500, 170, HEIGHT - 475, 1) trayElement[3] = UIElement(2, "Button", 40, HEIGHT - 190, 170, HEIGHT - 150, 1) trayElement[4] = UIElement(3, "Text Box", 10, HEIGHT - 590, 200, HEIGHT - 540, 1) trayElement[5] = UIElement(4, "ON;OFF", 55, HEIGHT - 360, 155, HEIGHT - 330, 1) trayElement[6] = UIElement(5, "Range", 10, HEIGHT - 110, 200, HEIGHT - 70, 2) trayElement[7] = UIElement(6, "Drop List", 10, HEIGHT - 350, 140, HEIGHT - 320, 4) trayElement[8] = UIElement(7, "Multi;Choice;Button", 10, HEIGHT - 290, 220, HEIGHT - 250, 2) trayElement[9] = UIElement(8, "Check Box", 40, HEIGHT - 430, 170, HEIGHT - 390, 1) trayElement[10] = UIElement(9, "A;B;C", 30, HEIGHT - 210, 200, HEIGHT - 160, 2) trayElement[11] = UIElement(10, "IconButton", 40, HEIGHT - 290, 170, HEIGHT - 220, 1) trayElement[12] = UIElement(11, "Dial", 20, HEIGHT - 210, 150, HEIGHT - 70, 3) trayElement[13] = UIElement(12, "Ring", 20, HEIGHT - 380, 150, HEIGHT - 240, 3) trayElement[14] = UIElement(13, "Item 1;Item 2;Item 3", 30, HEIGHT - 460, 200, HEIGHT - 330, 2) trayElement[15] = UIElement(14, "Tab 1;Tab 2;Tab 3", 10, HEIGHT - 550, 240, HEIGHT - 500, 2) swtGrid = Switch("ON;OFF", 55, 90, 150, 120) lblGrid = Label("Grid", 10, 90, 35, 100) btnCode = TextButton("Save Code", 10, 30, 150, 70) lblMain = Label("Main", 10, 130, 35, 140) swtMain = Switch("ON;OFF", 55, 130, 150, 160) eSelected = 0 eType = 0 dragElement = nil leftTopSize = Frame(0, 0, 0, 0) rightTopSize = Frame(0, 0, 0, 0) leftBottomSize = Frame(0, 0, 0, 0) rightBottomSize = Frame(0, 0, 0, 0) infoRect = Frame(-90, 0, -90, 0) startRect = Frame(0, 0, 0, 0) stretch = 0 dialog = Dialog("Properties", 200, HEIGHT - 750, WIDTH - 200, HEIGHT - 30) showProperties = false showHandles = false l = dialog.left + 100 r = dialog.right - 30 b = dialog.bottom + 40 t = dialog.top - 75 txtName = TextBox("", l, t-10, r, t + 20) txtText = TextBox("", l, t - 70, r, t - 40) font("HelveticaNeue-Bold") drpFont = DropList("HelveticaNeue-Bold;ArialMT;".. "Arial-BoldMT;Copperplate;".. "Courier;TimesNewRomanPSMT", l, t - 130, r, t - 100) drpFont.selected = 1 sldFontSize = Slider("", l, t - 200, r, t - 165, 8 , 48, 14) ctlBackground = Control("", l, t - 250, r, t - 220) ctlForeground = Control("", l, t - 310, r, t - 280) ctlHighlight = Control("", l, t - 370, r, t - 340) deleteBtn = TextButton("Delete", l - 80, b - 15, l + 60, b + 20) deleteBtn.highlight = color(224, 94, 94, 255) -- optional properties mlbTextAlign = MultiButton("Left;Center;Right", l, t - 430, r, t - 400) swtMulti = Switch("ON;OFF", l, t-430, l+100, t-400) drpSource = DropList("None;Gravity X;Gravity Y;Gravity Z;".. "Acceleration X;Acceleration Y;Acceleration Z" , l, t - 430, r, t - 400) drpSource.selected = 1 clrChooser = nil showBackgroundColor = false showForegroundColor = false showHighlightColor = false dragElement = nil offsetX = 0 offsetY = 0 stretch = 0 end function drawTray() pushMatrix() pushStyle() translate(WIDTH - trayWidth, 0) for i, e in ipairs(trayElement) do if e.tab == tabbar.selected then e:draw() --print(i,e.element.controlName) fill(255, 255, 255, 255) text(e.element.controlName, e.element:midX(), e.element.bottom - 10) end end lblGrid:draw() swtGrid:draw() lblMain:draw() swtMain:draw() btnCode:draw() tabbar:draw() popStyle() popMatrix() end function drawProperties() local i pushStyle() fontSize(14) font("ArialMT") dialog:draw() strokeWidth(2) stroke(30, 30, 30, 255) for i = 1,10 do line(dialog.left, dialog.top - i * 60 - 40, dialog.right, dialog.top - i * 60 - 40) end deleteBtn:draw() textMode(CORNER) textAlign(LEFT) fill(0, 0, 0, 255) txtName:draw() txtText:draw() text("Name", dialog.left + 10, dialog.top - 70) text("Text", dialog.left + 10, dialog.top - 130) text("Font", dialog.left + 10, dialog.top - 190) text("Font Size", dialog.left + 10, dialog.top - 250) text("Background", dialog.left + 10, dialog.top - 310) text("Foreground", dialog.left + 10, dialog.top - 370) text("Highlight", dialog.left + 10, dialog.top - 430) -- optional if dragElement.type == TEXTBOXTYPE then text("Text Align", dialog.left + 10, dialog.top - 490) mlbTextAlign:draw() elseif dragElement.type == ICONBUTTONTYPE then text("Image", dialog.left + 10, dialog.top - 490) text(dragElement.element.img, dialog.left + 100, dialog.top - 490) elseif dragElement.type == SELECTLISTTYPE then text("Multiselect", dialog.left + 10, dialog.top - 490) swtMulti:draw() elseif dragElement.type == DIALTYPE then text("Data source", dialog.left + 10, dialog.top - 490) drpSource:draw() end sldFontSize:draw() drpFont:draw() ctlBackground:draw() ctlForeground:draw() ctlHighlight:draw() popStyle() end function draw() local i, x -- This sets a dark background color background(194, 194, 194, 255) font("ArialMT") fontSize(222) stroke(146, 138, 138, 44) strokeWidth(2) if swtGrid.selected then for x=0, WIDTH, 20 do line(x, 0, x, HEIGHT) end for x=0, HEIGHT, 20 do line(0, x, WIDTH, x) end end fill(146, 140, 140, 29) text("Cider", WIDTH / 2, HEIGHT / 2 + 200) fontSize(72) text("Interface Designer", WIDTH / 2, HEIGHT / 2 - 100) fontSize(14) for i, e in ipairs(elements) do e:draw() end if trayOpen then if trayWidth < trayMaxWidth then trayWidth = trayWidth + traySpeed trayTab:offset(-traySpeed , 0) end else if trayWidth > 0 then trayWidth = trayWidth - traySpeed trayTab:offset(traySpeed , 0) end end strokeWidth(2) fill(107, 107, 107, 255) ellipse(WIDTH - trayWidth, HEIGHT / 2, 40) rect(WIDTH - trayWidth, 0, trayWidth, HEIGHT) noStroke() rect(WIDTH - trayWidth -5, HEIGHT / 2 - 18, 10, 36) trayFrame.left = WIDTH - trayWidth trayFrame.right = trayFrame.left + trayMaxWidth strokeWidth(5) stroke(127, 127, 127, 255) line(WIDTH - trayWidth - 10, HEIGHT / 2, WIDTH - trayWidth - 0, HEIGHT / 2 - 5) line(WIDTH - trayWidth - 10, HEIGHT / 2, WIDTH - trayWidth - 0, HEIGHT / 2 + 5) strokeWidth(2) line(WIDTH - trayWidth + 5, 200, WIDTH, 200) if trayWidth > 0 then drawTray() end if dragElement then dragElement:draw() end if showHandles then fontSize(14) font("ArialMT") strokeWidth(4) stroke(78, 175, 203, 197) noFill() line(leftTopSize.left, leftTopSize.top, leftTopSize.left + 15, leftTopSize.top) line(leftTopSize.left, leftTopSize.top, leftTopSize.left, leftTopSize.top - 15) line(leftBottomSize.left, leftBottomSize.bottom, leftBottomSize.left + 15, leftBottomSize.bottom) line(leftBottomSize.left, leftBottomSize.bottom, leftBottomSize.left, leftBottomSize.bottom + 15) line(rightBottomSize.right - 15, rightBottomSize.bottom, rightBottomSize.right, rightBottomSize.bottom) line(rightBottomSize.right, rightBottomSize.bottom, rightBottomSize.right, rightBottomSize.bottom + 15) line(rightTopSize.right - 15, rightTopSize.top, rightTopSize.right, rightTopSize.top) line(rightTopSize.right, rightTopSize.top, rightTopSize.right, rightTopSize.top - 15) strokeWidth(1) stroke(255, 255, 255, 255) fill(93, 103, 230, 255) ellipse(infoRect:midX(), infoRect:midY(), 25) fill(255, 255, 255, 255) text("i", infoRect:midX(), infoRect:midY()) text(dragElement.element:width(), infoRect:midX(), rightBottomSize.bottom) text(dragElement.element:height(), leftBottomSize:midX(), dragElement.element:midY()) strokeWidth(2) stroke(255, 255, 255, 255) line(dragElement.element.left - 30, dragElement.element.top, dragElement.element.left - 10, dragElement.element.top) end if showProperties then drawProperties() end if showBackgroundColor or showForegroundColor or showHighlightColor then clrChooser:draw() end end function resetHandles(x, y) l = dragElement.element.left - minSize b = dragElement.element.bottom - minSize r = dragElement.element.right t = dragElement.element.top x = dragElement.element:midX() leftTopSize.left = l leftTopSize.right = l + minSize leftTopSize.bottom = t leftTopSize.top = t + minSize rightTopSize.left = r rightTopSize.right = r + minSize rightTopSize.bottom = t rightTopSize.top = t + minSize rightBottomSize.left = r rightBottomSize.right = r + minSize rightBottomSize.bottom = b rightBottomSize.top = b + minSize leftBottomSize.left = l leftBottomSize.right = l + minSize leftBottomSize.bottom = b leftBottomSize.top = b + minSize infoRect.left = x - minSize / 2 infoRect.right = x + minSize / 2 infoRect.bottom = t + minSize infoRect.top = t + minSize * 2 end function printElements() s = "" if swtMain.selected then s = s.."-- Generated by Cider\n" s = s.."--\n" s = s.."-- Add CiderControls as a dependency\n" s = s.."--\n" s = s.." \n" s = s.."displayMode(FULLSCREEN)\n" s = s.." \n" s = s.."function setup()\n" else s = "-- ===================\n" s = s.."-- Copy code into the setup function\n" s = s.."-- ===================\n" end for i, e in ipairs(elements) do s = s..e:printInit().."\n" if e.type == SELECTLISTTYPE then if e.element.multi then s = s.." "..e.name..".multi = true\n" else s = s.." "..e.name..".multi = false\n" end end end if swtMain.selected then s = s.."end\n" s = s.."\n" s = s.."function draw()\n" s = s.." background(194, 194, 194, 255)\n" else s = s.." \n" s = s.."-- ===================\n" s = s.."-- Copy into the draw function\n" s = s.."-- ===================\n" end for i, e in ipairs(elements) do s = s..e:printDraw().."\n" if e.type == DIALTYPE then if e.source == 2 then s = s.." "..e.name..".val = Gravity.x * 50 + 50\n" elseif e.source == 3 then s = s.." "..e.name..".val = Gravity.y * 50 + 50\n" elseif e.source == 4 then s = s.." "..e.name..".val = Gravity.z * 50 + 50\n" elseif e.source == 5 then s = s.." "..e.name..".val = UserAcceleration.x".. " * 50 + 50\n" elseif e.source == 6 then s = s.." "..e.name..".val = UserAcceleration.y".. " * 50 + 50\n" elseif e.source == 7 then s = s.." "..e.name..".val = UserAcceleration.z".. " * 50 + 50\n" end end end if swtMain.selected then s = s.."end\n" s = s.."\n" s = s.."function touched(touch)\n" else s = s.." \n" s = s.."-- ===================\n" s = s.."-- Copy into the touched function\n" s = s.."-- ===================\n" end for i, e in ipairs(elements) do s = s..e:printTouched().."\n" end if swtMain.selected then s = s.."end\n" s = s.."\n" else s = s.." \n" s = s.."-- ===================\n" s = s.."-- Copy into main, or modify your\n" s = s.."-- existing keyboard function\n" s = s.."-- ===================\n" s = s.." \n" end s = s.."function keyboard(key)\n" s = s.." if CCActiveTextBox then\n" s = s.." CCActiveTextBox:acceptKey(key)\n" s = s.." end\n" s = s.."end\n" s = s.." \n" saveProjectTab("Output", s) end function closeDialog() showProperties = false if string.len(txtName.text) > 0 then dragElement.name = txtName.text end dragElement.element.text = txtText.text if dragElement.type == SWITCHTYPE or dragElement.type == MULTIBUTTONTYPE or dragElement.type == NOTCHSLIDERTYPE or dragElement.type == SELECTLISTTYPE or dragElement.type == DROPLISTTYPE then dragElement.element.itemText = {} dragElement.element:splitText() end dragElement.element.font = drpFont.itemText[drpFont.selected] dragElement.element.fontSize = sldFontSize.val dragElement.element.background = ctlBackground.background dragElement.element.foreground = ctlForeground.background dragElement.element.highlight = ctlHighlight.background if isKeyboardShowing() then hideKeyboard() end if dragElement.type == TEXTBOXTYPE then if mlbTextAlign.selected == 1 then dragElement.element.textAlign = LEFT elseif mlbTextAlign.selected == 2 then dragElement.element.textAlign = CENTER elseif mlbTextAlign.selected == 3 then dragElement.element.textAlign = RIGHT end end sound(SOUND_HIT, 28774) end function touchedProperties(touch) if touch.state == BEGAN and oldState ~= BEGAN then if dialog:touched(touch) then txtName:touched(touch) txtText:touched(touch) if drpFont:touched(touch) then return nil end sldFontSize:touched(touch) mlbTextAlign:touched(touch) if dragElement.type == SELECTLISTTYPE then swtMulti:touched(touch) dragElement.element.multi = swtMulti.selected elseif dragElement.type == DIALTYPE then drpSource:touched(touch) dragElement.source = drpSource.selected end if ctlBackground:touched(touch) then clrChooser = ColorSelector(ctlBackground:midX(), ctlBackground.bottom) clrChooser:setColor(ctlBackground.background) showBackgroundColor = true end if ctlForeground:touched(touch) then clrChooser = ColorSelector(ctlForeground:midX(), ctlForeground.bottom) clrChooser:setColor(ctlForeground.background) showForegroundColor = true end if ctlHighlight:touched(touch) then clrChooser = ColorSelector(ctlHighlight:midX(), ctlHighlight.bottom) clrChooser:setColor(ctlHighlight.background) showHighlightColor = true end deleteBtn:touched(touch) else closeDialog() end end if touch.state == MOVING or touch.state == ENDED then if dragElement.type == DIALTYPE then drpSource:touched(touch) dragElement.source = drpSource.selected end if dialog:touched(touch) then drpFont:touched(touch) sldFontSize:touched(touch) end if deleteBtn:touched(touch) then dragElement = nil table.remove(elements, dragIndex) showProperties = false showHandles = false end end oldState = touch.state end function touchedHandles(touch) if touch.state == BEGAN and oldState ~= BEGAN then stretch = 0 if leftTopSize:touched(touch) then stretch = 1 elseif rightTopSize:touched(touch) then stretch = 2 elseif leftBottomSize:touched(touch) then stretch = 3 elseif rightBottomSize:touched(touch) then stretch = 4 elseif infoRect:touched(touch) then stretch = 5 showProperties = true txtName.text = dragElement.name txtText.text = dragElement.element.text sldFontSize.val = dragElement.element.fontSize if dragElement.type == LABELTYPE then mlbTextAlign.selected = dragElement.element.textAlign end ctlBackground.background = dragElement.element.background ctlForeground.background = dragElement.element.foreground ctlHighlight.background = dragElement.element.highlight end if stretch == 0 then showHandles = false end elseif touch.state == MOVING then if swtGrid.selected then x = math.floor(touch.x / 20) * 20 y = math.floor(touch.y / 20) * 20 else x = touch.x y = touch.y end if stretch == 1 then -- top left if x > rightTopSize.left - minSize then x = rightTopSize.left - minSize end if y < leftBottomSize.top + minSize then y = leftBottomSize.top + minSize end dragElement.element.left = x dragElement.element.top = y elseif stretch == 2 then -- top right if x < leftTopSize.right + minSize then x = leftTopSize.right + minSize end if y < leftBottomSize.top + minSize then y = leftBottomSize.top + minSize end dragElement.element.right = x dragElement.element.top = y elseif stretch == 3 then -- bottom left if x > rightTopSize.left - minSize then x = rightTopSize.left - minSize end if y > leftTopSize.bottom - minSize then y = leftTopSize.bottom - minSize end dragElement.element.left = x dragElement.element.bottom = y elseif stretch == 4 then -- bottom right if x < leftTopSize.right + minSize then x = leftTopSize.right + minSize end if y > leftTopSize.bottom - minSize then y = leftTopSize.bottom - minSize end dragElement.element.right = x dragElement.element.bottom = y end resetHandles() elseif touch.state == ENDED and oldState == MOVING then resetHandles() end end function placeDragElement() local e if dragElement then dragElement = nil showHandles = false end end function liftDragElement(e, l) local ui if l > 0 then ui = UIElement(e.type, e.element.text, e.element.left + l, e.element.bottom, e.element.right + l, e.element.top) dragElement = ui table.insert(elements, ui) else dragElement = e end showHandles = false end function touched(touch) if showBackgroundColor then showBackgroundColor = clrChooser:touched(touch) ctlBackground.background = clrChooser:getColor() return false elseif showForegroundColor then showForegroundColor = clrChooser:touched(touch) ctlForeground.background = clrChooser:getColor() return false elseif showHighlightColor then showHighlightColor = clrChooser:touched(touch) ctlHighlight.background = clrChooser:getColor() return false elseif showProperties then touchedProperties(touch) oldState = touch.state return false elseif showHandles and dragElement then touchedHandles(touch) if showProperties then return false end end if trayOpen and trayFrame:touched(touch) then if dragElement then placeDragElement() end tt = Ttouch(touch) tt:translate(trayFrame.left, 0) swtGrid:touched(tt) swtMain:touched(tt) if btnCode:touched(tt) then printElements() end if touch.state == BEGAN then if tabbar:touched(tt) then else for i, e in ipairs(trayElement) do if e.tab == tabbar.selected and e:touched(tt) then -- drag a new element into the table liftDragElement(e, trayFrame.left) dragElement.name = dragElement.name..controlCount controlCount = controlCount + 1 offsetX = 0 trayOpen = false end end end end end if touch.state == BEGAN and oldState ~= BEGAN then if dragElement and not showHandles then if dragElement:touched(touch) then showHandles = true resetHandles(e) end end if trayTab:touched(touch) then placeDragElement() trayOpen = not trayOpen else -- pick up element for i, e in ipairs(elements) do if e:touched(touch) then if dragElement then placeDragElement() end liftDragElement(e, 0) dragIndex = i offsetX = e.element.left - touch.x --table.remove(elements, i) end end end end if touch.state == MOVING and dragElement and showHandles == false then w = dragElement.element:width() h = dragElement.element:height() if swtGrid.selected then x = math.floor((touch.x + offsetX) / 20) * 20 y = math.floor(touch.y / 20) * 20 else x = touch.x + offsetX y = touch.y end dragElement.element.left = x dragElement.element.right = x + w dragElement.element.bottom = y dragElement.element.top = y + h elseif touch.state == ENDED and dragElement and oldState == MOVING then placeDragElement() elseif touch.state == ENDED and dragElement and oldState == BEGAN then if dragElement:touched(touch) then resetHandles(dragElement.element.left, dragElement.element.right) showHandles = true else showHandles = false end end oldState = touch.state end function keyboard(key) if showProperties then if CCActiveTextBox then CCActiveTextBox:acceptKey(key) end end end --# Output