123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- local love = require("compat")
- local START_X, START_Y, START_ALPHA = 0, 30, 0
- local START_TIME = 0.3
- local PATH = (...):match("(.-)[^%.^/]+$")
- local class = require( PATH .. "middleclass" )
- local utility = require( PATH .. "utility" )
- local TextBlock = require( PATH .. "textBlock" )
- local InputBlock = require( PATH .. "inputBlock" )
- local col = require(PATH .. "colors")
- local COLORS, COLORS_INACTIVE = col[1], col[2]
- local Panel = class("PunchUiPanel")
- function Panel:initialize( name, x, y, w, h, font, padding, corners )
- self.name = name or ""
- self.x = x or 0
- self.y = y or 0
- --width and height:
- self.w = w
- self.h = h
- self.font = font
- self.padding = padding or 10
- self.texts = {}
- self.events = {}
- self.inputs = {}
- self.lines = {}
- self.activeInput = nil
- self.corners = corners or {3,3,3,3}
- self:calcBorder()
- self.isList = false
- self.startX = START_X
- self.startY = START_Y
- self.alpha = START_ALPHA
- self.startTime = 0
- self.animationTime = START_TIME
- end
- function Panel:calcBorder()
- self.border = {}
- -- top left:
- if self.corners[1] > 0 then
- table.insert( self.border, 0 )
- table.insert( self.border, 0 + self.corners[1] )
- table.insert( self.border, 0 + self.corners[1] )
- table.insert( self.border, 0 )
- else
- table.insert( self.border, 0 )
- table.insert( self.border, 0 )
- end
- -- top right
- if self.corners[2] > 0 then
- table.insert( self.border, self.w - self.corners[2] )
- table.insert( self.border, 0 )
- table.insert( self.border, self.w )
- table.insert( self.border, 0 + self.corners[2] )
- else
- table.insert( self.border, self.w )
- table.insert( self.border, 0 )
- end
- -- bottom right
- if self.corners[3] > 0 then
- table.insert( self.border, self.w )
- table.insert( self.border, self.h - self.corners[3] )
- table.insert( self.border, self.w - self.corners[3] )
- table.insert( self.border, self.h )
- else
- table.insert( self.border, self.w )
- table.insert( self.border, self.h )
- end
- -- bottom left:
- if self.corners[4] > 0 then
- table.insert( self.border, self.corners[4] )
- table.insert( self.border, self.h )
- table.insert( self.border, 0 )
- table.insert( self.border, self.h - self.corners[4] )
- else
- table.insert( self.border, 0 )
- table.insert( self.border, self.h )
- end
- end
- function Panel:addText( name, x, y, width, height, txt )
- self:removeText( name )
- -- if the width is not given, make sure text does not
- -- move outside of panel:
- x = x + self.padding
- y = y + self.padding
- local maxWidth = self.w - x - self.padding
-
- width = math.min( width or math.huge, maxWidth )
- local t = TextBlock:new( name, x, y, width, height, txt, self.font, true )
- table.insert( self.texts, t )
- return t, t.trueWidth or t.width, t.height
- end
- function Panel:removeText( name )
- for k, t in ipairs(self.texts) do
- if t.name == name then
- table.remove(self.texts, k)
- end
- end
- end
- function Panel:addHeader( name, x, y, txt )
- return self:addText( name, x, y, math.huge, 1, COLORS.HEADER.ID ..txt )
- end
- function Panel:update( dt )
- if self.startTime < self.animationTime then
- self.startTime = self.startTime + dt
- -- let amount go towards zero:
- local t = math.max(self.startTime/self.animationTime, 0)
- --local amount = math.pow( linear, 6)
- local amount = -2.5*t^2+3.5*t
- self.startX = START_X*(1-amount)
- self.startY = START_Y*(1-amount)
- self.alpha = t
- if self.startTime >= self.animationTime then
- self.startX = 0
- self.startY = 0
- self.alpha = 1
- end
- end
- end
- function Panel:draw( inactive )
- local COL = COLORS
- if inactive then
- COL = COLORS_INACTIVE
- end
- love.graphics.push()
- love.graphics.translate( self.x + self.startX, self.y + self.startY )
- love.graphics.setColor( COL.PANEL_BG[1], COL.PANEL_BG[2], COL.PANEL_BG[3], COL.PANEL_BG[4]*self.alpha )
- love.graphics.polygon( "fill", self.border )
- love.graphics.setColor( COL.BORDER[1], COL.BORDER[2], COL.BORDER[3], COL.BORDER[4]*self.alpha )
- love.graphics.polygon( "line", self.border )
- love.graphics.setColor( COL.BORDER[1], COL.BORDER[2], COL.BORDER[3], COL.BORDER[4]*self.alpha*0.5 )
- for k, l in ipairs( self.lines ) do
- love.graphics.line( l.x1, l.y1, l.x2, l.y2 )
- end
- for k, e in ipairs( self.events ) do
- if e.highlight then
- love.graphics.setColor( COL.HLIGHT[1], COL.HLIGHT[2], COL.HLIGHT[3], COL.HLIGHT[4]*self.alpha )
- love.graphics.rectangle( "fill", e.x, e.y,
- e.w, e.h )
- end
- end
- for k, v in ipairs( self.texts ) do
- v:draw( inactive )
- end
- for k, v in ipairs( self.inputs ) do
- v:draw( inactive )
- end
- love.graphics.pop()
- end
- function Panel:addFunction( name, x, y, txt, key, event, tooltip )
- local fullTxt = COLORS.FUNCTION.ID .. string.upper(key) .. " "
- fullTxt = fullTxt .. COLORS.PLAIN_TEXT.ID .. txt
- local t, w, h = self:addText( name, x, y, math.huge, 1, fullTxt )
- local newEvent = {
- name = name,
- key = key,
- event = event,
- tooltip = tooltip,
- x = x + self.padding - 1,
- y = y + self.padding - 1,
- w = w + 2,
- h = h + 2,
- }
- table.insert( self.events, newEvent )
- return newEvent, w, h
- end
- function Panel:removeFunction( name )
- for k, ev in pairs( self.events ) do
- if ev.name == name then
- table.remove( self.events, k )
- break
- end
- end
- -- Also remove the text which describes this function:
- self:removeText( name )
- end
- function Panel:addInput( name, x, y, width, height, key, returnEvent, password, content, maxLetters )
- -- add a function which will set the new input box to active:
- -- add the key infront of the input box:
- local event = function()
- self.activeInput = self:inputByName( name )
- self.activeInput:setActive( true )
- end
- local ev = self:addFunction( name, x, y, "", key, event )
- x = x + self.padding
- y = y + self.padding
- local maxWidth = self.w - x - self.padding
- local keyWidth = self.font:getWidth( key .. " " )
-
- width = math.min( width or math.huge, maxWidth )
- height = height or self.font:getHeight()
- ev.w = width
- local i = InputBlock:new( name, x + keyWidth, y, width-keyWidth, height, self.font, returnEvent, password, maxLetters )
- if content and type(content) == "string" then
- i:setContent( content )
- end
- table.insert(self.inputs, i)
- return i
- end
- function Panel:inputByName( name )
- for k, i in ipairs( self.inputs ) do
- if i.name == name then
- return i
- end
- end
- end
- function Panel:disableInput()
- if self.activeInput then
- self.activeInput:setActive(false)
- self.activeInput = nil
- end
- end
- function Panel:keypressed( key, unicode )
- if not self.activeInput then
- for k, f in pairs( self.events ) do
- if f.key == key then
- if love.keyboard.isDown("lshift") then
- if f.tooltip then
- f.tooltip()
- end
- elseif f.event then
- f.event( f )
- end
- return true
- end
- end
- else
- local re = self.activeInput:keypressed( key, unicode )
- -- if "esc" was pressed (or similar), stop:
- if re == "stop" then
- --self.activeInput:setActive(false)
- --self.activeInput = nil
- self:disableInput()
- elseif re == "forward" then -- tab pressed: go to next input
- self.activeInput:setActive(false)
- local current = self.activeInput
- self.activeInput = nil
- local found = false
- for k, inp in ipairs(self.inputs) do
- if found then
- self.activeInput = inp
- self.activeInput:setActive(true)
- break
- end
- if inp == current then
- found = true
- end
- end
- elseif re == "backward" then -- tab pressed: go to next input
- self.activeInput:setActive(false)
- local current = self.activeInput
- self.activeInput = nil
- local found = false
- local inp
- for k = #self.inputs, 1, -1 do
- inp = self.inputs[k]
- if found then
- self.activeInput = inp
- self.activeInput:setActive(true)
- break
- end
- if inp == current then
- found = true
- end
- end
- end
- end
- end
- function Panel:textinput( key )
- if self.activeInput then
- -- type the key into the current input box:
- self.activeInput:textinput( key, true )
- end
- end
- function Panel:addLine( x1, y1, x2, y2 )
- self.lines[#self.lines+1] = {x1=x1, y1=y1, x2=x2, y2=y2 }
- end
- --------------------------------------
- -- Handle lists:
- function Panel:putListItem( item, i, curY )
- local ev, w, h
- local ev = function()
- if item.event then
- item.event()
- end
- end
- local tip = item.tooltip or "Choose option " .. i .. "."
- local tooltipEv = function()
- self:newTooltip( tip )
- end
- local key = item.key or tostring(i)
- ev, w, h = self:addFunction( key, 5, curY, item.txt, key, ev, tooltipEv )
- curY = curY + self.list.lineHeight
- return curY, w, ev
- end
- function Panel:buildList()
- local curY = self.padding
- local maxWidth = self.list.minWidth or 0
- self.events = {}
- self.texts = {}
- local itemsAdded = 1
- -- Display a scroll up button?
- if self.list.startItem > 1 then
- local item = {
- event = function()
- self:scrollList( self.list.startItem - 1 )
- end,
- tooltip = "Scroll up",
- key = "u",
- txt = "Up",
- }
- curY = self:putListItem( item, nil, curY )
- end
- local count = 0
- local moreItemsAvailable = false
- for k = self.list.startItem, #self.list.items do
- v = self.list.items[k]
- count = count + 1
- if curY + self.list.lineHeight*2 > self.h then
- moreItemsAvailable = true
- break
- end
- curY, w = self:putListItem( v, count, curY )
- maxWidth = math.max( maxWidth, w )
- itemsAdded = itemsAdded + 1
- end
- -- Display a scroll down button?
- if self.list.startItem < #self.list.items then
- local item = {
- event = function()
- self:scrollList( self.list.startItem + 1 )
- end,
- tooltip = "Scroll down",
- key = "d",
- txt = "Down",
- }
- curY = self:putListItem( item, nil, self.h - self.list.lineHeight -self.padding )
- end
- self.w = 12 + maxWidth
- end
- function Panel:toList( list, minWidth, listLength )
- self.list = {
- items = list,
- displayLength = math.max(listLength, 3),
- minWidth = minWidth,
- startItem = 1,
- lineHeight = self.font:getHeight() + 8
- }
- self.h = self.list.lineHeight*listLength + 2*self.padding
- self:buildList()
- --[[curY = 0
- for k, v in ipairs( list ) do
- curY = curY + self.font:getHeight() + 8
- if k < #list then
- self:addLine( 4, curY , maxWidth + 4, curY )
- end
- end]]
- self:calcBorder()
- self.isList = true
- end
- function Panel:scrollList( num )
- if self.isList then
- local prev = self.list.startItem
- self.list.startItem = math.min( math.max( num, 1 ), #self.list.items )
- if prev ~= self.list.startItem then
- self:buildList()
- end
- end
- end
- function Panel:addListItem( item )
- if not self.isList then
- return
- end
- table.insert( self.list.items, item )
- self:buildList()
- --[[if #self.events > 0 then
- self:addLine( 4, self.h , self.w - 8, self.h )
- end
- local curY = self.h
- local ev = function()
- if item.event then
- item.event()
- end
- end
- local tip = item.tooltip or "Choose option " .. #self.events + 1 .. "."
- local tooltipEv = function()
- self:newTooltip( tip )
- end
- local key = item.key or tostring( #self.events + 1 )
- ev, w, h = self:addFunction( key, 5, curY, item.txt, key, ev, tooltipEv )
- maxWidth = math.max( self.w - 12, w )
- curY = curY + self.font:getHeight() + 8
- self.h = curY
- self.w = maxWidth + 12
- self:calcBorder()]]
- end
- ------------------------------------------------------
- -- Handle mouse input:
- function Panel:mousemoved( x, y )
- for k, e in pairs( self.events ) do
- if utility.isInside( x, y, e.x + self.x, e.y + self.y, e.w, e.h ) then
- e.highlight = true
- return e
- end
- end
- end
- function Panel:mousepressed( x, y, button )
- for k, e in pairs( self.events ) do
- if utility.isInside( x, y, e.x + self.x, e.y + self.y, e.w, e.h ) then
- if e.event then
- e.event( e )
- end
- return e
- end
- end
- end
- return Panel
|