summaryrefslogtreecommitdiffhomepage
path: root/not/Selector.lua
diff options
context:
space:
mode:
Diffstat (limited to 'not/Selector.lua')
-rw-r--r--not/Selector.lua365
1 files changed, 139 insertions, 226 deletions
diff --git a/not/Selector.lua b/not/Selector.lua
index ef78778..ee6f0e3 100644
--- a/not/Selector.lua
+++ b/not/Selector.lua
@@ -1,282 +1,195 @@
-require "not.Element"
-
--- `Selector`
--- Used in Menu for selecting various things from list. Works for each Controller set or globally.
---[[
-How to use `Selector` in `Menu` config file?
-selector:new(menu)
- :setPosition(x, y)
- :setMargin(8) -- each block has marigin on both sides; they do stack
- :setSize(32, 32) -- size of single graphics frame
- :set("list", require "nautslist")
- :set("icons_i", love.graphics.newImage("assets/portraits.png"))
- :set("icons_q", require "portraits")
- :set("global", false) -- true: single selector; false: selector for each controller set present
- :init()
-]]
-Selector = Element:extends()
+-- Element for selecting variable from list.
+Selector = require "not.Element":extends()
-Selector.width = 0
-Selector.height = 0
-Selector.margin = 0
-Selector.focused = false
-Selector.global = false
-Selector.delay = 2
-Selector.first = false
-Selector.list = --[[]]nil
-Selector.sets = --[[]]nil
-Selector.locks = --[[]]nil
-Selector.selections = --[[]]nil
-Selector.shape = "portrait"
-Selector.sprite = --[[]]nil
-Selector.quads = --[[]]nil
-Selector.icons_i = --[[]]nil
-Selector.icons_q = --[[]]nil
+Selector.DEFAULT_DELAY = 2
+Selector.SHAPE_PORTRAIT = 1
+Selector.SHAPE_PANORAMA = 2
--- Constructor
-function Selector:new (parent)
+function Selector:new (list, group, parent)
Selector.__super.new(self, parent)
- self.sprite, self.quads = parent:getSheet()
+ self.atlas, self.quads = parent:getSheet()
+ self.group = group
+ self.list = list
+ self.delay = Selector.DEFAULT_DELAY
+ self.shape = Selector.SHAPE_PORTRAIT
+ self.focused = false
+ self.lock = false
+ self.index = 1
end
--- Size of single block
+-- TODO: See `not/Element@getSize`.
function Selector:getSize ()
- return self.width, self.height
-end
-function Selector:setSize (width, height)
- self.width, self.height = width, height
- return self
-end
-
--- Spacing between two blocks
-function Selector:getMargin ()
- return self.margin
-end
-function Selector:setMargin (margin)
- self.margin = margin
- return self
+ if self.shape == Selector.SHAPE_PORTRAIT then
+ return 32, 32
+ end
+ if self.shape == Selector.SHAPE_PANORAMA then
+ return 80, 42
+ end
end
--- Initialize Selector with current settings.
-function Selector:init ()
- -- Make sure that there is list present
- if self.list == nil then
- self.list = {}
+--- Makes sure that n is in <1, total> range.
+local
+function limit (n, total)
+ if n > total then
+ return limit(n - total, total)
end
- -- Initialize global Selector
- if self.global then
- self.sets = {}
- self.locks = {false}
- self.selections = {1}
- -- Initialize Selector for Controllers
- else
- self.sets = Controller.getSets()
- self.locks = {}
- self.selections = {}
- for n=1,#self.sets do
- self.locks[n] = false
- self.selections[n] = 1
- end
+ if n < 1 then
+ return limit(n + total, total)
end
- return self
+ return n
end
--- Cycle through list on given number
-function Selector:next (n)
- local current = self.selections[n]
- self:setSelection(n, current + 1)
-end
-function Selector:previous (n)
- local current = self.selections[n]
- self:setSelection(n, current - 1)
+--- Chooses item with an index.
+-- @param index selected item's index
+-- @return old index
+function Selector:setIndex (index)
+ local old = self.index
+ self.index = limit(index, #self.list)
+ return old
end
--- Get number associated with a given set
-function Selector:checkNumber (set)
- if self.global then return 1 end -- For global Selector
- for n,check in pairs(self.sets) do
- if check == set then return n end
+function Selector:rollRandom (exclude)
+ local exclude = exclude or {}
+ local index = love.math.random(1, #self.list)
+ local elgible = true
+ for _,i in ipairs(exclude) do
+ if index == i then
+ elgible = false
+ break
+ end
+ end
+ if not elgible or not self:isUnique(self.list[index]) then
+ table.insert(exclude, index)
+ return self:rollRandom(exclude)
end
+ return index
end
--- Check if given number is locked
-function Selector:isLocked (n)
- local n = n or 1
- return self.locks[n]
+--- Returns selected item's value.
+-- @return item selected from the list
+function Selector:getSelected ()
+ return self.list[self.index]
end
--- Sets value of selection of given number. Returns old.
-function Selector:setSelection (n, new)
- -- Functception. It sounds like fun but it isn't.
- local function limit(new, total)
- if new > total then
- return limit(new - total, total)
- elseif new < 1 then
- return limit(total + new, total)
- else
- return new
- end
+--- Checks if selection is locked and returns item's value.
+-- @return item selected from the list if Selector is locked, nil otherwise
+function Selector:getLocked ()
+ if self.lock then
+ return self:getSelected()
end
- local n = n or 1
- local old = self.selections[n]
- self.selections[n] = limit(new, #self.list)
- return old
end
--- Get value of selection of given number
-function Selector:getSelection (n)
- local n = n or 1
- return self.selections[n]
+--- Checks if Selected value is unique in group's scope.
+-- @param index optional parameter to fill in place of currently selected item
+-- @return boolean answering question
+function Selector:isUnique (item)
+ local item = item or self:getSelected()
+ if self.group then
+ local locked = self.group:callEachBut(self, "getLocked")
+ for _,value in pairs(locked) do
+ if value == item then
+ return false
+ end
+ end
+ end
+ return true
end
--- Get value from list by selection
-function Selector:getListValue (i)
- return self.list[i]
+function Selector:getText ()
+ return tostring(self:getSelected())
end
--- Checks if selection of given number is unique within Selector scope.
-function Selector:isUnique (n)
- local selection = self:getSelection(n)
- for fn,v in pairs(self.selections) do
- if fn ~= n and self:isLocked(fn) and v == selection then
- return false
- end
- end
+function Selector:focus ()
+ self.focused = true
return true
end
--- Get list of selections, checks if not locked are allowed.
-function Selector:getFullSelection (allowed)
- local allowed = allowed
- if allowed == nil then allowed = false end
- local t = {}
- for n,v in pairs(self.selections) do
- local name = self:getListValue(self:getSelection(n))
- local locked = self:isLocked(n)
- if locked or allowed then
- local a = {name}
- if self.sets[n] then table.insert(a, self.sets[n]) end
- table.insert(t, a)
- end
- end
- return t
+function Selector:blur ()
+ self.focused = false
end
--- Rolls and returns random selection from list that is not locked.
-function Selector:rollRandom (avoids)
- -- Me: You should make it simpler.
- -- Inner me: Nah, it works. Leave it.
- -- Me: Ok, let's leave it as it is.
- local avoids = avoids or {}
- local total = #self.list
- local random = love.math.random(1, total)
- local eligible = true
- for _,avoid in ipairs(avoids) do
- if random == avoid then
- eligible = false
- break
- end
+-- TODO: Temporary function to determine quad to use. Will be obsolete when BoxElement will be done. See also `not/Element@getSize`.
+function Selector:getShapeString ()
+ if self.shape == Selector.SHAPE_PORTRAIT then
+ return "portrait"
end
- if not eligible or self:isLocked(random) then
- table.insert(avoids, random)
- return self:rollRandom(avoid)
- else
- return random
+ if self.shape == Selector.SHAPE_PANORAMA then
+ return "panorama"
end
end
--- Draw single block of Selector
-function Selector:drawBlock (n, x, y, scale)
- if self.quads == nil or self.sprite == nil then return end
- local x, y = x or 0, y or 0
- local name = self:getListValue(self:getSelection(n))
- local locked = self:isLocked(n)
- local sprite = self.sprite
- local quad = self.quads
- local icon = self.icons_i
- local iconq = self.icons_q[name]
- local w,h = self:getSize()
- local unique = self:isUnique(n)
- if unique then
- love.graphics.setColor(255, 255, 255, 255)
- else
- love.graphics.setColor(140, 140, 140, 255)
+function Selector:draw (scale)
+ local x, y = self:getPosition()
+ local w, h = self:getSize()
+
+ local boxType = "normal"
+ if self:getLocked() then
+ boxType = "active"
+ end
+
+ love.graphics.setColor(255, 255, 255, 255)
+ if not self:isUnique() then
+ love.graphics.setColor(120, 120, 120, 255)
end
- if not locked then
- love.graphics.draw(sprite, quad[self.shape].normal, x*scale, y*scale, 0, scale, scale)
- else
- love.graphics.draw(sprite, quad[self.shape].active, x*scale, y*scale, 0, scale, scale)
+ love.graphics.draw(self.atlas, self.quads[self:getShapeString()][boxType], x*scale, y*scale, 0, scale, scale)
+ -- TODO: That is one way to draw icon for selected value. Find better one. See: `config/menus/host`.
+ if self.icons_atlas and self.icons_quads then
+ love.graphics.draw(self.icons_atlas, self.icons_quads[self.index], (x+2)*scale, (y+3)*scale, 0, scale, scale)
end
- love.graphics.draw(icon, iconq, (x+2)*scale, (y+3)*scale, 0, scale, scale)
+
+ love.graphics.setColor(255, 255, 255, 255)
+
if self.focused then
local dy = (h-6)/2
- if not locked then
- love.graphics.draw(sprite, quad.arrow_l, (x+0-2-math.floor(self.delay))* scale, (y+dy)*scale, 0, scale, scale)
- love.graphics.draw(sprite, quad.arrow_r, (x+w-4+math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale)
- else
- love.graphics.draw(sprite, quad.arrow_r, (x+0-2-math.floor(self.delay))* scale, (y+dy)*scale, 0, scale, scale)
- love.graphics.draw(sprite, quad.arrow_l, (x+w-4+math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale)
+ local al, ar = self.quads.arrow_r, self.quads.arrow_l
+ if self.lock then
+ al, ar = ar, al
end
- end
- if (self:getSelection(n) ~= 1 or self.first) then
- love.graphics.setFont(Font)
- love.graphics.setColor(255, 255, 255, 255)
- love.graphics.printf(string.upper(name), (x-w)*scale, (y+h+1)*scale, w*3, "center", 0, scale, scale)
- end
-end
--- Menu callbacks
-function Selector:focus () -- Called when Element gains focus
- self.focused = true
- return true
-end
-function Selector:blur () -- Called when Element loses focus
- self.focused = false
-end
-
--- LÖVE2D callbacks
-function Selector:draw (scale)
- local x,y = self:getPosition()
- local margin = self:getMargin()
- local width = self:getSize()
- x = x - #self.selections*0.5*(margin+margin+width)
- for n=1,#self.selections do
- self:drawBlock(n, x+(margin+width)*(n-1)+margin*n, y, scale)
+ love.graphics.draw(self.atlas, ar, (x+0-2-math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale)
+ love.graphics.draw(self.atlas, al, (x+w-4+math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale)
end
+
+ love.graphics.setFont(Font)
+ love.graphics.printf(self:getText(), (x-w)*scale, (y+h+1)*scale, w*3, "center", 0, scale, scale)
end
+
function Selector:update (dt)
self.delay = self.delay + dt
- if self.delay > Selector.delay then -- Selector.delay is initial
- self.delay = self.delay - Selector.delay
+ if self.delay > Selector.DEFAULT_DELAY then
+ self.delay = self.delay - Selector.DEFAULT_DELAY
end
end
--- Controller callbacks
--- TODO: Add action to perform when key is pressed and selector is locked in e.g. to move into character selection from map selection.
function Selector:controlpressed (set, action, key)
if set and self.focused then
- local n = self:checkNumber(set)
- local locked = self:isLocked(n)
- if action == "left" and not locked then self:previous(n) end
- if action == "right" and not locked then self:next(n) end
- if action == "attack" then
- local name = self:getListValue(self:getSelection(n))
- if name == "random" then
- self:setSelection(n, self:rollRandom({1,2})) -- avoid empty naut
- self.locks[n] = true
- else
- -- If not empty or if first is allowed. Additionaly must be unique selection.
- if (self:getSelection(n) ~= 1 or self.first) and self:isUnique(n) then
- self.locks[n] = true
- end
- end
- end
- if action == "jump" then
- if locked then
- self.locks[n] = false
- end
+ local handler = self[action]
+ if handler then
+ handler(self)
end
end
end
+function Selector:left ()
+ if not self.lock then
+ self:setIndex(self.index - 1)
+ end
+end
+
+function Selector:right ()
+ if not self.lock then
+ self:setIndex(self.index + 1)
+ end
+end
+
+function Selector:attack ()
+ self.lock = true
+end
+
+-- Selector doesn't actually jump, haha, I tricked you!
+function Selector:jump ()
+ self.lock = false
+end
+
return Selector