Skip to content

Nlcke/layout

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Layout

Layout is GUI framework for Gideros game engine.

Features:

  • User-friendly interface
  • Fully customizable
  • Mouse, touch, keyboard, joystick support
  • Powerful animations
  • Predefined events
  • Easy-to-use inheritance
  • Various scale modes
  • Advanced positioning and sizing
  • Template grids
  • Kinetic scrolling and moving
  • Move/Scale/Rotate for images' preview
  • Resource loader

Table of Contents

Copy Layout.lua file to your Gideros project and you will get access to Layout class without the need to require it. If you want to look at Layout examples then just download everything from this git and open Layout.gproj in Gideros Studio.

layout = Layout.new{} -- create empty layout
stage:addChild(layout)      -- add it to the stage
textfield = TextField.new(nil, "Hello, World!", "|")
layout:update{textfield}            -- update layout

Creates new layout. Accepts only one parameter which must be a table with layout settings. Most common way to use it:

layout = Layout.new{
    child1,
    child2,
    ...
    childN,
    setting1 = value1,
    setting2 = value2,
    ...
    settingN = valueN
}

Alternatively you can create a table with settings and pass it to layouts later:

settings = {child1, child2, ... childN, setting1 = value1, setting2 = value2, ... settingN = valueN}
layout1 = Layout.new(settings)
layout2 = Layout.new(settings)

Or you can create empty layout with default settings and update it afterwards:

layout = Layout.new{}
layout{child1, child2, ... childN, setting1 = value1, setting2 = value2, ... settingN = valueN}

Each integer key will be treated as a child to add and other keys will be treated as settings. NOTE: It is an error to use it without any parameters (Layout.new()) or call it with multiple arguments (Layout.new(a, b, c)).

Extends Layout or Layout-based class with new settings and returns new class. Accepts only one parameter p which should be a table. All settings from this table will override existing parameters or create new ones. Resulting class can be instantiated (new) or extended (with).

There are 3 special callback-keys which you can optionally use in p table to make your classes more flexible:

  • init(self, p) -- called at class instantiation
  • ext(self, child) -- called at children adding
  • upd(self, p) -- called at layout update

All existing settings will be overridden silently so it's recommended to check parent class first if you don't know it's structure well. For example, if you want to add buttonText key to Layout class you can do assert(Layout.buttonText) to check if it exists.

Examples:

Button = Layout:with{
	text = "BUTTON", textColor = 0xFFFFFF;
	absW = 200, absH = 100,
	absX = 0, absY = 0,
	bgrC = 0x0088AA,
	bgrA = 1.0,
	
	init = function(self, p)
		self.textfield = TextField.new(font, self.text, "|")
		self.textfield:setTextColor(self.textColor)
		table.insert(p, self.textfield)
	end,
	
	upd = function(self, p)
		if p.text then self.textfield:setText(p.text, "|") end
	end,
	
	anPress = Layout.newAnimation(14, 7, 0.04),
	anHover = Layout.newAnimation(14, 7, 0.02),
	
	onPress = function(self) print(self.text, self.col, self.row) end
}

local button = Button.new{}
stage:addChild(button)

Updates existing layout with new settings from optional settings table p and/or adds children with numeric indexes from it. Most common way to use it:

layout:update{
    child1,
    child2,
    ...
    childN,
    setting1 = value1,
    setting2 = value2,
    ...
    settingN = valueN
}

Or you can pass a table with settings to it:

local settings = {child1, child2, ... childN, setting1 = value1, setting2 = value2, ... settingN = valueN}
layout:update(settings)

You should call update (without any arguments) after you finished modification of template grid database via layout(col, row) or layout.database[i] in order to update the cells:

local database = {{absX = 10}, {absX = 20}, {absX = 30}}
local layout = Layout.new{cols = 1, template = Layout, database = database}
stage:addChild(layout)
local cell = layout(1, 2)
cell.absX = 100
database[3].absX = 300
layout:update()

Each layout and sprite can have optional id key to access it from it's parent layout where id key can be any value. It's convenient if you want to create complex layout in declarative way (like HTML or XML):

