Skip to content

Instantly share code, notes, and snippets.

@JMV38

JMV38/1aTabOrder Secret

Created August 20, 2013 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JMV38/c7e33b175d33f9f01ee5 to your computer and use it in GitHub Desktop.
Save JMV38/c7e33b175d33f9f01ee5 to your computer and use it in GitHub Desktop.
XFC Test Build: v0.0.3 Build: 1
XFC Tab Order Version: 0.0.3
------------------------------
This file should not be included in the Codea project.
#Main
#XFC000
#XFC001_history
#XFC005_autoinstall
#XFC010_MenuItem
#XFC011_ChoiceItem
#XFC011_LinkItem
#XFC011_yesNoMenu
#XFC012_InfoItem
#XFC013_DocItem1
#XFC013_InfoBox
#XFC014_DocItem2
#XFC015_FIleIO
#XFC016_DownloadItem
#XFC017_UploadItem
#XFC018_RemoveItem
#XFC019_downloadList
#XFC021_FunctionItem
#XFC030_unitTests
#XFC031_functionsMenu
#XFC032_linksMenu
#XFC033_settingsMenu
#XFC050_Menu
-- main
--VERSION = "X.X.X" -- Use this to set Version Numbers Or set Version in class creation
--PROJECTNAME = "Your project Name"
--BUILD = false -- Include this Global if you want a separate Gist for builds *true* creates a build gist
VERSION = "0.0.3"
PROJECTNAME = "XFC" --Do not change this, your project should be named AutoGist
BUILD = true
--If Build is true version number is ignored and a Private gist is created for builds
--If Build is false or nil the Version checks for a Release gist update
PUBLIC = false
-- Create a public Gist = true, private gist is false
function setup()
VersionUpdateChecker.check()
-- if XFC then XFC.init() end -- dont change this line!
--create an instance of AutoGist
--Add this to the project that you would like to backup
--@param ProjectName -- must match your project use PROJECTNAME at the top
--@param Description of your project
--@param version number. I like using a global VERSION at the top.
--@param [true|false] true will add an update checker to the gist
local autoGist = AutoGist(
PROJECTNAME,
"eXtensions For Codea",
VERSION,
BUILD)--Do not edit this one
--This must be called to check for backups
autoGist:backup(PUBLIC)
-- displayMode(FULLSCREEN)
-- this is just an example:
parameter.action("start loop to test wait",loop)
-- end of example
end
function loop()
-- function for tests
--XFC.wait(1,loop)
local ok,err = pcall( XFC.functions.wait,1,loop )
if ok then
print("hello from XFC.wait fonction")
else
print("wait function not available")
end
end
function draw()
-- *** these lines just to simulate user background
background(40, 40, 50)
spriteMode(CENTER)
sprite("Cargo Bot:Codea Icon",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
-- ***
-- if XFC then XFC.draw() end -- dont change this line!
end
function touched(touch)
-- put this line at the BEGINNING of your touched()
-- if XFC and XFC.touched(touch) then return end -- dont change this line!
end
-----------------------------
--Update Checker Code added by AutoGist
-----------------------------
VersionUpdateChecker = {}
VersionUpdateChecker.gistURL = "https://api.github.com/gists/6218525"
VersionUpdateChecker.check = function()
local jsonURL = "https://dl.dropboxusercontent.com/s/9e4nvqeu4hsux2q/Json.lua?token_hash=AAFyMB98j4bnt_1gawf9wSke52hsoC7hsIvARcTuZNeOEw&dl=1"
local jsonSuccess = function(data)
local jsonCode = data
if jsonCode then local l = loadstring(jsonCode) l() end
local handleSuccess = function(data)
local gist = json.decode(data)
local version = string.match(gist.description,"%d+%.%d+%.%d+")
if VERSION ~= version then
displayMode(STANDARD)
print("Click Update_Project.")
alert("New Update Availiable! Click Update.","Update")
parameter.action("Update_Project",function() VersionUpdateChecker.GetProject() end)
end
end
http.request(VersionUpdateChecker.gistURL,handleSuccess,function() print("Update Failed") end)
end
http.request(jsonURL,jsonSuccess,function() print("Check Internet Connection") end)
end
function VersionUpdateChecker.GetProject()
local handleSuccess = function(data,i,j)
if listProjectTabs(PROJECTNAME) == nil then
error("Check Project Name")
end
local gist = json.decode(data)
local projName = PROJECTNAME
if gist.files["1aTabOrder"] then
print("***Tab Order Found***")
local taborder = gist.files["1aTabOrder"].content
local strStart =1
local strEnd =0
strStart = string.find(taborder,"#",strEnd)
strEnd = string.find(taborder,"\n",strStart)
while strStart do
local tmp = string.sub(taborder,strStart+1,strEnd-1)
local name = PROJECTNAME..":"..tmp
tmp = tmp..".lua"
saveProjectTab(name,gist.files[tmp].content)
strStart = string.find(taborder,"#",strEnd)
strEnd = string.find(taborder,"\n",strStart)
end
else
for k,v in pairs(gist.files) do
local name = PROJECTNAME .. ":" .. string.gsub(k,".lua","")
saveProjectTab(name, v.content)
end
end
if gist.files["ChangeLog.lua"] then
local str = gist.files["ChangeLog.lua"].content
alert(str,"Version Notes")
end
sound(SOUND_PICKUP, 24058)
print("Reload Project to finish update!")
end
http.request(VersionUpdateChecker.gistURL,handleSuccess,function(data) print("Update Failed") end)
end
--End of Update Checker
--------------------------------------------------
-- XFC
-- eXtensions For Codea
-- contibutors : contribution
-- @Jmv38 : project proposal - July 2013
-- @Briarfox : gist, documentation box.
-- this project is a library to find and import easily
-- snippets, function, libraries or apps
-- designed by the people of the forum, and that must be saved.
-- objectives:
-- provide the codea missing functions
-- compile those great forum posts
-- hopefuly become a 'must have' for every codea user project (mine too)
-- technical requirements:
-- not intrusive, minimal look, but nice
-- the simplest/easiest interface possible targetting the occasionnal programmer /newbee
-- updates are managed by the code, like in the appstore
-- requested code is copied into the requesting project
-- (no dependencies needed in the finished version of the code)
-- the user doesnt have to think about it (similar to built-in codea functions)
-- clean code: no globals created, good fps, low memory load, clear code.
-- documentation included, codea-alike if possible
-- adding / updating snippets for the XFC developpers is easy
-- (maybe) access the code via a web server to monitor and share activity
-- (maybe) collaborative additions possible, with or w/o a control board approval.
-- only global variable
XFC = {}
XFC.remove = {}
XFC.tabInit = {}
XFC.tabs = {} -- all tabs here
XFC.developper = false
XFC.init = function()
XFC.main = XFC.menu.root()
--XFC.functions = XFC.Functions()
end
XFC.draw = function()
XFC.main:draw()
end
XFC.touched = function(touch)
local touchIntercepted = XFC.main:touched(touch)
return touchIntercepted
end
--[[
HISTORY OF CHANGES
------------------
still to be done
------------------
- prototype a runnable example (in function doc)
- make the doc sections scrollable? (to use the runnable example in the doc)
- then add a cross top right to close the box (touch should not close)
- functions submenu: all gist url stored in one tab?
- check for XFC updates
- check for content updates (new functions)
- count installed tabs that changed => red pastilla
- count new tabs => green pastllia
- each tab has a version number
- each content tab has an install function
- each content tab has an uninstall function
- tab list is managed
- how to have several solutions for one function?
- how to show several versions of one function? std,beta
- how to check how many installs? update checks? (monitor user activity)
- make a link to XFC user requests / feedback
------------------
version 0.0.3
------------------
- autoinstall in a project with just dependancy check to XFC
- decide what to put in minimal proto
------------------
version 0.0.2
------------------
- make first version of a function template
- make a clean menu item class
- make function question - yes - no
- introduce developper only permissions (for upload for instance)
------------------
version 0.0.1
------------------
- install autogist inside XFC
------------------
version 0.0.0
------------------
first version not saved
--]]
-- function to auto-install XFC with a single dependency
local autoinstall= function()
XFC.init()
if draw then
local draw0 = draw
draw = function() draw0() XFC.draw() end
end
if touched then
local touched0 = touched
touched = function(touch)
if XFC.touched(touch) then return end
touched0(touch)
end
else
touched = XFC.touched
end
end
-- this waits 3s then tries to install XFC. Delay needed for Main tab to be available
tween(1,{a=0},{a=1},linear,autoinstall)
local autoinstallOld= function()
local lineSetup =
[[ if XFC then XFC.init() end -- dont change this line!
]]
local lineDraw =
[[ if XFC then XFC.draw() end -- dont change this line!
]]
local lineTouched =
[[ if XFC and XFC.touched(touch) then return end -- dont change this line!
]]
local drawTouched =
[[ if XFC then XFC.draw() end -- dont change this line!
end
function touched(touch)
-- put this line at the BEGINNING of your touched()
if XFC and XFC.touched(touch) then return end -- dont change this line!
]]
-- look for lineSetup, and cancel if already there
local mainTab = readProjectTab("Main")
local s = string.find(mainTab,"XFC.init()")
if s then return end
-- otherwise,
alert("XFC in not installed. It will install automatically in your Main tab")
-- paste lineSetup
mainTab = string.gsub(mainTab,"function setup()",lineSetup)
-- paste lineDraw
-- paste lineTouched
mainTab = string.gsub(mainTab,
[[end
function touched(touch)]]
,drawTouched)
-- finalize Main tab
print(mainTab)
end
local MenuItem = class()
XFC.MenuItem = MenuItem
XFC.MenuItemNames = {} -- a table to manage items via their names
XFC.itemClass = {} -- a table to store all various item classes
XFC.itemClass["basic"] = MenuItem
function MenuItem:init(data)
self:setup(data)
end
function MenuItem:setup(data)
-- generic menu item class
-- self.parent = otherMenuItem required
-- self.name = a string to access easily this item (optionnal)
-- self.iconLetter = a string (1 letter or emoticon, but more is possible)
-- self.txt = data.txt a short text display aside the icon
-- self.permission: if present, then shown only if XFC[self.permission] is true
-- save all inputs
for i,v in pairs(data) do self[i]=v end
-- if parent defined by its name, then replace it by parent object
if self.parent and type(self.parent) == "string" then
local str = self.parent
self.parent = XFC.MenuItemNames[str]
if self.parent == nil then
print("error: the item name "..str.." is not registered")
end
end
-- all items must have a parent, except "root"
if self.parent then
self.parent:addChild(self) -- register to parent
else
if self.name ~= "root" then
print("error: menuItem "..tostring(self.name).." has no parent defined!")
end
end
-- register item in list
if self.name ~= nil then
if XFC.MenuItemNames[self.name] then
print("error: the item name "..self.name.." is already used")
end
XFC.MenuItemNames[self.name] = self
end
-- check other inputs to avoid errors
if self.iconLetter == nil then self.iconLetter = "" end
if self.txt == nil then self.txt = "" end
-- a table to store all children
self.children = {}
self.childrenVisible = false
-- draw and touch position is computed from parent position
self:computePosition()
self:hide()
end
function MenuItem:valid()
-- ok by default (to be implemented by derived classes)
return true
end
function MenuItem:update()
self.disabled = false
end
function MenuItem:callback()
if self.disabled then return end
-- default callback: toggle children visibility on/off
if self.childrenVisible then self:hideChildren() else self:showChildren() end
self:hideAllTxt()
end
function MenuItem:createIcon()
local w,h = self.w,self.h
local dy = 0
local icon = image(w,w)
local tfont = self.tfont or "AmericanTypewriter-Bold"
local fsize = self.fsize or 32
local bgcolor = self.bgcolor or color(218, 218, 218, 255)
local tcolor = self.tcolor or color(0, 0, 0, 255)
if tfont == "AppleColorEmoji" then
tcolor = color(255, 255, 255, 255)
dy=-w/10
end
setContext(icon)
resetStyle() resetMatrix()
background(bgcolor)
font(tfont)
fontSize(fsize)
fill(tcolor)
textMode(CENTER)
text(self.iconLetter,w/2,w/2+dy)
setContext()
self.icon = icon
end
function MenuItem:computePosition()
local w0,h0,w,h,dw,dh = 70,70,40,40,5,5
local x,y = WIDTH - w0,HEIGHT - h0
if self.parent then
if self.childIndex == 1 then
local pos = self.parent.position
x,y = pos.x,pos.y -- child start from parent
x = x - w - dw
y = y
else
local previousBrotherIndex = self.childIndex - 1
local pos = self.parent.children[previousBrotherIndex].position
x,y = pos.x,pos.y -- item starts from previous brother
x = x
y = y - h - dh
end
end
local mypos = vec2(x,y)
self.position = mypos
-- touch coordinates
self.tx, self.ty, self.tw, self.th = x+w/2, y+h/2, w/2, h/2
-- size definition
self.w0,self.h0,self.w,self.h,self.dw,self.dh = w0,h0,w,h,dw,dh
end
function MenuItem:show()
if self.permission and XFC[self.permission] == false then
self:hide()
return
end
-- these 2 variables are the same exactly, except inverted, but more clear for me
self.hidden = false
self.visible = true
-- self.icon = self:createIcon()
self:createIcon()
self:showIcon()
-- this is an animation
if self.parent then
local y = self.position.y
local ty = self.ty
local y0 = self.parent.position.y
local ty0 = self.parent.ty
self.position.y = y0
self.ty = ty0
local n = #self.parent.children
local duration = 0.5
if n<10 then duration = 0.4 *n/10 +0.1 end
tween(duration, self.position, {y=y})
tween(duration, self, {ty=ty})
end
end
function MenuItem:hide()
self.hidden = true
self.visible = false
self:hideChildren()
self:hideTxt()
self.icon = nil -- free memory from this image
collectgarbage()
end
-- details
function MenuItem:showIcon()
self.displayIcon = true
end
function MenuItem:hideIcon()
self.displayIcon = false
end
function MenuItem:showTxt()
self.displayTxt = true
-- a little animation
end
function MenuItem:hideTxt()
self.displayTxt = false
end
function MenuItem:showAllTxt()
local p = self.parent
if p then
for _,child in pairs(p.children) do child:showTxt() end
end
end
function MenuItem:hideAllTxt()
local p = self.parent
if p then
for _,child in pairs(p.children) do child:hideTxt() end
end
end
function MenuItem:tabExist(tabName)
local list = listProjectTabs()
local exist = false
for i,name in pairs(list) do if name==tabName then exist = true end end
return exist
end
function MenuItem:eraseAllTheseFields(fields)
for _,field in pairs(fields) do self[field] = nil end
for _,child in pairs(self.children) do child:eraseAllTheseFields(fields) end
end
function MenuItem:updateField(field,value)
self[field] = value
for _,child in pairs(self.children) do child:updateField(field,value) end
end
-- children functions
function MenuItem:addChild(item)
table.insert(self.children,item)
item.childIndex = #self.children
end
function MenuItem:removeChildren()
self.children = {}
end
function MenuItem:updateChildren()
for _,child in pairs(self.children) do child:update() end
end
function MenuItem:showChildren()
-- compute dynamic position
self:shiftChildrenUp()
-- show children
if #self.children > 0 then
self.childrenVisible = true
for _,child in pairs(self.children) do child:show() end
self.children[1]:showAllTxt()
else
self.childrenVisible = false
end
-- hide children of other items
local p = self.parent
if p then
for _,child in pairs(p.children) do
if child ~= self then child:hideChildren() end
end
end
end
function MenuItem:hideChildren()
self.childrenVisible = false
for _,child in pairs(self.children) do child:hide() end
end
function MenuItem:shiftChildrenUp(shift)
-- if no children, return
local n = #self.children
if n == 0 then return end
-- if no problem, return
local lastChild = self.children[n]
local yn = lastChild.position.y
local ymin = 30
if yn > ymin and shift==nil then return end
-- compute shift if not provided
local forced = (shift ~= nil)
if not forced then
shift = ymin - yn
local y0 = HEIGHT - self.h0
local firstChild = self.children[1]
local y1 = firstChild.position.y
if y1 + shift > y0 then shift = y0-y1 end
end
-- apply this shift to children
for _,child in pairs(self.children) do
local newy = child.position.y + shift
local newty = child.ty + shift
child.position.y = newy
child.ty = newty
child:shiftChildrenUp(shift)
end
end
-- draw functions
function MenuItem:drawIcon()
local position = self.position
local x,y = position.x, position.y
noSmooth() noStroke()
spriteMode(CORNER)
if self.disabled then tint(200) else tint(255) end
sprite(self.icon,x,y)
tint(255)
end
function MenuItem:drawTxt()
local position = self.position
local w,h = 400,40
local x,y = position.x - w -5, position.y
if x<0 then w = w + x - 5 ; x = 5 end
rectMode(CORNER)
textMode(CORNER)
if self.disabled then
fill(192)
else
fill(238)
end
rect(x,y,w,h)
font("ArialMT")
fontSize(18)
fill(0, 0, 0, 255)
text(self.txt,x+5,y+10)
end
function MenuItem:draw()
if self.hidden then return end
if self.displayIcon then self:drawIcon() end
if self.displayTxt then self:drawTxt() end
if self.childrenVisible then
for _,child in pairs(self.children) do child:draw() end
end
end
function MenuItem:touched(touch)
local touchIntercepted = false
if self.hidden then return touchIntercepted end
local x,y = touch.x, touch.y
local abs = math.abs
-- check if item touched
if abs(x- self.tx)<self.tw and abs(y- self.ty)<self.th then
if touch.state == BEGAN then self:callback(touch) end
touchIntercepted = true
else
touchIntercepted = false
end
-- or if its children touched
if self.childrenVisible then
for _,child in pairs(self.children) do
if not touchIntercepted
then touchIntercepted = child:touched(touch) end
end
end
return touchIntercepted
end
local ChoiceItem = class(XFC.MenuItem)
XFC.itemClass["choice"] = ChoiceItem
function ChoiceItem:init(data)
-- this item is a button to make choices
-- special fields of data:
-- data.choices = table of choice elements: {txt="comment",value=v,iconLetter=nil}
-- (iconLetter is optionnal)
-- data.currentValue : optionnal
-- data.tag : a str describing the variable
-- data.choiceCallback(v)
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = '?' end
-- shortcuts
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
-- top item
self:setup(data)
-- information
local item = {}
item.parent = self
item.txt = data.txt
self.info = infoItem(item)
-- choices
self.choiceItems = {}
if self.choices == nil then
print("error : choices field missing!")
else
for _,choice in pairs(self.choices) do
local item = {}
item.parent = self
item.txt = choice.txt
item.value = choice.value
item.callback = function(s)
self.choiceCallback(choice.value)
self.currentValue = choice.value
self:update()
end
self.choiceItems[choice.value] = basicItem(item)
end
end
self:update()
end
function ChoiceItem:update()
self.disabled = false
if self.choices == nil then self.disabled = true end
if self.disabled then
self.callback = function() end
else
self.txt = self.tag .." : " .. tostring(self.currentValue)
self.info.txt = self.tag .." : " .. tostring(self.currentValue)
for _,choice in pairs(self.choices) do
local value = choice.value
local item = self.choiceItems[value]
if self.currentValue == value
then item.iconLetter = '◉'
else item.iconLetter = '○'
end
item:createIcon()
end
self.callback = XFC.MenuItem.callback
end
end
local LinkItem = class(XFC.MenuItem)
XFC.itemClass["link"] = LinkItem
function LinkItem:init(data)
-- this item is a button to open a web link
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = '' end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
self:setup(data)
self:update()
end
function LinkItem:update()
self.disabled = false
self.link = self.parent.link or self.link
if self.link == nil then self.disabled = true end
if self.disabled then
self.callback = function() end
else
self.callback = self.openLink
end
end
function LinkItem:openLink()
-- standard callback (to erase other displayed)
XFC.MenuItem.callback(self)
-- open link
openURL(self.link,self.internal)
end
local function yesNoMenu(data)
-- create a sub-menu with a yes no question
-- data has same fields as a menuItem
-- fires data.callback( true | false) if the user touches yes or no
-- shortcuts
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
-- the question
local info = infoItem({parent=data.parent, txt = data.txt})
local parent = info.parent -- here it is an item, not a string
-- yes answer
local item = {}
item.parent = data.parent
item.tfont = "AppleColorEmoji"
item.iconLetter = '✅'
item.txt = "YES"
item.callback = function()
parent:hideChildren()
data.callback(true)
end
local yes = basicItem(item)
-- no answer
local item = {}
item.parent = data.parent
item.tfont = "AppleColorEmoji"
item.iconLetter = '⛔'
item.txt = "NO"
item.callback = function()
parent:hideChildren()
data.callback(false)
end
local no = basicItem(item)
end
XFC.menu = {}
XFC.menu["yesNoMenu"] = yesNoMenu
local InfoItem = class(XFC.MenuItem)
XFC.itemClass["info"] = InfoItem
function InfoItem:init(data)
-- this item is a button to show / hide all item txt
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = 'ℹ' end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
self:setup(data)
if self.txt == "" then self.txt = self.parent.txt end
self.callback = self.toggleAllInfos
end
function InfoItem:toggleAllInfos()
if self.displayTxt then self:hideAllTxt() else self:showAllTxt() end
if self.childrenVisible then self:hideChildren() else self:showChildren() end
end
-- thix is obsolete. Not used any longer.
local DocItem = class(XFC.MenuItem)
-- XFC.itemClass["doc"] = DocItem
function DocItem:init(data)
-- this item is a button to show a detailed documentation
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = "📋" end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
self:setup(data)
self.callback = self.docPopup
end
function DocItem:docPopup()
alert(self.more,"More details")
end
local InfoBox = class()
-- this tab was written by @Briarfox
XFC.InfoBox = InfoBox
XFC.InfoBox.style = {}
--#h - Header
--#c - code
--#s - syntax
--#t - text
--Styles defined
XFC.InfoBox.style.bg = {}
XFC.InfoBox.style.bg.dark = color(42,45,49, 255)
XFC.InfoBox.style.bg.medium = color(60,65,70,255)
XFC.InfoBox.style.bg.light = color(242,235,218)
local myFont = "ArialMT"
local myFontSize = 20
XFC.InfoBox.style.header = {}
XFC.InfoBox.style.header.font = myFont
XFC.InfoBox.style.header.color = color(250, 250, 250, 255)
XFC.InfoBox.style.header.size = myFontSize+4
XFC.InfoBox.style.syntax = {}
XFC.InfoBox.style.syntax.font = myFont
XFC.InfoBox.style.syntax.color = color(174,205,217,255)
XFC.InfoBox.style.syntax.size = myFontSize - 2
XFC.InfoBox.style.text = {}
XFC.InfoBox.style.text.font = myFont
XFC.InfoBox.style.text.color = color(255, 255, 255, 255)
XFC.InfoBox.style.text.size = myFontSize - 2
XFC.InfoBox.style.code = {}
XFC.InfoBox.style.code.font = myFont
XFC.InfoBox.style.code.color = color(72, 59, 48, 255)
XFC.InfoBox.style.code.size = myFontSize - 2
function InfoBox:init(str)
self.enabled = true
self.padding = 15
local imgStr = str
local height = 500
local width = 500
self.imgheader = {}
self.imgsyntax = {}
self.imgtext = {}
self.imgcode = {}
self.header = nil
self.syntax = nil
self.txt = nil
self.code = nil
self.returns = nil
self:format(str)
--create Header
font(XFC.InfoBox.style.header.font)
fontSize(XFC.InfoBox.style.header.size)
textWrapWidth(400)
self.imgheader.w,self.imgheader.h = textSize(self.header)
self.imgheader.h = self.imgheader.h + self.padding
self.imgheader.img = image(width,self.imgheader.h)
setContext(self.imgheader.img)
background(XFC.InfoBox.style.bg.medium)
fill(XFC.InfoBox.style.header.color)
textMode(CENTER)
text(self.header,width/2,self.imgheader.h/2)
setContext()
-----------------------------
--draw syntax header
font(XFC.InfoBox.style.header.font)
fontSize(20)
local synHead = {}
synHead.str = "Syntax"
synHead.w,synHead.h = textSize(synHead.str)
synHead.h = synHead.h + self.padding
synHead.img = image(width,synHead.h)
setContext(synHead.img)
background(XFC.InfoBox.style.bg.dark)
fill(XFC.InfoBox.style.syntax.color)
textMode(CENTER)
text(synHead.str,30,synHead.h/2)
setContext()
------------------------
--draw syntax
font(XFC.InfoBox.style.syntax.font)
fontSize(XFC.InfoBox.style.syntax.size)
self.imgsyntax.w,self.imgsyntax.h = textSize(self.syntax)
self.imgsyntax.h = self.imgsyntax.h + self.padding
self.imgsyntax.img = image(width,self.imgsyntax.h)
setContext(self.imgsyntax.img)
background(XFC.InfoBox.style.bg.medium)
fill(XFC.InfoBox.style.syntax.color)
textMode(CENTER)
text(self.syntax,width/2-100,self.imgsyntax.h/2)
setContext()
----------------------------
--draw text
font(XFC.InfoBox.style.text.font)
fontSize(XFC.InfoBox.style.text.size)
textWrapWidth(500 - self.padding)
textAlign(LEFT)
self.imgtext.w,self.imgtext.h = textSize(self.txt)
self.imgtext.h = self.imgtext.h + self.padding
self.imgtext.img = image(width,self.imgtext.h)
setContext(self.imgtext.img)
background(XFC.InfoBox.style.bg.dark)
fill(XFC.InfoBox.style.text.color)
textMode(CENTER)
text(self.txt,width/2,self.imgtext.h/2)
setContext()
---------------------------
--draw code header
font(XFC.InfoBox.style.code.font)
fontSize(18)
local codeHead = {}
codeHead.str = "Examples"
codeHead.w,codeHead.h = textSize(codeHead.str)
codeHead.h = codeHead.h + self.padding
codeHead.img = image(width,codeHead.h)
setContext(codeHead.img)
background(XFC.InfoBox.style.bg.medium)
fill(255, 255, 255, 255)
textMode(CENTER)
text(codeHead.str,45,codeHead.h/2)
setContext()
---------------------
--draw code
font(XFC.InfoBox.style.code.font)
fontSize(XFC.InfoBox.style.code.size)
textWrapWidth(500 - self.padding)
textAlign(LEFT)
textMode(CENTER)
self.imgcode.w,self.imgcode.h = textSize(self.code)
self.imgcode.h = self.imgcode.h + self.padding
self.imgcode.img = image(width,self.imgcode.h)
setContext(self.imgcode.img)
background(XFC.InfoBox.style.bg.light)
fill(XFC.InfoBox.style.code.color)
textMode(CENTER)
text(self.code,width/2 - 100,self.imgcode.h/2)
setContext()
------------------------
--bottom
local bottom = image(width,self.imgheader.h)
setContext(bottom)
background(XFC.InfoBox.style.bg.medium)
setContext()
self.img = image(500,self.imgheader.h+synHead.h+self.imgsyntax.h+self.imgtext.h+codeHead.h+self.imgcode.h+self.imgheader.h)
setContext(self.img)
background(255, 255, 255, 255)
spriteMode(CORNER)
local y = self.img.height - self.imgheader.h
sprite(self.imgheader.img,0,y)
y = y - synHead.h
sprite(synHead.img,0,y)
y = y - self.imgsyntax.h
sprite(self.imgsyntax.img,0,y)
y = y - self.imgtext.h
sprite(self.imgtext.img,0,y)
y = y - codeHead.h
sprite(codeHead.img,0,y)
y = y - self.imgcode.h
sprite(self.imgcode.img,0,y)
y = y - self.imgheader.h
sprite(bottom,0,y)
setContext()
end
function InfoBox:draw()
if self.enabled then
spriteMode(CENTER)
sprite(self.img,WIDTH/2,HEIGHT - self.img.height/2-50)
end
end
function InfoBox:touched(t)
if self.enabled and t.state == BEGAN then
if t.state == ENDED then self.enabled = false end
end
end
function InfoBox:format(str)
local s
local e
s,e = string.find(str,"#h",1)
e,_ = string.find(str,"%#",e)
if s ~= nil and e ~= nil then
self.header = string.sub(str,s+2,e-1)
elseif s~= nil and e == nil then
self.header = string.sub(str,s+2,#str) end
s,e = string.find(str,"#s",1)
e,_ = string.find(str,"%#",e)
if s ~= nil and e ~= nil then self.syntax = string.sub(str,s+2,e-1) elseif
s~= nil and e == nil then self.syntax = string.sub(str,s+2,#str) end
s,e = string.find(str,"#t",1)
e,_ = string.find(str,"%#",e)
if s ~= nil and e ~= nil then self.txt = string.sub(str,s+2,e-1) elseif
s~= nil and e == nil then self.txt = string.sub(str,s+2,#str) end
s,e = string.find(str,"#c",1)
e,_ = string.find(str,"%#",e)
if s ~= nil and e ~= nil then self.code = string.sub(str,s+2,e-1) elseif
s~= nil and e == nil then self.code = string.sub(str,s+2,#str) end
s,e = string.find(str,"#r",1)
e,_ = string.find(str,"%#",e)
if s ~= nil and e ~= nil then self.returns = string.sub(str,s+2,e-1) elseif
s~= nil and e == nil then self.returns = string.sub(str,s+2,#str) end
end
-- docitem2
local DocItem = class(XFC.MenuItem)
XFC.itemClass["doc"] = DocItem
function DocItem:init(data)
-- this item is a button to show a detailed documentation
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = "📋" end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
self:setup(data)
self:update()
end
function DocItem:update()
self.disabled = false
self.more = self.parent.more or self.more
if self.more == nil then self.disabled = true end
if self.disabled then
self.callback = function() end
else
self.callback = self.docPopup
end
end
function DocItem:docPopup()
-- standard callback (to erase other displayed)
XFC.MenuItem.callback(self)
-- create popup window...
self.popup = XFC.InfoBox(self.more)
-- and bypass normal XFC draw and touch:
self.XFCdraw = XFC.draw
self.XFCtouched = XFC.touched
XFC.draw = function() self.popup:draw() end
XFC.touched = function(touch)
if touch.state == BEGAN then
-- in case of touch, restore previous state:
self.popup = nil
XFC.draw = self.XFCdraw
XFC.touched = self.XFCtouched
collectgarbage()
end
local intercepted = true -- intercept any touch
return intercepted
end
end
local FileIO = class()
XFC.FileIO = FileIO
XFC.FileIO.json = false
--callback will be passed gist id,tabname
--XFC.FileIO.upload(tabname,callback)
--To Download:
--XFC.FileIO.download(gistid,tabname,singletab[true | false])
--Checks for json sets XFC.downloader.json to true to avoid future checks
XFC.FileIO.getJsonLib = function(callback)
local handleSuccess = function(data)
local jsonCode
jsonCode = data
if jsonCode then
XFC.FileIO.json = true
l = loadstring(jsonCode)
l()
callback()
--XFC.FileIO.GetProject(gistid,tabname,single)
end
end
http.request("https://dl.dropboxusercontent.com/s/9e4nvqeu4hsux2q/Json.lua?token_hash=AAFyMB98j4bnt_1gawf9wSke52hsoC7hsIvARcTuZNeOEw&dl=1", handleSuccess)
end
--This pulls the project once json has been loaded
XFC.FileIO.getProject = function(gistid,tabname,single,callback)
local handleSuccess = function(data,i,j)
local gist = json.decode(data)
local counter = 1
if single then
local str = ""
for k,v in pairs(gist.files) do
if k ~= "1aTabOrder" then
str = str..v.content
loadstring(v.content)()
end
end
saveProjectTab(tabname, str) -- Save a single tab
else
for k,v in pairs(gist.files) do
if k ~= "1aTabOrder" then
saveProjectTab(tabname..string.format("%03d",counter), v.content)
loadstring(v.content)()
counter = counter + 1
end
end
end
if callback then callback() end
alert("Download complete. You can now run the code or inspect it by exiting and viewing the tab",
">> "..tabname)
end
local handleFailure = function(data)
sound(SOUND_EXPLODE, 32351)
print(data)
end
http.request("https://api.github.com/gists/"..gistid,handleSuccess, handleFailure)
end
--Uploader get project
XFC.FileIO.uploadGist = function (tabname,callback)
local gist = {}
gist.public = public
gist.description = tabname or nil
gist.files = {}
gist.files[tabname .. ".lua"] = {content = readProjectTab(tabname)}
local projectJson = json.encode(gist)
local opts = {
data = projectJson,
method = "POST"
}
--success callback
local handleSuccess = function(data)
local gistReturn = json.decode(data)
callback(gistReturn.id,tabname)
alert("File has been uploaded to gistid: "..gistReturn.id,"Success")
--sound(SOUND_PICKUP, 11797)
--openURL(gistReturn.html_url)
end
--fail callback
local handleFailure = function(data)
sound(SOUND_EXPLODE, 32351)
print(data)
if data == "The request timed out" then print("But your gist should be there") end
end
http.request("https://api.github.com/gists",
handleSuccess,
handleFailure,
opts)
end
--Gist Pull
XFC.FileIO.download = function(gistid,tabname,single,callback)
if XFC.FileIO.json then
-- print("Already have json")
XFC.FileIO.getProject(gistid,tabname,single,callback)
else
XFC.FileIO.getJsonLib(function()
XFC.FileIO.getProject(gistid,tabname,single,callback)
end)
end
end
--Gist Push
XFC.FileIO.upload = function(tabname,callback)
if XFC.FileIO.json then
-- print("Already have json")
XFC.FileIO.uploadGist(tabname,callback)
else
XFC.FileIO.getJsonLib(function() XFC.FileIO.uploadGist(tabname,callback) end)
end
end
local DownloadItem = class(XFC.MenuItem)
XFC.itemClass["download"] = DownloadItem
function DownloadItem:init(data)
-- this item is a button to download a function
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = "📥" end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
if data.txt == nil then data.txt = "Download this function in this project" end
--[[
if data.gist == nil then
alert("error: you must provide a gist to download a fonction") end
if data.tabName == nil then
alert("error: you must provide a tabName to download a fonction") end
XFC.menu["yesNoMenu"]({parent=self, txt="Do you really want to download this function?",
callback = function(confirm)
self:downloadTab(confirm)
end
})
--]]
self:setup(data)
self:update()
end
function DownloadItem:update()
self.disabled = false
if self.tabName == nil or self.gist == nil then self.disabled = true end
if self.disabled then
-- remove yes no menu
self:removeChildren()
elseif #self.children == 0 then
-- create yes no menu
local dat = {}
dat.parent = self
dat.txt = "Do you really want to download this function?"
dat.callback = function(confirm)
self:downloadTab(confirm)
end
XFC.menu["yesNoMenu"](dat)
end
end
function DownloadItem:downloadTab(confirm)
-- cancel download if not requested
if confirm ~= true then return end
-- start download otherwise
callback = function()
XFC.tabInit[self.tabName]()
self.parent:updateChildren()
end
XFC.FileIO.download(self.gist,self.tabName,true,callback)
local msg = "Download requested from web.It may take several seconds. Please be patient!"
local boxName = ">> "..self.tabName
alert( msg, boxName)
end
local UpItem = class(XFC.MenuItem)
XFC.itemClass["upload"] = UpItem
function UpItem:init(data)
-- this item is a button to upload a function
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = "📤" end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
if data.txt == nil then data.txt = "upload this function to a gist" end
data.permission = "developper" -- this is devopper-only item
self:setup(data)
self:update()
end
function UpItem:update()
self.disabled = false
if self.tabName == nil then self.disabled = true end
if not self:tabExist(self.tabName) then self.disabled = true end
if self.disabled then
-- remove yes no menu
self:removeChildren()
elseif #self.children == 0 then
-- create yes no menu
local dat = {}
dat.parent = self
dat.txt = "Really want to upload tab ".. self.tabName .." ?"
dat.callback = function(confirm)
self:upload(confirm)
end
XFC.menu["yesNoMenu"](dat)
end
end
function UpItem:upload(confirm)
-- cancel download if not requested
if confirm ~= true then return end
-- start download otherwise
local function callback(gist,tab)
print("your tab " ..tab.. " has been saved to:")
print(gist)
-- alert("your gist has been created")
end
XFC.FileIO.upload(self.tabName,callback)
alert("Upload to github requested.It may take several seconds. Please be patient!")
end
local RemoveTab = class(XFC.MenuItem)
XFC.itemClass["remove"] = RemoveTab
function RemoveTab:init(data)
-- this item is a button to remove a tab
-- default icon (unless other required)
if data.iconLetter == nil then data.iconLetter = '⚠' end
if data.tfont == nil then data.tfont = "AppleColorEmoji" end
if data.txt == nil then data.txt = "Remove this tab" end
self:setup(data)
self:update()
end
function RemoveTab:update()
self.disabled = false
if self.tabName == nil then self.disabled = true end
if not self:tabExist(self.tabName) then self.disabled = true end
if self.disabled then
-- remove yes no menu
self:removeChildren()
elseif #self.children == 0 then
-- create yes no menu
local dat = {}
dat.parent = self
dat.txt = "Really want to remove tab ".. self.tabName .." ?"
dat.callback = function(confirm)
self:remove(confirm)
end
XFC.menu["yesNoMenu"](dat)
end
end
function RemoveTab:remove(confirm)
-- cancel remove if not requested
if confirm ~= true then return end
-- remove otherwise
local list = listProjectTabs()
local tabExist = false
for i,name in pairs(list) do if name==self.tabName then tabExist = true end end
if tabExist then
local msg = "The XFC tab containing this function has been removed from this project."
if XFC.remove[self.tabName] then
-- the tab contains a remove function, use it:
XFC.remove[self.tabName](self.tabName)
else
-- else directly erase the tab:
saveProjectTab(self.tabName,nil)
msg = msg
.."\nNote that the functions that were in this tab are still active in memory!"
.."\nSo restart this project to really update its behavior."
end
-- also remove data not supposed to be available
-- (not implemented yet: too much to do here, have to think of it)
self.parent:eraseAllTheseFields({"link","more"})
self.parent:updateChildren()
alert( msg , ">> "..self.tabName)
else
alert("This project tab is not present in your project, so it cannot be removed!",
">> "..self.tabName)
end
end
XFC.downloadList = {
}
local FunctionItem = class(XFC.MenuItem)
XFC.itemClass["function"] = FunctionItem
function FunctionItem:init(data)
-- this is a standard menu for each function
-- data must contain special fields:
-- txt, gist, tabName, more
-- shortcuts
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
local linkItem = XFC.itemClass["link"]
local docItem = XFC.itemClass["doc"]
local dwldItem = XFC.itemClass["download"]
local uploadItem = XFC.itemClass["upload"]
local removeItem = XFC.itemClass["remove"]
-- function item
data.iconLetter = "f()"
data.tfont = "Arial-ItalicMT"
data.fsize = 25
self:setup(data)
-- sub menu
-- function title
local item = {}
item.parent = self
item.txt = data.txt
local newItem = infoItem(item)
-- install function
local item = {}
item.parent = self
item.gist = data.gist
item.tabName = data.tabName
local newItem = dwldItem(item)
-- function documentation
local item = {}
item.parent = self
item.txt = "Detailed description"
item.more = data.more
local newItem = docItem(item)
-- function credits
local item = {}
item.parent = self
item.txt = "Credits: link to original code source"
item.link = data.link
local newItem = linkItem(item)
-- function remove
local item = {}
item.parent = self
item.tabName = data.tabName
local newItem = removeItem(item)
-- function upload
local item = {}
item.parent = self
item.tabName = data.tabName
local newItem = uploadItem(item)
end
local UnitTestsMenu = class(XFC.MenuItem)
XFC.itemClass["unitTestsMenu"] = UnitTestsMenu
function UnitTestsMenu:init(parent)
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
local docItem = XFC.itemClass["doc"]
local linkItem = XFC.itemClass["link"]
self:setup({parent=parent, name = "tests", iconLetter = "⚒" ,
permission = "developper", -- this is devopper-only item
txt = "various unit tests"})
infoItem({parent= "tests",})
basicItem({parent= "tests", name = "yesNo", iconLetter = "?" ,
txt = "test of menu : question - yes - no ",})
XFC.menu["yesNoMenu"]({parent="yesNo",
txt = "Do you agree?",
callback = function(ans)
if ans then print("yes") else print("no") end
end
})
local str = [[#h Cool Function
#stest( color )
test( color, something )
#t Testing the text there is lots of text so it must be tested. Testing the text there is lots of text so it must be tested. Testing the text there is lots of text so it must be tested. Testing the text there is lots of text so it must be tested.
param This does blah blah
@parameter This also does blah
@return This returns something
#c function draw()
code goes here
end
function test( Code )
--do something here
end
]]
docItem({parent= "tests", txt = "test of docItem", more = str})
docItem({parent= "tests", txt = "disabled doc item",})
linkItem({parent= "tests",
link="https://bitbucket.org/TwoLivesLeft/core/wiki/Codea%20Programming%20FAQ",
txt = "test of linkItem with @ignatz FAQ link"})
linkItem({parent= "tests",
txt = "test of linkItem with no link"})
local data = {}
data.txt = "test choice item"
data.parent = "tests"
data.choices = {
{txt="choice 1", value=1},
{txt="choice 2", value=2},
{txt="choice 3", value=3}
}
data.currentValue = 3
data.tag = "test choice"
data.choiceCallback = function(v) print(tostring(v)) end
XFC.itemClass["choice"](data)
local data = {}
data.txt = "test download item"
data.parent = "tests"
data.gist = "62a0660686725b81f29b"
data.tabName = "XFC016_test"
XFC.itemClass["download"](data)
local data = {}
data.txt = "test upload item"
data.parent = "tests"
data.tabName = "XFC016_test"
XFC.itemClass["upload"](data)
XFC.itemClass["upload"]({parent= "tests", txt = "disabled upload item",})
local data = {}
data.txt = "remove item"
data.parent = "tests"
data.tabName = "XFC016_test"
XFC.itemClass["remove"](data)
XFC.itemClass["remove"]({parent= "tests", txt = "disabled remove item",})
local data = {}
data.iconLetter = "f()"
data.tfont = "Arial-ItalicMT"
data.fsize = 25
data.txt = "test function wait"
data.parent = "tests"
data.gist = "62a0660686725b81f29b"
data.tabName = "XFC016_test"
data.more = str
XFC.itemClass["function"](data)
end
XFC.menu.unitTestsMenu = unitTestsMenu
local FunctionsMenu = class(XFC.MenuItem)
XFC.itemClass["functionMenu"] = FunctionsMenu
function FunctionsMenu:init(parent)
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
self.functionItem = XFC.itemClass["function"]
local data = {}
data.iconLetter = "f()"
data.tfont = "Arial-ItalicMT"
data.tfont = "Arial"
data.fsize = 25
data.txt = "useful functions"
data.parent = parent
data.name = "functions"
self:setup(data)
self.parentMenu = "functions"
local data = {}
data.txt = "Functions currently available"
data.parent = self.parentMenu
infoItem(data)
self.functions = {}
-- ADD your gist functions here:
self:add({ txt="wait(delay,callback)",
tabName="XFC110_wait", gist ="f9963a32ea8f85beac90"})
self:add({ txt="param_integer(name, min, max, init, cb)",
tabName="XFC120_param", gist ="56a89595a0a22a8a20a3"})
end
function FunctionsMenu:add(data)
data.parent = self.parentMenu
--table.insert(self.functions,data)
-- self.functions[data.tabName] = self.functionItem(data)
local item = self.functionItem(data)
XFC.tabs[data.tabName] = item
local init = XFC.tabInit[data.tabName]
if init then init() item:updateChildren() end
end
--XFC.menu.functionsMenu = function(parent) return FunctionsMenu(parent) end
-- TO BE SUPPRESSED: (clean up unit test example first)
XFC.Functions = {} -- to store functions
local LinksMenu = class(XFC.MenuItem)
XFC.itemClass["linksMenu"] = LinksMenu
function LinksMenu:init(parent)
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
local linkItem = XFC.itemClass["link"]
self:setup({parent=parent, name = "webLinks", iconLetter = '' ,
tfont = "AppleColorEmoji",
txt = "links to useful web discussions or tutorials"})
infoItem({parent= "webLinks", txt = "list of available useful links"})
local data = {}
data.parent = "webLinks"
data.txt = "@ignatz book 'lua for beginners'"
data.link = "https://www.dropbox.com/s/qh1e7ft4rvhlpt2/Lua%20for%20beginners.pdf"
linkItem(data)
local data = {}
data.parent = "webLinks"
data.txt = "@ignatz FAQ about code"
data.link = "https://bitbucket.org/TwoLivesLeft/core/wiki/Codea%20Programming%20FAQ"
data.internal = true
linkItem(data)
end
local SettingsMenu = class(XFC.MenuItem)
XFC.itemClass["settingsMenu"] = SettingsMenu
function SettingsMenu:init(parent)
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
local linkItem = XFC.itemClass["link"]
self:setup({parent=parent, name = "settings", iconLetter = "⚙" ,
txt = "settings of XFC"})
infoItem({parent= "settings", txt = "settings of XFC"})
local data = {}
data.txt = "developper settings"
data.parent = "settings"
data.choices = {
{txt="enable", value=true},
{txt="disable (recommended)", value=false},
}
data.currentValue = XFC.developper
data.iconLetter = "⚒"
data.tag = "enable developper buttons"
data.choiceCallback = function(v)
XFC.developper = v
end
XFC.itemClass["choice"](data)
XFC.itemClass["unitTestsMenu"]("settings")
end
local Menu = class()
XFC.menu.root = Menu
function Menu:init(x)
local basicItem = XFC.itemClass["basic"]
local infoItem = XFC.itemClass["info"]
local docItem = XFC.itemClass["doc"]
local linkItem = XFC.itemClass["link"]
-- this is the top root item menu
local root = basicItem({name="root", iconLetter = "X" , bgcolor = color(127,127,127,21),
txt = "hello test"})
self.root = root
root:show()
infoItem({parent=root, txt = "Menu of XFC, eXtensions For Codea"})
XFC.itemClass["functionMenu"]("root")
basicItem({parent=root, name = "classes", iconLetter = "C" , disabled = true,
txt = "useful classes"})
basicItem({parent=root, name = "shaders", iconLetter = "S" , disabled = true,
txt = "useful shaders"})
basicItem({parent=root, name = "toolbars", iconLetter = "T" , disabled = true,
txt = "useful toolbars"})
basicItem({parent=root, name = "apps", iconLetter = "A" , disabled = true,
txt = "complete stand-alone apps, games"})
XFC.itemClass["linksMenu"]("root")
basicItem({parent=root, name = "updates", iconLetter = '🔄' ,
tfont = "AppleColorEmoji", disabled = true,
txt = "check for available updates"})
XFC.itemClass["settingsMenu"]("root")
end
function Menu:draw()
self.root:draw()
end
function Menu:touched(touch)
local touchIntercepted = self.root:touched(touch)
return touchIntercepted
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment