poppy-client/lua/ui.lua

461 lines
12 KiB
Lua

ui = {}
ui.textureTree = nil
local layout = require("lua.layout")
local utils = require("shared.utils")
local fonts = require("shared.fonts")
ui.speedText = {
love.graphics.newText(fonts.normalFont, "0000"),
love.graphics.newText(fonts.normalFont, "0000"),
love.graphics.newText(fonts.normalFont, "0000"),
love.graphics.newText(fonts.normalFont, "0000")
}
ui.sidebarScale = 1
ui.sidebarWidth = 13 * 16
function ui.update_scale(p_scale)
scale = p_scale
end
function ui.updateSpeed(xspeed, yspeed, xpos, ypos)
ui.speedText = {
love.graphics.newText(fonts.normalFont, "XSpeed: " .. xspeed),
love.graphics.newText(fonts.normalFont, "YSpeed: " .. yspeed),
love.graphics.newText(fonts.normalFont, "X: " .. xpos),
love.graphics.newText(fonts.normalFont, "X: " .. ypos)
}
end
ui.helptext = [[[P] toggle fly
{A/D} Move
{Shift} Move faster
[Space] Jump
{A/S/DW} Move (flying)
[C] Clear canvas
[F] Fill foreground
[G] Fill background
{Mouse1} Draw
{Mouse2} Delete
{ctrl} Background draw
[PGUP/PGDWN] Zoom canvas
{Cursor keys} Move camera
]]
local menuVisible = false
local textEnabled = false
local textEntry = ""
function ui.keyreleased(key, _)
if key == "escape" then
menuVisible = not menuVisible
if menuVisible then
love.visible = function(visible)
if visible then
love.update = function(dt)
levelloop.networkSync(dt)
physics.update(dt)
camera.update(dt)
love.timer.sleep((1/60) -dt)
end
else
love.update = function(dt)
levelloop.networkSync(dt)
physics.update(dt)
end
end
end
ui.drawMenu(window.x, window.y)
else
love.visible = function(visible)
if visible then
love.update = levelloop.normalVisible
else
love.update = levelloop.reducedVisible
end
end
ui.draw(window.x, window.y)
end
love.visible(true)
return
end
if key == "return" and not love.keyboard.isDown("lalt") then
textEnabled = true
love.keyboard.setTextInput(true)
ui.draw(window.x, window.y)
end
if textEnabled then
love.visible = function(visible)
if visible then
love.update = function(dt)
levelloop.networkSync(dt)
drawing.input(dt)
physics.update(dt)
camera.update(dt)
end
else
love.update = function(dt)
levelloop.networkSync(dt)
physics.update(dt)
end
end
end
love.visible(true)
love.keyreleased = function(key, _)
if key == "return" and not love.keyboard.isDown("lalt") then
textEnabled = false
if textEntry ~= "" then
levelloop.remoteCall("chatMessage", textEntry)
textEntry = ""
end
ui.draw(window.x, window.y)
love.keyboard.setTextInput(false)
love.keyreleased = levelloop.keyreleased
love.keypressed = levelloop.keypressed
love.update = levelloop.normalVisible
elseif key == "backspace" then
textEntry = string.sub(textEntry, 0, #textEntry -1)
ui.draw(window.x, window.y)
end
end
love.keypressed = function(key, _) return end
else
love.keyreleased = levelloop.keyreleased
love.keypressed = levelloop.keypressed
end
end
function love.textinput(text)
textEntry = textEntry .. text
ui.draw(window.x, window.y)
end
function ui.chatEntry()
local passedEntry = ""
if textEntry == "" then passedEntry = "Start typing your message." else passedEntry = textEntry end
local chatEntry =
{name = "copySize",
{name = "rect",
fill = "fill",
color = { r = .1, g = .1, b = .1, .7 }
},
{name = "frame",
{name = "label",
text = passedEntry
}
}
}
return chatEntry
end
chatentries = {name = "vertical", {name = "spacer", width = 0}}
function ui.chatlog()
return chatentries
end
function ui.addChatEntry(user, message)
if #chatentries > 10 then
table.remove(chatentries, 1)
end
local chatText
if user ~= "" then
chatText = user .. ": " .. message
else
chatText = message
end
local entry = {name = "rotate",
rotation = 0, -- OKAY DIEGO >:(
{name = "copySize",
{name = "rect",
fill = "fill",
color = { r = .1, g = .1, b = .1, a = .6 }
},
{name = "vertical",
{name = "label",
text = chatText,
font = fonts.smallFont
},
{name = "spacer",
height = 2
}
}
}
}
table.insert(chatentries, entry)
ui.draw(window.x, window.y)
end
function ui.loadTextures(directory, container)
if not container then container = {} end
local entries = love.filesystem.getDirectoryItems(directory)
if #entries == 0 then return container end
for i, file in pairs(entries) do
local path = directory .."/".. file
local entry = love.filesystem.getInfo(path)
if entry.type == "directory" and file ~= ".git" then
container[file] = {}
container[file] = ui.loadTextures(path, container[file])
elseif entry.type == "file" or entry.type == "symlink" then
local status, imageData = pcall(love.image.newImageData, path);
if status then
local hash = love.data.hash("sha512", imageData:getString())
levelloop.textures[hash] = {data = imageData}
container[file] = hash
end
end
end
return container
end
function textureEntry(hash)
local texture = levelloop.textures[hash]
assert(texture, "No texture found for textureentry?")
assert(texture.data, "No imagedata found for textureentry?")
if not texture.image then
texture.image = love.graphics.newImage(texture.data)
end
local width = texture.image:getWidth()
local height = texture.image:getHeight()
if drawing and drawing.cursorHash and hash == drawing.cursorHash then
return {name = "overlayRect",
fill = "line",
{name = "drawHash",
hash = hash,
scale = ui.sidebarScale
}
}
else
return {name = "cursorSelect", uiSelect = "GameUI",
identifier = hash,
kind = "picker",
{name = "drawHash",
hash = hash,
scale = ui.sidebarScale
}
}
end
end
function textureRun(entryTable, width)
local textures = levelloop.textures
local entries = {name = "naiveGrid", width = width - 20}
local entryTableSorted = {}
-- Sort the entries alphapetically (or well, probably more... "byte compared") :)
-- This implies that in <author>/<packname>/<fileName> the fileName controls where
-- the texture lands in the block drawer, smaller lands further left.
for iter, entry in pairs(entryTable) do
table.insert(entryTableSorted, {name = iter, entry = entry})
end
table.sort(entryTableSorted, function(k1, k2) return k1.name < k2.name end)
for iter, entry in pairs(entryTableSorted) do
if not textures[entry.entry].image then
textures[entry.entry].image = love.graphics.newImage(textures[entry.entry].data)
end
table.insert(entries, textureEntry(entry.entry))
end
return entries
end
function ui.blockDrawer(textureTree, w, h, container)
if not textureTree then return {name = "label", text = "Loading textures..."} end
local pointSize = 8
if ui.sidebarScale == 2 then pointSize = 16 end
if not container then container = {name="vertical",
{name = "colorPicker", kind = "colorpicker",
granularity = 0.25, pointSize = pointSize},
{name = "spacer", height = 5 * ui.sidebarScale},
{name = "bwColorPicker", kind = "bwColorPicker",
pointSize = pointSize}}
end
local textureTreeSorted = {}
for author, tree in pairs(textureTree) do
table.insert(textureTreeSorted, {author = author, tree = tree})
end
table.sort(textureTreeSorted, function(k1, k2) return k1.author < k2.author end)
for author, tree in pairs(textureTreeSorted) do
for pack, subTree in pairs(tree.tree) do
container.name = "vertical"
table.insert(container, {name = "label", text = pack})
table.insert(container,
{name = "color",
color = drawing.color or {1, 1, 1},
--[[ HACK! remove the 1, 1, 1.
drawing.color should be set!
]]--
textureRun(subTree, w)
})
end
end
return container
end
function ui.menuDrawer(w, h)
return {name = "horizontal",
{name = "vertical",
{name = "button",
identifier = "save",
uiSelect = "Menu",
buttonColor = "greenTranslucent",
text = "Save world"
},
{name = "spacer",
height = 10,
},
{name = "button",
identifier = "disconnect",
uiSelect = "Menu",
buttonColor = "pinkTranslucent",
text = "Disconnect"
},
{name = "spacer",
height = 25,
},
{name = "button",
identifier = "sideBarScaleTwo",
uiSelect = "Menu",
buttonColor = "grayTranslucent",
text = "Ui scale x2"
},
{name = "spacer",
height = 4,
},
{name = "button",
identifier = "sideBarScaleOne",
uiSelect = "Menu",
buttonColor = "grayTranslucent",
text = "Ui scale x1"
},
},
{name = "spacer",
width = 80,
},
{name = "label",
text = ui.helptext,
font = fonts.normallFont
}
}
end
function ui.draw(w, h)
window.x, window.y = w, h
love.graphics.setCanvas(ui.buffer)
layout.uiState.GameUI = {}
love.graphics.clear( )
local blockDrawer = ui.blockDrawer(ui.textureTree, w, h)
blockMaxX, blockMaxY = layout.handle(blockDrawer, 0, 0, true)
local blockDrawerAdjusted = ui.blockDrawer(ui.textureTree, blockMaxX, blockMaxY)
layout.handle(blockDrawerAdjusted, window.x - blockMaxX, 0)
layout.handle(ui.chatlog(), 25, 90)
love.graphics.setCanvas()
end
function ui.drawMenu(w, h)
window.x, window.y = w, h
layout.uiState.Menu = {}
love.graphics.setCanvas(ui.buffer)
love.graphics.clear()
local menuDrawer = ui.menuDrawer(w, h)
menux, menuy = layout.handle(menuDrawer, 0, 0, true)
layout.handle(menuDrawer, (window.x - menux) /2, (window.y - menuy)/2)
love.graphics.setCanvas()
end
function ui.mousepressed(mousex, mousey)
local textures = levelloop.textures
if menuVisible then
for i, v in ipairs(layout.uiState.Menu) do
if mousex >= v.x and mousex <= v.x2 and --hit testing
mousey >= v.y and mousey <= v.y2 then
if v.kind == "button" then
if v.identifier == "save" then
levelloop.networkSend("saveWorld")
ui.keyreleased("escape")
elseif v.identifier == "disconnect" then
levelloop.remoteCall("playerLeave")
menu.init()
elseif v.identifier == "sideBarScaleTwo" then
ui.sidebarScale = 2
ui.draw(window.x, window.y)
ui.keyreleased("escape")
elseif v.identifier == "sideBarScaleOne" then
ui.sidebarScale = 1
ui.draw(window.x, window.y)
ui.keyreleased("escape")
end
end
return -- Return after the first hit...
end
end
else
for i, v in ipairs(layout.uiState.GameUI) do
if mousex >= v.x and mousex <= v.x2 and
mousey >= v.y and mousey <= v.y2 then
if v.kind == "picker" then
assert(v.identifier, "No identifier in picker!")
drawing.cursorHash = v.identifier
drawing.cursor = textures[v.identifier]
assert(drawing.cursor, "No cursor texture found!")
ui.draw(window.x, window.y)
return
elseif v.kind == "tab" then
selectedTab = v.identifier
ui.draw(window.x, window.y)
return
elseif v.kind == "colorpicker" then
print("Picker hit :D")
local scale = ui.sidebarScale / granularity
local red = math.floor((mousey - v.y) / v.pointSize) / scale
local green = math.floor((mousex - v.x) / v.pointSize / (scale + 1)) / scale
local blue = (math.floor((mousex - v.x) / v.pointSize) % (scale + 1)) / scale
print("I think the color is " .. red .. ":" .. green .. ":" .. blue)
drawing.color = {red, green, blue, 1}
ui.draw(window.x, window.y)
return
elseif v.kind == "bwColorPicker" then
local scale = 1.0 / granularity
local saturation = math.floor((mousex - v.x) / v.pointSize) / scale
drawing.color = {saturation, saturation, saturation, 1}
ui.draw(window.x, window.y)
return
end
return
end
end
end
end
ui.init = function()
love.keyboard.setTextInput( false )
local w,h = love.window.getMode()
ui.textureTree = ui.loadTextures("textures/blocks")
ui.draw(w, h)
ui.resize = function()
local w,h = love.window.getMode()
ui.buffer = love.graphics.newCanvas(w, h)
love.graphics.setCanvas(ui.buffer)
love.graphics.clear()
ui.draw(w, h)
love.graphics.setCanvas()
end
end
local w, h = love.window.getMode()
ui.buffer = love.graphics.newCanvas(w, h)
ui.space = 300