editor = Layout.new{
	Layout.new{id = "menu",
    	Layout.new{id = "button1"},
        Layout.new{id = "button2"},
        Layout.new{id = "button3"}
    },
    Layout.new{id = "textfield"},
    Layout.new{id = "statusbar"},
}
editor "menu" "button2":update{bgrC = 0xFF00FF}
editor "menu" "button3":update{absX = 100}

Each layout and sprite can have optional col and row numeric keys when used as a cell inside parent layout so you can access them using that keys:

grid = Layout.new{
	cellAbsW = 200, cellAbsH = 100,
	Layout.new{col = 0, row = 0, TextField.new(nil, "Cell [0, 0]", "|")},
	Layout.new{col = 1, row = 0, TextField.new(nil, "Cell [1, 0]", "|")},
    Layout.new{col = 0, row = 1, TextField.new(nil, "Cell [0, 1]", "|")},
    Layout.new{col = 1, row = 1, TextField.new(nil, "Cell [1, 1]", "|")},
    Layout.new{col = 0.5, row = 0.5, TextField.new(nil, "Cell [0.5, 0.5]", "|")},
}
grid(0, 0):update{bgrA = 0.5}
grid(0.5, 0.5):update{bgrA = 0.8}

If template grid used then you will get a table from database, not an layout. In this case you need to call updateTemplateGrid method in order to update the scene.:

database = {}
for i = 1, 1000 * 1000 do
    database[i] = {bgrC = math.random(0, 0xFFFFFF), bgrA = 1.0}
end
grid = Layout.new{
    template = Layout, database = database,
    scroll = true, content = true,
    cellAbsW = 200, cellAbsH = 50,
    cols = 1000, rows = 1000,
}
grid(20, 10).bgrC = 0xFF0000
grid(10, 14).bgrC = 0x00FF00
grid:updateTemplateGrid()

NOTE: In Layout cols and rows are 0-based and can be floating point numbers i.e. you just define cell position (col as X and row as Y relative to cell definition in parent layout). This way you can place cells anywhere and in any order.

Sets focus on a sprite. You will the selector above the sprite. Selector will have colors and alphas defined in layout selLineC, selLineA, selFillC, selFillA keys. Examples:

layout = Layout.new{}
Layout.select(layout)

Plays an animation, optionally can animate state transitions and if specified a callback function will be executed at the end of animation. See Animation section for full description of available animation parameters. If defined state must be a table with numeric keys supported by this Layout class. Examples:

local layout = Layout.new{bgrA = 1.0, bgrC = 0xFF0000, absX = 0, absY = 200}
stage:addChild(layout)
local animation = Layout.newAnimation()
local state = {absX = 400, absY = 0}
local callback = function(self) print(self.absX, self.absY) end
layout: play(animation, state, callback)

Creates new random animation. See description of frames, mark and strength keys at Animation section. seed parameter is a random seed which can be used to get same animation each time. Examples:

local animation1 = Layout.newAnimation()
local animation1 = Layout.newAnimation(30)
local animation1 = Layout.newAnimation(20, 0.5)
local animation1 = Layout.newAnimation(60, 20, 0.3)
local animation1 = Layout.newAnimation(20, -1, 0.3, 343234234)
-- anchored (to width and height of parent) positioning
ancX = 0.5, 
ancY = 0.5,

-- relative (to width and height of parent) positioning
relX = false,
relY = false,

-- absolute positioning (disables relative and anchored one)
absX = false, -- absolute X
absY = false, -- absolute Y

-- absolute size (disables relative and anchored one)
absW = false,
absH = false,

-- relative (to width and height of parent) size
relW = 1.0,
relH = 1.0,

-- 	width/height restriction 
limW = false, -- maximal width/height aspect ratio, [0..]
limH = false, -- maximal height/width aspect ratio, [0..]

-- scrollable or movable content
content = false, -- enables content size updates

-- relative content size
conRelW = 1, -- content width relative to parent, [false|number]
conRelH = 1, -- content height relative to parent, [false|number]

-- absolute content size (disables relative width and/or height)
conAbsW = false, -- content absolute width (in pixels), [false|number]
conAbsH = false, -- content absolute height (in pixels), [false|number]

-- background
bgrC = 0x000000, -- background color
bgrA =      0.0, -- background alpha

-- selector color settings
selLineC = 0x000000, -- selector line color
selLineA = 1.0,      -- selector line alpha
selFillC = 0x000000, -- selector fill color
selFillA = 0.1,      -- selector fill alpha

