dcearth/ui/menu/cities.lua

290 lines
7.4 KiB
Lua

local love = assert( love )
local lg = assert( love ).graphics
local utf8 = require 'utf8'
local button = require 'ui.button'
local textinput = require 'ui.textinput'
local modal = require 'ui.modal'
local map = require 'map.map'
local camera = require 'ui.camera'
local t = {}
local city
local function keypressed( key, code, isRepeat )
if code == 'escape' then return modal.current:stop() end
if modal.previous then return modal.previous.keypressed( key, code, isRepeat ) end
end
--select modal: as normal, but clicking a city will proceed to the previously selected mode,
--and clicking escape will clear the previously selected mode
local selectModal = modal.new{}
local textModal = modal.new{}
local numberModal = modal.new{}
local editModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed, }
local moveModal = modal.new{ mousepressed = button.mousepressed, keypressed = keypressed, mousemoved = button.selectIn }
local deleteModal = modal.new{ keypressed = keypressed }
local currentMode
button.new{ name = "NEW CITY",
group = t,
icon = lg.newImage("icons/city-new.png"),
x = 615,
y = 0,
callback = function()
city = map.cities.newCity()
city:add()
return editModal:start()
end
}
moveModal.button = button.new{ name = "MOVE CITY",
group = t,
icon = lg.newImage("icons/city-move.png"),
x = 615,
y = button.h + 4,
callback = function( self )
self.lit = true
selectModal.mode = moveModal
return selectModal:start()
end,
}
editModal.button = button.new{ name = "EDIT CITY",
group = t,
x = 615,
y = (button.h + 4) * 2,
callback = function( self )
self.lit = true
selectModal.mode = editModal
return selectModal:start()
end,
}
deleteModal.button = button.new{ name = "DELETE CITY",
group = t,
icon = lg.newImage("icons/city-delete.png"),
x = 615,
y = (button.h + 4) * 3,
callback = function( self )
self.lit = true
return deleteModal:start()
end,
}
--editButtons
local function editText( self )
print( "editing: ", self.field, city.name )
self.lit = true
return textModal:start( self.field )
end
local function editNumber( self )
print( "editing: ", self.field, city.name )
self.lit = true
return numberModal:start( self.field )
end
local editButtons = {
save = button.new{
icon = lg.newImage( "icons/check.png" ),
callback = function() return editModal:stop() end,},
name = button.new{ callback = editText },
country = button.new{ callback = editText },
x = button.new{ callback = editNumber },
y = button.new{ callback = editNumber },
capital = button.new{ callback = function( self )
if city then
self.name = tostring( not( city.capital ) )
return city:toggleCapital()
end
end },
}
do
local i = 0
for _, key in ipairs{ "save", "name", "country", "x", "y", "capital" } do
local b = assert( editButtons[ key ] )
b.align = "right"
b.field = key
b.name = tostring( key ) --bools must be cast to string before getting passed to printf
b.group = editModal
b.x = lg.getWidth() / 2 - button.w / 2
b.y = (button.h + 4) * i
i = i + 1
end
end
function editModal:start()
modal.start( self )
button.displayGroup( self, false, true )
for k, b in pairs( editButtons ) do
b.name = tostring( city[k] or b.name )
end
if city.capital == false then editButtons.capital.name = "false" end
end
function editModal:stop()
return modal.stop( self )
end
function editModal.draw()
lg.setColor( 1, 1, 1, 0.5 )
return button:draw()
end
function editModal.resize( w, h )
local i = 0
local high = h / 6
for key, b in pairs( editButtons ) do
b.x = w / 2 - button.w / 2
b.y = ( high + 4 ) * i
b.h = high
i = i + 1
end
end
function moveModal.update( dt )
local x, y = love.mouse.getPosition()
if y > t.menuHeight and love.mouse.isDown( 1 ) then
local wx, wy = camera.GetWorldCoordinate( x, y )
city:moveTo( wx, wy )
end
end
function moveModal.mousemoved( x, y, dx, dy, istouch )
return button.selectIn( x, y )
end
function moveModal.mousepressed( x, y, mouseButton, istouch, presses )
if y < t.menuHeight then
moveModal:stop()
return button.mousepressed( x, y, mouseButton, istouch, presses )
end
if map.selected and mouseButton == 2 then
city = map.selected
end
end
function deleteModal.mousepressed( x, y, mouseButton, istouch, presses )
if map.selected then
map.selected:delete()
end
if y < t.menuHeight then
deleteModal.button.lit = false
deleteModal:stop()
return button.mousepressed( x, y, mouseButton, istouch, presses )
end
end
function numberModal:start( field )
self.field = field
return modal.start( self )
end
function numberModal.keypressed( key, code, isrepeat )
if code == "backspace" then
local text = tostring( city[numberModal.field] )
-- get the byte offset to the last UTF-8 character in the string.
local byteoffset = utf8.offset(text, -1)
print( "textmodal: backspace", byteoffset )
if byteoffset then
-- remove the last UTF-8 character.
-- string.sub operates on bytes rather than UTF-8 characters, so we couldn't do string.sub(text, 1, -2).
local newstr = text:sub( 1, byteoffset - 1)
if newstr == "" then newstr = 0 end
city[numberModal.field] = tonumber( newstr ) or city[numberModal.field]
editButtons[numberModal.field].name = city[numberModal.field]
end
end
if code == "escape" or code == "return" then
return numberModal:stop()
end
end
function numberModal.textinput( char )
local str = tostring( city[ numberModal.field ] )
local plus = str..char
print( "text input: ", char )
if tonumber( plus ) then
city[ numberModal.field ] = plus
editButtons[ numberModal.field ].name = plus
end
end
function textModal.textinput( char )
print( "text input: ", char )
city[textModal.field] = city[textModal.field] .. char
editButtons[textModal.field].name = city[textModal.field]
end
function textModal.mousepressed()
end
function textModal:stop()
self.field = nil
return modal.stop( self )
end
function textModal:start( field )
self.field = field
return modal.start( self )
end
function textModal.keypressed( key, code, isRepeat )
if code == "backspace" then
local text = city[textModal.field]
-- get the byte offset to the last UTF-8 character in the string.
local byteoffset = utf8.offset(text, -1)
print( "textmodal: backspace", byteoffset )
if byteoffset then
-- remove the last UTF-8 character.
-- string.sub operates on bytes rather than UTF-8 characters, so we couldn't do string.sub(text, 1, -2).
city[textModal.field] = text:sub( 1, byteoffset - 1)
editButtons[textModal.field].name = city[textModal.field]
end
end
if code == "escape" or code == "return" then
return textModal:stop()
end
end
function selectModal.keypressed( key, code, isRepeat )
if code == 'escape' then return selectModal:stop() end
if modal.previous then return modal.previous.keypressed( key, code, isRepeat ) end
end
function selectModal:stop()
local mode = selectModal.mode
if mode then
mode.button.lit = false
end
return modal.stop( self )
end
function selectModal.mousepressed( x, y, mouseButton, istouch, presses )
if y < t.menuHeight then
selectModal:stop()
return button.mousepressed( x, y, mouseButton, istouch, presses )
end
if map.selected then
city = map.selected
return selectModal.mode:start()
end
end
function t.setMenuHeight( h )
t.menuHeight = h
end
return t