diff options
Diffstat (limited to 'not/Selector.lua')
-rw-r--r-- | not/Selector.lua | 365 |
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 |