1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/features/gui/toast.lua

291 lines
8.2 KiB
Lua
Raw Normal View History

2019-01-25 22:06:19 +02:00
local Event = require 'utils.event'
local Global = require 'utils.global'
local Gui = require 'utils.gui'
2019-01-27 17:34:40 +02:00
local Token = require 'utils.token'
2019-02-17 02:44:33 +02:00
local Command = require 'utils.command'
local Utils = require 'utils.core'
local Game = require 'utils.game'
2019-02-02 19:09:56 +02:00
local Settings = require 'utils.redmew_settings'
2019-01-25 22:06:19 +02:00
local Color = require 'resources.color_presets'
2019-02-17 02:44:33 +02:00
local Ranks = require 'resources.ranks'
2019-01-25 22:06:19 +02:00
local pairs = pairs
local next = next
2019-01-25 22:06:19 +02:00
local toast_volume_name = 'toast-volume'
Settings.register(toast_volume_name, 'fraction', 1.0)
2019-01-25 22:06:19 +02:00
local Public = {}
2019-01-27 17:34:40 +02:00
local active_toasts = {}
local id_counter = {0}
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
local on_tick
Global.register(
{active_toasts = active_toasts, id_counter = id_counter},
function(tbl)
active_toasts = tbl.active_toasts
id_counter = tbl.id_counter
end,
'toast'
)
local toast_frame_name = Gui.uid_name()
local toast_container_name = Gui.uid_name()
local toast_progress_name = Gui.uid_name()
local close_toast_name = Gui.uid_name()
2019-01-25 22:06:19 +02:00
2019-01-27 18:02:58 +02:00
--- Apply this name to an element to have it close the toast when clicked.
-- Two elements in the same parent cannot have the same name. If you need your
-- own name you can use Toast.close_toast(element)
Public.close_toast_name = close_toast_name
2019-01-25 22:06:19 +02:00
---Creates a unique ID for a toast message
local function autoincrement()
2019-01-27 17:34:40 +02:00
local id = id_counter[1] + 1
id_counter[1] = id
2019-01-25 22:06:19 +02:00
return id
end
2019-01-27 17:34:40 +02:00
---Attempts to get a toast based on the element, will traverse through parents to find it.
---@param element LuaGuiElement
local function get_toast(element)
if not element or not element.valid then
return nil
end
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
if element.name == toast_frame_name then
return element.parent
2019-01-25 22:06:19 +02:00
end
2019-01-27 17:34:40 +02:00
return get_toast(element.parent)
end
--- Closes the toast for the element.
--@param element LuaGuiElement
function Public.close_toast(element)
local toast = get_toast(element)
if not toast then
return
2019-01-25 22:06:19 +02:00
end
2019-01-27 17:34:40 +02:00
local data = Gui.get_data(toast)
active_toasts[data.toast_id] = nil
Gui.destroy(toast)
end
---Toast to a specific player
---@param player LuaPlayer
---@param duration number in seconds
---@param sound string sound to play, nil to not play anything
local function toast_to(player, duration, sound)
2019-01-27 17:34:40 +02:00
local frame_holder = player.gui.left.add({type = 'flow'})
local frame =
frame_holder.add({type = 'frame', name = toast_frame_name, direction = 'vertical', style = 'captionless_frame'})
2019-01-25 22:06:19 +02:00
frame.style.width = 300
2019-01-27 17:34:40 +02:00
local container = frame.add({type = 'flow', name = toast_container_name, direction = 'horizontal'})
2019-01-25 22:06:19 +02:00
container.style.horizontally_stretchable = true
2019-01-27 17:34:40 +02:00
local progressbar = frame.add({type = 'progressbar', name = toast_progress_name})
2019-01-25 22:06:19 +02:00
local style = progressbar.style
style.width = 290
2019-03-01 20:58:44 +02:00
style.height = 4
style.color = Color.orange
2019-01-25 22:06:19 +02:00
progressbar.value = 1 -- it starts full
local id = autoincrement()
local tick = game.tick
if not duration then
duration = 15
end
2019-01-27 17:34:40 +02:00
Gui.set_data(
frame_holder,
{
toast_id = id,
progressbar = progressbar,
start_tick = tick,
end_tick = tick + duration * 60
}
)
if not next(active_toasts) then
Event.add_removable_nth_tick(2, on_tick)
end
active_toasts[id] = frame_holder
2019-01-25 22:06:19 +02:00
if sound then
player.play_sound({path = sound, volume_modifier = Settings.get(player.index, toast_volume_name)})
end
2019-01-25 22:06:19 +02:00
return container
end
2019-01-27 17:34:40 +02:00
local close_toast = Public.close_toast
local function on_click_close_toast(event)
close_toast(event.element)
end
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
Gui.on_click(toast_frame_name, on_click_close_toast)
Gui.on_click(toast_container_name, on_click_close_toast)
Gui.on_click(toast_progress_name, on_click_close_toast)
Gui.on_click(close_toast_name, on_click_close_toast)
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
local function update_toast(id, frame, tick)
if not frame.valid then
active_toasts[id] = nil
return
2019-01-25 22:06:19 +02:00
end
2019-01-27 17:34:40 +02:00
local data = Gui.get_data(frame)
local end_tick = data.end_tick
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
if tick > end_tick then
Gui.destroy(frame)
active_toasts[data.toast_id] = nil
else
local limit = end_tick - data.start_tick
local current = end_tick - tick
data.progressbar.value = current / limit
2019-01-25 22:06:19 +02:00
end
2019-01-27 17:34:40 +02:00
end
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
on_tick =
Token.register(
function(event)
if not next(active_toasts) then
Event.remove_removable_nth_tick(2, on_tick)
return
end
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
local tick = event.tick
2019-01-25 22:06:19 +02:00
2019-01-27 17:34:40 +02:00
for id, frame in pairs(active_toasts) do
update_toast(id, frame, tick)
2019-01-25 22:06:19 +02:00
end
end
2019-01-27 17:34:40 +02:00
)
2019-01-25 22:06:19 +02:00
---Toast a specific player, template is a callable that receives a LuaGuiElement
---to add contents to and a player as second argument.
2019-01-27 17:43:09 +02:00
---@param player LuaPlayer
---@param duration table
---@param template function
---@param sound string sound to play, nil to not play anything
function Public.toast_player_template(player, duration, template, sound)
sound = sound or 'utility/new_objective'
local container = toast_to(player, duration, sound)
if container then
template(container, player)
end
end
---Toast all players of the given force, template is a callable that receives a LuaGuiElement
---to add contents to and a player as second argument.
---@param force LuaForce
---@param duration number
---@param template function
---@param sound string sound to play, nil to not play anything
function Public.toast_force_template(force, duration, template, sound)
sound = sound or 'utility/new_objective'
2019-01-27 17:34:40 +02:00
local players = force.connected_players
for i = 1, #players do
local player = players[i]
template(toast_to(player, duration, sound), player)
end
end
---Toast all players, template is a callable that receives a LuaGuiElement
---to add contents to and a player as second argument.
---@param duration number
---@param template function
---@param sound string sound to play, nil to not play anything
function Public.toast_all_players_template(duration, template, sound)
sound = sound or 'utility/new_objective'
2019-01-27 17:34:40 +02:00
local players = game.connected_players
for i = 1, #players do
local player = players[i]
template(toast_to(player, duration, sound), player)
2019-01-26 15:47:16 +02:00
end
end
---Toast a message to a specific player
2019-01-27 17:43:09 +02:00
---@param player LuaPlayer
---@param duration number
---@param message string
function Public.toast_player(player, duration, message)
2019-01-27 17:34:40 +02:00
Public.toast_player_template(
player,
duration,
function(container)
local label = container.add({type = 'label', name = close_toast_name, caption = message})
label.style.single_line = false
end
)
end
---Toast a message to all players of a given force
---@param force LuaForce
---@param duration number
---@param message string
function Public.toast_force(force, duration, message)
2019-01-27 17:34:40 +02:00
local players = force.connected_players
for i = 1, #players do
local player = players[i]
Public.toast_player(player, duration, message)
end
end
---Toast a message to all players
---@param duration number
---@param message string
function Public.toast_all_players(duration, message)
2019-01-27 17:34:40 +02:00
local players = game.connected_players
for i = 1, #players do
local player = players[i]
Public.toast_player(player, duration, message)
end
end
2019-01-26 15:47:16 +02:00
2019-02-17 02:44:33 +02:00
Command.add(
2019-02-17 18:55:01 +02:00
'toast',
2019-02-17 02:44:33 +02:00
{
description = {'command_description.toast'},
2019-02-17 02:44:33 +02:00
arguments = {'msg'},
capture_excess_arguments = true,
required_rank = Ranks.admin,
allowed_by_server = true
},
function(args)
Public.toast_all_players(15, args.msg)
Utils.print_admins({'command_description.sent_all_toast', Utils.get_actor()})
2019-02-17 02:44:33 +02:00
end
)
Command.add(
'toast-player',
{
description = {'command_description.toast_player'},
2019-02-17 02:44:33 +02:00
arguments = {'player', 'msg'},
capture_excess_arguments = true,
required_rank = Ranks.admin,
allowed_by_server = true
},
function(args)
2019-02-19 03:51:39 +02:00
local target_name = args.player
local target = game.players[target_name]
if target then
Public.toast_player(target, 15, args.msg)
Utils.print_admins({'command_description.sent_player_toast', Utils.get_actor(), target_name})
2019-02-17 02:44:33 +02:00
else
2019-02-19 03:51:39 +02:00
Game.player_print({'common.fail_no_target', target_name}, Color.yellow)
2019-02-17 02:44:33 +02:00
end
end
)
2019-01-25 22:06:19 +02:00
return Public