[*] Add examples.
parent
53fdcdd843
commit
c159cb078c
@ -0,0 +1,124 @@
|
|||||||
|
--- Basic menu example
|
||||||
|
--
|
||||||
|
-- Trivial menu made of buttons.
|
||||||
|
-- Illustrates onHit() and onEnter()/onLeave()
|
||||||
|
-- events.
|
||||||
|
--
|
||||||
|
-- Relevant code to build UI inside: makeMainMenu().
|
||||||
|
--
|
||||||
|
-- Layout: Rows
|
||||||
|
-- Widget: Button
|
||||||
|
|
||||||
|
local yui = require 'lib.yui'
|
||||||
|
|
||||||
|
local Button = yui.Button
|
||||||
|
local Rows = yui.Rows
|
||||||
|
local Ui = yui.Ui
|
||||||
|
|
||||||
|
local GUI_WIDTH = 500
|
||||||
|
local GUI_HEIGHT = 300
|
||||||
|
local FONT_SIZE = 32
|
||||||
|
|
||||||
|
local function centerRectOnScreen(w, h)
|
||||||
|
local x = math.floor((love.graphics.getWidth() - w) / 2)
|
||||||
|
local y = math.floor((love.graphics.getHeight() - h) / 2)
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Creates main menu.
|
||||||
|
local function makeMainMenu()
|
||||||
|
-- Position the UI
|
||||||
|
local x,y = centerRectOnScreen(GUI_WIDTH, GUI_HEIGHT)
|
||||||
|
local rh = GUI_HEIGHT / 5 -- 5 elements along height
|
||||||
|
|
||||||
|
-- Keep track what's being focused...
|
||||||
|
widgetEnter = function (w)
|
||||||
|
guiStatus.current = "You're hovering \""..w.text.."\", feel like pressing it?"
|
||||||
|
end
|
||||||
|
widgetLeave = function (w)
|
||||||
|
guiStatus.previous = "So you left \""..w.text.."\"..."
|
||||||
|
end
|
||||||
|
|
||||||
|
return Ui.new {
|
||||||
|
x = x, y = y, -- Place UI at the calculated spot
|
||||||
|
|
||||||
|
-- Place the elements in rows from top to bottom
|
||||||
|
Rows {
|
||||||
|
Button {
|
||||||
|
-- Provide first button's size...
|
||||||
|
w = GUI_WIDTH, h = rh,
|
||||||
|
|
||||||
|
text = "Start game",
|
||||||
|
|
||||||
|
onHit = function ()
|
||||||
|
guiStatus = { current = "Game started!" }
|
||||||
|
end,
|
||||||
|
onEnter = widgetEnter,
|
||||||
|
onLeave = widgetLeave
|
||||||
|
},
|
||||||
|
Button {
|
||||||
|
-- ...subsequent widgets _in the same layout_
|
||||||
|
-- take last widget's size by default.
|
||||||
|
text = "Continue",
|
||||||
|
|
||||||
|
onHit = function()
|
||||||
|
guiStatus = { current = "Loading game..." }
|
||||||
|
end,
|
||||||
|
onEnter = widgetEnter,
|
||||||
|
onLeave = widgetLeave
|
||||||
|
},
|
||||||
|
Button {
|
||||||
|
text = "Options",
|
||||||
|
|
||||||
|
onHit = function()
|
||||||
|
guiStatus = { current = "Options pressed." }
|
||||||
|
end,
|
||||||
|
onEnter = widgetEnter,
|
||||||
|
onLeave = widgetLeave
|
||||||
|
},
|
||||||
|
Button {
|
||||||
|
text = "Credits",
|
||||||
|
|
||||||
|
onHit = function()
|
||||||
|
guiStatus = { current = "Showcasing credits 8)" }
|
||||||
|
end,
|
||||||
|
onEnter = widgetEnter,
|
||||||
|
onLeave = widgetLeave
|
||||||
|
},
|
||||||
|
Button {
|
||||||
|
text = "Quit",
|
||||||
|
|
||||||
|
onHit = function () love.event.quit() end,
|
||||||
|
onEnter = widgetEnter,
|
||||||
|
onLeave = widgetLeave
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.load()
|
||||||
|
guiStatus = { current = "Menu is open." }
|
||||||
|
guiFont = love.graphics.newFont('fonts/PixelDroidMenu.ttf', FONT_SIZE)
|
||||||
|
gui = makeMainMenu()
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.update(dt)
|
||||||
|
-- Let the UI update its status
|
||||||
|
gui:update(dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.draw()
|
||||||
|
love.graphics.setFont(guiFont)
|
||||||
|
|
||||||
|
-- Print UI status
|
||||||
|
local y = 0
|
||||||
|
if guiStatus.previous ~= nil then
|
||||||
|
love.graphics.print(guiStatus.previous, 0, y)
|
||||||
|
y = y + guiFont:getHeight()
|
||||||
|
end
|
||||||
|
love.graphics.print(guiStatus.current, 0, y)
|
||||||
|
|
||||||
|
-- Draw UI
|
||||||
|
gui:draw()
|
||||||
|
end
|
@ -0,0 +1,51 @@
|
|||||||
|
-- the ubiquitous "Hello, World!" demo.
|
||||||
|
-- 'Nuff said.
|
||||||
|
--
|
||||||
|
-- Layout: Rows
|
||||||
|
-- Widgets: Label, Button
|
||||||
|
-- Relevant UI construction code in: love.load()
|
||||||
|
|
||||||
|
local yui = require 'lib.yui'
|
||||||
|
|
||||||
|
-- Some convenience aliases
|
||||||
|
local Ui = yui.Ui
|
||||||
|
local Rows = yui.Rows
|
||||||
|
local Button, Label = yui.Button, yui.Label
|
||||||
|
|
||||||
|
local function centerRectOnScreen(w, h)
|
||||||
|
local x = math.floor((love.graphics.getWidth() - w) / 2)
|
||||||
|
local y = math.floor((love.graphics.getHeight() - h) / 2)
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.load()
|
||||||
|
local W, H = 400, 80 -- pick arbitrary UI size
|
||||||
|
local x, y = centerRectOnScreen(W, H)
|
||||||
|
|
||||||
|
gui = Ui.new {
|
||||||
|
x = x, y = y,
|
||||||
|
|
||||||
|
Rows {
|
||||||
|
Label {
|
||||||
|
w = W, h = H,
|
||||||
|
|
||||||
|
text = "Hello, World!"
|
||||||
|
},
|
||||||
|
Button {
|
||||||
|
text = "OBEY",
|
||||||
|
onHit = function () love.event.quit() end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.update(dt)
|
||||||
|
gui:update(dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.draw()
|
||||||
|
-- Pretty black out there, isn't it?
|
||||||
|
-- See more complete examples for shinier stuff :)
|
||||||
|
gui:draw()
|
||||||
|
end
|
@ -0,0 +1,79 @@
|
|||||||
|
local BASE = (...)..'.'
|
||||||
|
|
||||||
|
local endswith = require('lib.gear.strings').endswith
|
||||||
|
local yui = require 'lib.yui'
|
||||||
|
|
||||||
|
local Button = yui.Button
|
||||||
|
local Rows = yui.Rows
|
||||||
|
local Ui = yui.Ui
|
||||||
|
|
||||||
|
local Examples = {}
|
||||||
|
Examples.__index = Examples
|
||||||
|
|
||||||
|
|
||||||
|
local function isexample(file)
|
||||||
|
return file ~= 'init.lua' and endswith(file, '.lua')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loadexample(file)
|
||||||
|
love.event.clear()
|
||||||
|
for i in ipairs(love.handlers) do
|
||||||
|
love.handlers[i] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Restart to next example.
|
||||||
|
require(BASE..file)
|
||||||
|
if love.load then love.load() end
|
||||||
|
end
|
||||||
|
|
||||||
|
local W = 400
|
||||||
|
local RH = 32
|
||||||
|
|
||||||
|
local function makeSelectionMenu()
|
||||||
|
local menu = Rows {}
|
||||||
|
|
||||||
|
local files = love.filesystem.getDirectoryItems('examples')
|
||||||
|
table.sort(files)
|
||||||
|
|
||||||
|
for _,file in ipairs(files) do
|
||||||
|
if isexample(file) then
|
||||||
|
local name = file:sub(1, -5)
|
||||||
|
|
||||||
|
menu[#menu+1] = Button {
|
||||||
|
w = W, h = RH,
|
||||||
|
|
||||||
|
text = name,
|
||||||
|
notranslate = true,
|
||||||
|
onHit = function() loadexample(name) end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
menu[#menu+1] = Button {
|
||||||
|
w = W, h = RH,
|
||||||
|
|
||||||
|
text = "Quit",
|
||||||
|
onHit = function() love.event.quit() end
|
||||||
|
}
|
||||||
|
|
||||||
|
local x = math.floor(love.graphics.getWidth() - W) / 2
|
||||||
|
local y = math.floor(love.graphics.getHeight() - RH * #menu) / 2
|
||||||
|
|
||||||
|
return Ui.new {
|
||||||
|
x = x, y = y,
|
||||||
|
menu
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.load()
|
||||||
|
gui = makeSelectionMenu()
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.update(dt)
|
||||||
|
gui:update(dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.draw()
|
||||||
|
gui:draw()
|
||||||
|
end
|
||||||
|
|
||||||
|
return Examples
|
@ -0,0 +1,264 @@
|
|||||||
|
--- Options screen example
|
||||||
|
--
|
||||||
|
-- A fairly complete configuration menu to demonstrate
|
||||||
|
-- several types of widgets coexisting.
|
||||||
|
-- Many widgets' behavior is tuned by their attributes.
|
||||||
|
--
|
||||||
|
-- Relevant code to build UI inside: makeOptionsMenu().
|
||||||
|
--
|
||||||
|
-- Layout: Rows, Columns
|
||||||
|
-- Widget: Button, Checkbox, Choice, Input, Label, Slider, Spacer
|
||||||
|
|
||||||
|
local yui = require 'lib.yui'
|
||||||
|
|
||||||
|
local Button = yui.Button
|
||||||
|
local Checkbox = yui.Checkbox
|
||||||
|
local Choice = yui.Choice
|
||||||
|
local Columns = yui.Columns
|
||||||
|
local Input = yui.Input
|
||||||
|
local Label = yui.Label
|
||||||
|
local Rows = yui.Rows
|
||||||
|
local Slider = yui.Slider
|
||||||
|
local Spacer = yui.Spacer
|
||||||
|
local Ui = yui.Ui
|
||||||
|
|
||||||
|
local GUI_WIDTH = 500
|
||||||
|
local GUI_HEIGHT = 300
|
||||||
|
local FONT_SIZE = 32
|
||||||
|
|
||||||
|
-- A dummy save file, for demo purposes.
|
||||||
|
local dummySave = {}
|
||||||
|
|
||||||
|
-- Dummy config load mock.
|
||||||
|
function dummySave.load()
|
||||||
|
local config = {}
|
||||||
|
|
||||||
|
-- The default configuration
|
||||||
|
local defconfig = {
|
||||||
|
name = "Player 1",
|
||||||
|
graphics = 'medium',
|
||||||
|
lang = 'en',
|
||||||
|
fullscreen = false,
|
||||||
|
musicVolume = 80,
|
||||||
|
sfxVolume = 90
|
||||||
|
}
|
||||||
|
|
||||||
|
local saved = dummySave.latest or defconfig
|
||||||
|
|
||||||
|
print("Loading configuration: {")
|
||||||
|
for k,v in pairs(saved) do
|
||||||
|
config[k] = v
|
||||||
|
|
||||||
|
print(("\t%s = %s,"):format(k, v))
|
||||||
|
end
|
||||||
|
print("}")
|
||||||
|
|
||||||
|
return config
|
||||||
|
end
|
||||||
|
-- Dummy config save mock
|
||||||
|
function dummySave.save(config)
|
||||||
|
dummySave.latest = {}
|
||||||
|
|
||||||
|
print("Saving configuration: {")
|
||||||
|
for k,v in pairs(config) do
|
||||||
|
dummySave.latest[k] = v
|
||||||
|
|
||||||
|
print(("\t%s = %s,"):format(k, v))
|
||||||
|
end
|
||||||
|
print("}")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Center rectangle on screen.
|
||||||
|
local function centerRectOnScreen(w, h)
|
||||||
|
local x = math.floor((love.graphics.getWidth() - w) / 2)
|
||||||
|
local y = math.floor((love.graphics.getHeight() - h) / 2)
|
||||||
|
|
||||||
|
return x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Actual menu creation.
|
||||||
|
local function makeOptionsMenu()
|
||||||
|
-- Position the UI
|
||||||
|
local x,y = centerRectOnScreen(GUI_WIDTH, GUI_HEIGHT)
|
||||||
|
local vpad = 8
|
||||||
|
local hpad = 4
|
||||||
|
|
||||||
|
local w = (GUI_WIDTH - hpad) / 2 -- cut away padding from widget width
|
||||||
|
local h = (GUI_HEIGHT - vpad) / 9 -- 9 rows (Spacer counts as 2)
|
||||||
|
|
||||||
|
-- Load configuration "from disk"
|
||||||
|
local config = dummySave.load()
|
||||||
|
|
||||||
|
-- Make configuration editable via UI
|
||||||
|
return Ui.new {
|
||||||
|
x = x, y = y,
|
||||||
|
|
||||||
|
Rows {
|
||||||
|
padding = vpad,
|
||||||
|
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Label {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Name"
|
||||||
|
},
|
||||||
|
Input {
|
||||||
|
text = config.name, -- populate initial value
|
||||||
|
|
||||||
|
onChange = function(_, text)
|
||||||
|
config.name = text -- write changed value back
|
||||||
|
end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Label {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Language"
|
||||||
|
},
|
||||||
|
Choice {
|
||||||
|
-- We don't want languages to be translated.
|
||||||
|
notranslate = true,
|
||||||
|
|
||||||
|
choices = {
|
||||||
|
{ text = "English", value = 'en' }, -- just kidding, only English in demo :)
|
||||||
|
-- { text = "Français", value = 'fr' },
|
||||||
|
-- { text = "Italiano", value = 'it' },
|
||||||
|
-- { text = "日本語", value = 'ja' }
|
||||||
|
},
|
||||||
|
default = config.lang,
|
||||||
|
nowrap = true,
|
||||||
|
|
||||||
|
onChange = function(_, choice) config.lang = choice.value end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Label {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Graphics"
|
||||||
|
},
|
||||||
|
Choice {
|
||||||
|
choices = {
|
||||||
|
-- Text may be localized,
|
||||||
|
-- so map entries to well known enum values.
|
||||||
|
{ text = "Fastest", value = 'low' },
|
||||||
|
{ text = "Normal", value = 'medium' },
|
||||||
|
{ text = "Best", value = 'high' }
|
||||||
|
},
|
||||||
|
default = config.graphics,
|
||||||
|
nowrap = true,
|
||||||
|
|
||||||
|
onChange = function(_, choice) config.graphics = choice.value end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Label {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Fullscreen"
|
||||||
|
},
|
||||||
|
Checkbox {
|
||||||
|
checked = config.fullscreen,
|
||||||
|
|
||||||
|
onChange = function(_, checked) config.fullscreen = checked end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Label {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Music"
|
||||||
|
},
|
||||||
|
Slider {
|
||||||
|
min = 0, max = 100,
|
||||||
|
value = config.musicVolume,
|
||||||
|
|
||||||
|
onChange = function(_, value) config.musicVolume = value end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Label {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Effects"
|
||||||
|
},
|
||||||
|
Slider {
|
||||||
|
min = 0, max = 100,
|
||||||
|
value = config.sfxVolume,
|
||||||
|
|
||||||
|
onChange = function(_, value) config.sfxVolume = value end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Spacer { h = 2*h }, -- leave 2 rows out.
|
||||||
|
|
||||||
|
Columns {
|
||||||
|
padding = hpad,
|
||||||
|
|
||||||
|
Button {
|
||||||
|
w = w, h = h,
|
||||||
|
text = "Back",
|
||||||
|
|
||||||
|
cancelfocus = true, -- gets focused on ESC.
|
||||||
|
|
||||||
|
onHit = function() love.event.quit() end
|
||||||
|
},
|
||||||
|
Button {
|
||||||
|
text = "Apply",
|
||||||
|
|
||||||
|
onHit = function()
|
||||||
|
-- Save configuration "on disk"
|
||||||
|
dummySave.save(config)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.load()
|
||||||
|
guiFont = love.graphics.newFont('fonts/PixelDroidMenu.ttf', FONT_SIZE)
|
||||||
|
gui = makeOptionsMenu()
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.update(dt)
|
||||||
|
-- Let the UI update its status
|
||||||
|
gui:update(dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Options menu contains a text input field,
|
||||||
|
-- this requires propagating LÖVE input events to UI.
|
||||||
|
function love.keypressed(key, scan, isrepeat)
|
||||||
|
gui:keypressed(key, scan, isrepeat)
|
||||||
|
end
|
||||||
|
function love.keyreleased(key, scan)
|
||||||
|
gui:keyreleased(key, scan)
|
||||||
|
end
|
||||||
|
function love.textinput(text)
|
||||||
|
gui:textinput(text)
|
||||||
|
end
|
||||||
|
function love.textedited(text, start, len)
|
||||||
|
gui:textedited(text, start, len)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.draw()
|
||||||
|
love.graphics.setFont(guiFont)
|
||||||
|
|
||||||
|
-- Draw menu title
|
||||||
|
local title = "Options"
|
||||||
|
local tw = guiFont:getWidth(title)
|
||||||
|
local th = guiFont:getHeight()
|
||||||
|
local tx = (love.graphics.getWidth() - tw) / 2
|
||||||
|
local ty = th*2
|
||||||
|
love.graphics.print(title, tx,ty)
|
||||||
|
|
||||||
|
-- Draw UI
|
||||||
|
gui:draw()
|
||||||
|
end
|
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
pixeldroid fonts
|
||||||
|
|
||||||
|
Available at: https://github.com/pixeldroid/fonts
|
||||||
|
|
||||||
|
.otf, .ttf, and .fnt files can be downloaded from the releases page.
|
||||||
|
pixeldroid fonts are licensed under the Open Font License (OFL).
|
||||||
|
|
||||||
|
Full SIL Open Font License: https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL
|
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
Loading…
Reference in New Issue