local cwd = (...):gsub('%.grid$', '') .. "." local Menu = require(cwd .. "parent") local GridBox = Menu:extend() local menuutils = require(cwd .. "widgets.utils") function GridBox:new(menusystem, name, x, y, w, h, colNumber, lineNumber) self.view = {} self.view.slotNumber = colNumber * lineNumber self.view.colNumber = colNumber self.view.lineNumber = lineNumber self.view.firstSlot = 1 GridBox.super.new(self, menusystem, name, x, y, w, h) self.h = lineNumber * self.widget.h -- On fait en sorte que la hauteur self.w = colNumber * self.widget.w -- et la largeur -- soit un multiple du nombre de slot et de leur dimensions self.cursor = {} self.cursor.x = 0 self.cursor.y = 0 -- La gridbox possède la particularité de pouvoir fusioner des slots, on fait -- donc une liste de slots disponibles, qui serviront par la suite. self.slots = {} end function GridBox:addSlot(widgetID, x, y, w, h) local slot = {} slot.x = x slot.y = y slot.w = w slot.h = h slot.widgetID = widgetID table.insert(self.slots, slot) end function GridBox:updateWidgetSize() self.widget.h = math.floor( self.h / self.view.lineNumber ) self.widget.w = math.floor( self.w / self.view.colNumber ) end function GridBox:getWidgetSize(id) local slot = self:getWidgetSlot(id) if slot == 0 then return 1, 1 else return self.widget.w * self.slots[slot].w, self.widget.h * self.slots[slot].h end end function GridBox:getSlotHitbox(slot) local x, y, w, h x = self.slots[slot].x * self.widget.w y = self.slots[slot].y * self.widget.h w = self.slots[slot].w * self.widget.w h = self.slots[slot].h * self.widget.h return x, y, w, h end function GridBox:getSlotCenter(slot) local x, y, w, h = self:getSlotHitbox(slot) return x + (w/2), y + (h/2) end function GridBox:getWidgetID(slot) local widgetID if self.slots[slot] ~= nil then widgetID = self.slots[slot].widgetID else widgetID = 0 end return widgetID end function GridBox:haveWidget(slot) local id = self:getWidgetID(slot) return self.widget.list[id] ~= nil end function GridBox:getWidgetSlot(widgetID) local slot = 0 for i,v in ipairs(self.slots) do if (self.slots[i].widgetID == widgetID) then slot = i end end return slot end function GridBox:getWidgetAtPoint(x, y) local x = x or 0 local y = y or 0 local widgetID = nil for i,v in ipairs(self.slots) do local xx, yy, ww, hh = self:getSlotHitbox(i) if (x >= xx) and (y >= yy) and (x < xx + ww) and (y < yy + hh) then widgetID = v.widgetID end end return widgetID end function GridBox:update(dt) self.view.firstSlot = 1 end function GridBox:keyreleased(key, code) slotID = self:getWidgetSlot(self.widget.selected) local col, line = self.cursor.x, self.cursor.y if key == 'left' then self:moveCol(-1) end if key == 'right' then self:moveCol(1) end if key == 'up' then self:moveLine(-1) end if key == 'down' then self:moveLine(1) end if key == "A" and self.widget.selected <= #self.widget.list then self.widget.list[self.widget.selected]:action() end end function GridBox:moveCol(direction) local orig_x, orig_y = self:getSlotCenter(self.widget.selected) local distance = self.w -- on met directement à la distance max possible le système local nearastWidget = 0 for i,v in ipairs(self.slots) do local xx, yy = self:getSlotCenter(i) -- On commence par vérifier si le slot est bien positionné par rapport au -- widget de base if utils.math.sign(xx - orig_x) == direction then if utils.math.pointDistance(orig_x, orig_y, xx, yy) < distance then distance = utils.math.pointDistance(orig_x, orig_y, xx, yy) nearestWidget = v.widgetID end end end if nearestWidget ~= 0 then self.widget.selected = nearestWidget end end function GridBox:moveLine(direction) local orig_x, orig_y = self:getSlotCenter(self.widget.selected) local distance = self.h -- on met directement à la distance max possible le système local nearastWidget = 0 for i,v in ipairs(self.slots) do local xx, yy = self:getSlotCenter(i) -- On commence par vérifier si le slot est bien positionné par rapport au -- widget de base if utils.math.sign(yy - orig_y) == direction then if utils.math.pointDistance(orig_x, orig_y, xx, yy) < distance then distance = utils.math.pointDistance(orig_x, orig_y, xx, yy) nearestWidget = v.widgetID end end end if nearestWidget ~= 0 then self.widget.selected = nearestWidget end end function GridBox:mousemoved(x, y) local widgetID = self:getWidgetAtPoint(x, y) if widgetID ~= nil then self.widget.selected = widgetID self:getFocus() end if self.widget.selected < 1 then self.widget.selected = 1 end if self.widget.selected > #self.widget.list then self.widget.selected = #self.widget.list end end function GridBox:mousepressed(x, y, button, isTouch) local widgetID = self:getWidgetAtPoint(x, y) if widgetID ~= nil then self.widget.selected = widgetID self:getFocus() if #self.widget.list > 0 and self.widget.selected > 1 and self.widget.selected <= #self.widget.list then self.widget.list[self.widget.selected]:action() end end end function GridBox:draw() for i,v in ipairs(self.slots) do if self:haveWidget(i) then local widgetx = self.x + (v.x * self.widget.w) local widgety = self.y + (v.y * self.widget.h) if self.widget.selected == v.widgetID and self:haveFocus() == true then self.widget.list[v.widgetID]:drawSelected(widgetx, widgety) else self.widget.list[v.widgetID]:draw(widgetx, widgety) end end end end function GridBox:drawCursor() self:updateView() if (self.widget.selected >= 1 and self.widget.selected <= #self.widget.list) then local slot = self:getWidgetSlot(self.widget.selected) local w, h = self:getWidgetSize(slot) local x = self.slots[slot].x * self.widget.w local y = self.slots[slot].y * self.widget.h menuutils.drawCursor(self.x + x, self.y + y, w, h) end end return GridBox