-- texture
texture = false, -- texture object (from Texture.new)
texM = Layout.FIT_ALL, -- texture scale mode
texC = 0xFFFFFF, -- texture color
texA = 1.0, -- texture alpha
texS = 1.0, -- texture scale
texAncX = 0.5,   -- texture anchored X, [0..1]
texAncY = 0.5,   -- texture anchored Y, [0..1]
texOffX = 0,     -- texture X offset (in pixels)
texOffY = 0,     -- texture Y offset (in pixels)

-- non-layout sprites
sprM = Layout.FIT_ALL, -- sprite scale mode
sprS = 1.0, -- sprite scale
sprX = 0.5, -- sprite X
sprY = 0.5, -- sprite Y

-- relative center (affects rotation and scaling)
centerX = 0.5, -- [0..1]
centerY = 0.5, -- [0..1]

-- template grid
template    = false, -- Layout or Layout-based class
database    = false, -- list of cells' parameters
columnsFill = false, -- columns will be filled first if true

-- borders for cells
borderW = 0, -- cell border width
borderH = 0, -- cell border height

cols = 0, -- grid columns (integer) number, [0..]
rows = 0, -- grid rows (integer) number, [0..]

cellRelW = 1, -- cell relative width
cellRelH = 1, -- cell relative width

cellAbsW = false, -- cell absolute width
cellAbsH = false, -- cell absolute height

-- cell
col  = false, -- cell column number (integer|false)
row  = false, -- cell row number (integer|false)
colW =   1.0, -- cell width relative to default cell width
rowH =   1.0, -- cell height relative to default cell height

-- identification
id  = nil, -- to get child by id with 'layout(id)' call

-- inheritance
init = false, -- callback at instantiation (useful for custom classes)
	-- [false|function(self, parameters)]
ext  = false, -- callback at children adding (to modify them)
	-- [false|function(self, child)]
upd  = false, -- callback at updating (useful for custom classes)
	-- [false|function(self, parameters)]

-- keyboard control, can have multiple keys for the same action
keys = { -- [realCode] = action
	[16777234] =   "LEFT", -- jump to leftward cell
	[16777235] =     "UP", -- jump to upward cell
	[16777236] =  "RIGHT", -- jump to rightward cell
	[16777237] =   "DOWN", -- jump to downward cell
	[16777220] = "SELECT", -- enter the layout or press it
	[16777219] =   "BACK", -- return to parent layout or stage
},

-- gamepad control, can have multiple buttons for the same action
buttons = { -- [keyCode] = action
	[21]  =     "UP",
	[22]  =   "DOWN",
	[105] =  "RIGHT",
	--[???] = "LEFT", -- controller plugin is broken (only on Windows?)
	[96]  = "SELECT",
	[97]  =   "BACK",
	
	-- left stick for "UP", "DOWN", "RIGHT", "LEFT" actions
	stickDeadzone = 0.5, -- [0..1], stick disabled at 1
},

-- moving/scrolling
moveReactionX =   1, -- reaction coefficient for X while layout dragged
moveReactionY =   1, -- reaction coefficient for Y while layout dragged
moveDeadzone  =   5, -- moving/scrolling starts outside this zone, [0..]
moveFriction  = 0.5, -- friction coefficient while layout dragged
moveDamping   = 0.9, -- damping coefficient while layout released
moveDelta     =   1, -- area side to detect moving/scrolling, [0..]

-- scrolling
scrollFrames = 20, -- animation frames for keyboard or joystick scroll

-- scaling
scaleMouseResp = 0.005, -- scale response for mouse
scaleTouchResp = 0.005, -- scale response for touch
scaleMin       =   0.2, -- scale minimal value
scaleMax       =   2.0, -- scale maximal value

-- tilting
tiltMouseResp = 1, -- tilt response for mouse
tiltTouchResp = 1, -- tilt response for touch

events = true, -- enable mouse/touch events, [false|true]

-- event callbacks
onAdd    = false, -- callback at added to stage event, [false|function]
onRemove = false, -- callback at removed from stage event, [false|function]
onHover  = false, -- callback at mouse hovering, [false|function]
onPress  = false, -- callback at LMB or touch press, [false|function]
onHold   = false, -- callback at LMB or touch while hold, [false|function]
onMove   = false, -- callback at layout moving
onScroll = false, -- callback at layout scrolling

-- built-in callbacks
scroll = false, -- move children with mouse or touch, [false|true]
move   = false, -- move layout with mouse or touch, [false|true]
scale  = false, -- scale layout with RMB or double touch, [false|true]
tilt   = false, -- tilt layout with RMB or double touch, [false|true]

-- animation
anAdd    = false, -- opening animation (mark=0)
anRemove = false, -- ending animation (mark=-1)
anPress  = false, -- press animation (mark>0)
anHover  = false, -- hover animation (mark>0) 

Layout has optional resource loader to automatically load various resources. From the box it supports .jpg, .png, .wav, .mp3, .ttf, .otf, .lua, .json. Resource Loader returs a table with resources, their names and indexes where resources can be accessed with t[integer_number] or t[resource_name] and resource name can be received with negative index i.e. t[-integer_number].

It has following interface:

Layout.newResources(p) where p is a table with following parameters:

path    = string  -- path to directory with resources
subdirs = boolean -- load resources from subdirectories
names   = string  -- table of names to filter directory files
from    = number  -- index of first resource file to load
to      = number  -- index of last resource file to load
output  = boolean -- print list of resource files
namemod = function(name, path, base, ext, i) -- to filter file names
onlynames = boolean -- instead of resources return filenames

textureFiltering = boolean
textureOptions   = table
fontSize         = number
fontText         = text
fontFiltering    = boolean

Examples:

local examples = Layout.newResources{
	path = "|R|examples",
	namemod = function(name, path, base, ext, i) return base end
}

Animation should be a table and only the following special and standard keys are supported for it otherwise you will get an error.

  • frames defines animation length in frames. Should be an integer number greater than 0 or you will get an error message.
  • mark defines the type of animation and accepts following values:
    • -1 for ending animation from initial state to new one
    • 0 for opening animation from new state to initial one
    • 0.. for three-phase animation from initial state to new state and to initial state. If it is greater or equal to 1 then this number will be used as a mark at which animation will be reverted back. If it is between 0 and 1 then it will be multiplied on the number of frames first.
  • strength is optional key which defines multiplier for time parameter (range of time is [0..1]) to change animation range. Equal to 1 if not defined.
  • x
  • y
  • anchorX
  • anchorY
  • rotationX
  • rotationY
  • scaleX
  • scaleY
  • rotation
  • alpha
  • redMultiplier
  • greenMultiplier
  • blueMultiplier
  • alphaMultiplier

They are standard because they are the same as for Sprite.set method. However they are not absolute as for Sprite. They are relative to initial state of layout and some of them changed to better fit in [0..1] relative time range. For each of them 0 value means no change. For x, y, anchorX, anchorY values will be multiplied to width and height of animated layout and rotation will be multiplied by 360 degrees.

Each standard key is optional and can be either number or function.

If function key used it must receive one numeric value and return one numeric value. Most of standard math library functions are supported.

Animation can be played via Layout:play(animation, state, callback) method or can be assigned to built-in animation events:

  • anAdd -- opening animation when added to a parent
  • anRemove -- ending animation when removed from a parent
  • anPress -- three-phase animation when layout pressed
  • anHover -- three-phase animation when layout hovered

NOTE: you can animate any numeric key of Layout if you pass a table with new state to Layout.play i.e. you can animate absX, col, sprX etc. This works for Layout-based classes too if they have defined their numeric keys in upd function.

Examples:

-- rotates and changes X anchor position when added to parent
local layout1 = Layout.new{
    bgrA = 1.0,
    anAdd = {frames = 60, mark = 0, rotation = 1, anchorX = 1}
}
stage:addChild(layout1)

-- horizontally scales and changes alpha when removed from parent
local layout2 = Layout.new{
    bgrA = 1.0,
    anRemove = {frames = 60, mark = -1, scaleX = math.log, alpha = math.sqrt}
}
stage:addChild(layout2)
layout2:removeFromParent()

-- this layout get random animation which will be played with 'play' method
local layout3 = Layout.new{
    bgrA = 1.0,
}
stage:addChild(layout3)
local animation = Layout.newAnimation()
layout3: play(animation)

Copyright (c) 2016 Nikolay Yevstakhov

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

Gideros GUI framework

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages