1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-12 10:04:40 +02:00
RedMew/poll.lua

1282 lines
36 KiB
Lua
Raw Normal View History

2018-06-17 15:51:06 +02:00
local Gui = require 'utils.gui'
local Global = require 'utils.global'
local Event = require 'utils.event'
2018-06-23 18:52:20 +02:00
local UserGroups = require 'user_groups'
2018-06-17 15:51:06 +02:00
2018-06-22 12:38:40 +02:00
local default_poll_duration = 300 * 60 -- in ticks
local duration_max = 3600 -- in seconds
local duration_step = 15 -- in seconds
local duration_slider_max = duration_max / duration_step
2018-06-21 23:54:13 +02:00
local tick_duration_step = duration_step * 60
local inv_tick_duration_step = 1 / tick_duration_step
2018-06-21 19:01:43 +02:00
2018-06-19 18:44:56 +02:00
local normal_color = {r = 1, g = 1, b = 1}
local focus_color = {r = 1, g = 0.55, b = 0.1}
2018-06-17 15:51:06 +02:00
local polls = {}
2018-06-21 11:20:07 +02:00
local polls_counter = {0}
2018-06-17 15:51:06 +02:00
local no_notify_players = {}
2018-06-18 20:38:10 +02:00
local player_poll_index = {}
2018-06-22 03:21:33 +02:00
local player_create_poll_data = {}
2018-06-17 15:51:06 +02:00
Global.register(
2018-06-18 20:38:10 +02:00
{
polls = polls,
2018-06-21 11:20:07 +02:00
polls_counter = polls_counter,
2018-06-18 20:38:10 +02:00
no_notify_players = no_notify_players,
2018-06-22 03:21:33 +02:00
player_poll_index = player_poll_index,
player_create_poll_data = player_create_poll_data
2018-06-18 20:38:10 +02:00
},
2018-06-17 15:51:06 +02:00
function(tbl)
polls = tbl.polls
2018-06-21 11:20:07 +02:00
polls_counter = tbl.polls_counter
2018-06-17 15:51:06 +02:00
no_notify_players = tbl.no_notify_players
2018-06-18 20:38:10 +02:00
player_poll_index = tbl.player_poll_index
2018-06-22 03:21:33 +02:00
player_create_poll_data = tbl.player_create_poll_data
2018-06-17 15:51:06 +02:00
end
)
local main_button_name = Gui.uid_name()
local main_frame_name = Gui.uid_name()
local create_poll_button_name = Gui.uid_name()
local notify_checkbox_name = Gui.uid_name()
2018-06-18 20:38:10 +02:00
local poll_view_back_name = Gui.uid_name()
local poll_view_forward_name = Gui.uid_name()
local poll_view_vote_name = Gui.uid_name()
2018-06-21 11:20:07 +02:00
local poll_view_edit_name = Gui.uid_name()
2018-06-18 20:38:10 +02:00
2018-06-17 15:51:06 +02:00
local create_poll_frame_name = Gui.uid_name()
2018-06-21 19:01:43 +02:00
local create_poll_duration_name = Gui.uid_name()
2018-06-17 15:51:06 +02:00
local create_poll_label_name = Gui.uid_name()
2018-06-20 18:15:21 +02:00
local create_poll_question_name = Gui.uid_name()
local create_poll_answer_name = Gui.uid_name()
2018-06-19 20:47:01 +02:00
local create_poll_add_answer_name = Gui.uid_name()
local create_poll_delete_answer_name = Gui.uid_name()
2018-06-17 15:51:06 +02:00
local create_poll_close_name = Gui.uid_name()
2018-06-18 20:38:10 +02:00
local create_poll_clear_name = Gui.uid_name()
2018-06-22 01:34:37 +02:00
local create_poll_edit_name = Gui.uid_name()
2018-06-17 15:51:06 +02:00
local create_poll_confirm_name = Gui.uid_name()
2018-06-22 01:34:37 +02:00
local create_poll_delete_name = Gui.uid_name()
2018-06-17 15:51:06 +02:00
2018-06-21 11:20:07 +02:00
local function poll_id()
local count = polls_counter[1] + 1
polls_counter[1] = count
return count
end
2018-06-23 18:52:20 +02:00
local function apply_direction_button_style(button)
local button_style = button.style
button_style.width = 24
button_style.height = 24
button_style.top_padding = 0
button_style.bottom_padding = 0
button_style.left_padding = 0
button_style.right_padding = 0
button_style.font = 'default-listbox'
end
local function apply_button_style(button)
local button_style = button.style
button_style.font = 'default-bold'
button_style.height = 26
button_style.top_padding = 0
button_style.bottom_padding = 0
button_style.left_padding = 2
button_style.right_padding = 2
end
2018-06-21 19:01:43 +02:00
local function do_remaining_time(poll, remaining_time_label)
2018-06-21 11:20:07 +02:00
local end_tick = poll.end_tick
if end_tick == -1 then
2018-06-21 19:01:43 +02:00
remaining_time_label.caption = 'Endless Poll.'
return true
end
local ticks = end_tick - game.tick
if ticks < 0 then
remaining_time_label.caption = 'Poll Finished.'
return false
2018-06-21 11:20:07 +02:00
else
2018-06-21 19:01:43 +02:00
local time = math.ceil(ticks / 60)
remaining_time_label.caption = 'Remaining Time: ' .. time
return true
2018-06-21 11:20:07 +02:00
end
end
2018-06-19 17:33:33 +02:00
local function redraw_poll_viewer_content(data)
local poll_viewer_content = data.poll_viewer_content
2018-06-25 22:29:18 +02:00
local remaining_time_label = data.remaining_time_label
2018-06-19 17:33:33 +02:00
local poll_index = data.poll_index
2018-06-21 11:20:07 +02:00
local player = poll_viewer_content.gui.player
2018-06-19 17:33:33 +02:00
data.vote_buttons = nil
Gui.remove_data_recursivly(poll_viewer_content)
poll_viewer_content.clear()
2018-06-18 20:38:10 +02:00
local poll = polls[poll_index]
if not poll then
return
end
2018-06-20 18:15:21 +02:00
local answers = poll.answers
local voters = poll.voters
local tooltips = {}
2018-06-22 03:21:33 +02:00
for _, a in ipairs(answers) do
tooltips[a] = {}
2018-06-20 18:15:21 +02:00
end
2018-06-22 03:21:33 +02:00
for player_index, answer in pairs(voters) do
2018-06-21 11:20:07 +02:00
local p = game.players[player_index]
2018-06-22 03:21:33 +02:00
table.insert(tooltips[answer], p.name)
2018-06-20 18:15:21 +02:00
end
2018-06-22 03:21:33 +02:00
for a, t in pairs(tooltips) do
2018-06-20 18:15:21 +02:00
if #t == 0 then
2018-06-22 03:21:33 +02:00
tooltips[a] = ''
2018-06-20 18:15:21 +02:00
else
2018-06-22 03:21:33 +02:00
tooltips[a] = table.concat(t, ', ')
2018-06-20 18:15:21 +02:00
end
end
2018-06-21 11:20:07 +02:00
local created_by_player = poll.created_by
local created_by_text
if created_by_player and created_by_player.valid then
created_by_text = ' Created by ' .. created_by_player.name
else
created_by_text = ''
end
local top_flow = poll_viewer_content.add {type = 'flow', direction = 'horizontal'}
2018-06-27 21:57:30 +02:00
top_flow.add {type = 'label', caption = table.concat {'Poll #', poll.id, created_by_text}}
2018-06-21 19:01:43 +02:00
2018-06-22 03:21:33 +02:00
local edited_by_players = poll.edited_by
if next(edited_by_players) then
2018-06-27 21:57:30 +02:00
local edit_names = {'Edited by '}
2018-06-22 03:21:33 +02:00
for pi, _ in pairs(edited_by_players) do
local p = game.players[pi]
if p and p.valid then
table.insert(edit_names, p.name)
2018-06-27 21:57:30 +02:00
table.insert(edit_names, ', ')
2018-06-22 03:21:33 +02:00
end
end
2018-06-27 21:57:30 +02:00
table.remove(edit_names)
2018-06-30 15:50:17 +02:00
local edit_text = table.concat(edit_names)
2018-06-22 03:21:33 +02:00
2018-06-25 22:43:51 +02:00
top_flow.add {type = 'label', caption = edit_text, tooltip = edit_text}
2018-06-22 03:21:33 +02:00
end
2018-06-21 19:01:43 +02:00
local poll_enabled = do_remaining_time(poll, remaining_time_label)
2018-06-21 11:20:07 +02:00
local question_flow = poll_viewer_content.add {type = 'table', column_count = 2}
2018-06-23 18:52:20 +02:00
if player.admin or UserGroups.is_regular(player.name) then
2018-06-21 11:20:07 +02:00
local edit_button =
question_flow.add {
type = 'sprite-button',
name = poll_view_edit_name,
sprite = 'utility/rename_icon_normal',
tooltip = 'Edit Poll.'
}
local edit_button_style = edit_button.style
edit_button_style.width = 26
edit_button_style.height = 26
end
local question_label = question_flow.add {type = 'label', caption = poll.question}
2018-06-19 18:44:56 +02:00
question_label.style.height = 32
question_label.style.font_color = focus_color
question_label.style.font = 'default-listbox'
2018-06-18 20:38:10 +02:00
2018-06-19 17:33:33 +02:00
local grid = poll_viewer_content.add {type = 'table', column_count = 2}
2018-06-18 20:38:10 +02:00
2018-06-22 03:21:33 +02:00
local answer = voters[player.index]
2018-06-19 17:33:33 +02:00
local vote_buttons = {}
2018-06-20 18:15:21 +02:00
for i, a in ipairs(answers) do
2018-06-25 22:29:18 +02:00
local vote_button_flow = grid.add {type = 'flow'}
2018-06-18 20:38:10 +02:00
local vote_button =
2018-06-25 22:29:18 +02:00
vote_button_flow.add {
2018-06-21 19:01:43 +02:00
type = 'button',
name = poll_view_vote_name,
caption = a.voted_count,
enabled = poll_enabled
}
2018-06-20 18:15:21 +02:00
2018-06-22 03:21:33 +02:00
local tooltip = tooltips[a]
2018-06-20 18:15:21 +02:00
if tooltip ~= '' then
vote_button.tooltip = tooltip
end
2018-06-25 22:29:18 +02:00
local vote_button_style = vote_button.style
vote_button_style.height = 24
vote_button_style.width = 26
vote_button_style.font = 'default-small'
vote_button_style.top_padding = 0
vote_button_style.bottom_padding = 0
vote_button_style.left_padding = 0
vote_button_style.right_padding = 0
2018-06-21 11:20:07 +02:00
2018-06-22 03:21:33 +02:00
if answer == a then
2018-06-25 22:29:18 +02:00
vote_button_style.font_color = focus_color
vote_button_style.disabled_font_color = focus_color
2018-06-21 11:20:07 +02:00
end
2018-06-22 03:21:33 +02:00
Gui.set_data(vote_button, {answer = a, data = data})
2018-06-19 17:33:33 +02:00
vote_buttons[i] = vote_button
2018-06-19 18:44:56 +02:00
local label = grid.add {type = 'label', caption = a.text}
label.style.height = 24
2018-06-18 20:38:10 +02:00
end
2018-06-19 17:33:33 +02:00
data.vote_buttons = vote_buttons
2018-06-18 20:38:10 +02:00
end
2018-06-19 17:33:33 +02:00
local function update_poll_viewer(data)
local back_button = data.back_button
local forward_button = data.forward_button
local poll_index_label = data.poll_index_label
local poll_index = data.poll_index
2018-06-21 11:20:07 +02:00
if #polls == 0 then
poll_index = 0
else
poll_index = math.clamp(poll_index, 1, #polls)
end
data.poll_index = poll_index
2018-06-18 20:38:10 +02:00
if poll_index == 0 then
2018-06-19 17:33:33 +02:00
poll_index_label.caption = 'No Polls'
2018-06-18 20:38:10 +02:00
else
2018-06-27 21:57:30 +02:00
poll_index_label.caption = table.concat {'Poll ', poll_index, ' / ', #polls}
2018-06-18 20:38:10 +02:00
end
2018-06-19 17:33:33 +02:00
back_button.enabled = poll_index > 1
forward_button.enabled = poll_index < #polls
redraw_poll_viewer_content(data)
end
local function draw_main_frame(left, player)
local frame = left.add {type = 'frame', name = main_frame_name, caption = 'Polls', direction = 'vertical'}
2018-06-23 18:52:20 +02:00
frame.style.maximal_width = 320
2018-06-19 17:33:33 +02:00
2018-06-25 22:29:18 +02:00
local poll_viewer_top_flow = frame.add {type = 'table', column_count = 5}
2018-06-21 11:20:07 +02:00
poll_viewer_top_flow.style.horizontal_spacing = 0
local back_button = poll_viewer_top_flow.add {type = 'button', name = poll_view_back_name, caption = ''}
apply_direction_button_style(back_button)
local forward_button = poll_viewer_top_flow.add {type = 'button', name = poll_view_forward_name, caption = ''}
apply_direction_button_style(forward_button)
2018-06-19 17:33:33 +02:00
local poll_index_label = poll_viewer_top_flow.add {type = 'label'}
2018-06-21 11:20:07 +02:00
poll_index_label.style.left_padding = 8
2018-06-19 17:33:33 +02:00
2018-06-25 22:29:18 +02:00
local spacer = poll_viewer_top_flow.add {type = 'flow'}
spacer.style.horizontally_stretchable = true
local remaining_time_label = poll_viewer_top_flow.add {type = 'label'}
2018-06-19 17:33:33 +02:00
local poll_viewer_content = frame.add {type = 'scroll-pane'}
2018-06-21 11:20:07 +02:00
poll_viewer_content.style.maximal_height = 250
2018-06-19 18:44:56 +02:00
poll_viewer_content.style.width = 300
2018-06-19 17:33:33 +02:00
local poll_index = player_poll_index[player.index] or #polls
2018-06-18 20:38:10 +02:00
local data = {
back_button = back_button,
forward_button = forward_button,
poll_index_label = poll_index_label,
2018-06-19 17:33:33 +02:00
poll_viewer_content = poll_viewer_content,
2018-06-25 22:29:18 +02:00
remaining_time_label = remaining_time_label,
2018-06-19 17:33:33 +02:00
poll_index = poll_index
2018-06-18 20:38:10 +02:00
}
Gui.set_data(frame, data)
Gui.set_data(back_button, data)
Gui.set_data(forward_button, data)
2018-06-19 17:33:33 +02:00
update_poll_viewer(data)
2018-06-17 15:51:06 +02:00
2018-06-21 11:20:07 +02:00
frame.add {
type = 'checkbox',
name = notify_checkbox_name,
caption = 'Notify me about polls.',
state = not no_notify_players[player.index],
2018-06-21 19:01:43 +02:00
tooltip = 'Receive a message when new polls are created and popup the poll.'
2018-06-21 11:20:07 +02:00
}
2018-06-17 15:51:06 +02:00
local bottom_flow = frame.add {type = 'flow', direction = 'horizontal'}
local left_flow = bottom_flow.add {type = 'flow'}
left_flow.style.align = 'left'
left_flow.style.horizontally_stretchable = true
2018-06-23 18:52:20 +02:00
local close_button = left_flow.add {type = 'button', name = main_button_name, caption = 'Close'}
apply_button_style(close_button)
2018-06-17 15:51:06 +02:00
local right_flow = bottom_flow.add {type = 'flow'}
right_flow.style.align = 'right'
2018-06-23 18:52:20 +02:00
if player.admin or UserGroups.is_regular(player.name) then
local create_poll_button =
right_flow.add {type = 'button', name = create_poll_button_name, caption = 'Create Poll'}
apply_button_style(create_poll_button)
2018-06-21 19:01:43 +02:00
else
2018-06-23 18:52:20 +02:00
local create_poll_button =
right_flow.add {
2018-06-21 19:01:43 +02:00
type = 'button',
caption = 'Create Poll',
enabled = false,
tooltip = 'Sorry, you need to be a regular to create polls.'
}
2018-06-23 18:52:20 +02:00
apply_button_style(create_poll_button)
2018-06-18 20:38:10 +02:00
end
2018-06-17 15:51:06 +02:00
end
2018-06-22 03:21:33 +02:00
local function remove_create_poll_frame(create_poll_frame, player_index)
local data = Gui.get_data(create_poll_frame)
2018-06-22 12:38:40 +02:00
data.edit_mode = nil
2018-06-22 03:21:33 +02:00
player_create_poll_data[player_index] = data
Gui.remove_data_recursivly(create_poll_frame)
create_poll_frame.destroy()
end
local function remove_main_frame(main_frame, left, player)
local player_index = player.index
local data = Gui.get_data(main_frame)
player_poll_index[player_index] = data.poll_index
Gui.remove_data_recursivly(main_frame)
main_frame.destroy()
local create_poll_frame = left[create_poll_frame_name]
if create_poll_frame and create_poll_frame.valid then
remove_create_poll_frame(create_poll_frame, player_index)
end
end
2018-06-17 15:51:06 +02:00
local function toggle(event)
local left = event.player.gui.left
local main_frame = left[main_frame_name]
if main_frame then
2018-06-22 03:21:33 +02:00
remove_main_frame(main_frame, left, event.player)
2018-06-17 15:51:06 +02:00
else
draw_main_frame(left, event.player)
end
end
2018-06-21 19:01:43 +02:00
local function update_duration(slider)
local slider_data = Gui.get_data(slider)
local label = slider_data.duration_label
local value = slider.slider_value
value = math.floor(value)
2018-06-21 23:54:13 +02:00
slider_data.data.duration = value * tick_duration_step
2018-06-21 19:01:43 +02:00
if value == 0 then
label.caption = 'Endless Poll.'
else
2018-06-21 23:54:13 +02:00
label.caption = value * duration_step .. ' seconds.'
2018-06-21 19:01:43 +02:00
end
end
2018-06-20 18:15:21 +02:00
local function redraw_create_poll_content(data)
2018-06-18 20:38:10 +02:00
local grid = data.grid
local answers = data.answers
2018-06-20 18:15:21 +02:00
Gui.remove_data_recursivly(grid)
grid.clear()
2018-06-19 20:47:01 +02:00
2018-06-21 19:01:43 +02:00
grid.add {type = 'flow'}
grid.add {
type = 'label',
caption = 'Duration:',
tooltip = 'Pro tip: Use mouse wheel or arrow keys for more fine control.'
}
local duration_flow = grid.add {type = 'flow', direction = 'horizontal'}
local duration_slider =
duration_flow.add {
type = 'slider',
name = create_poll_duration_name,
minimum_value = 0,
2018-06-22 12:38:40 +02:00
maximum_value = duration_slider_max,
2018-06-21 23:54:13 +02:00
value = math.floor(data.duration * inv_tick_duration_step)
2018-06-21 19:01:43 +02:00
}
duration_slider.style.width = 100
2018-06-22 03:21:33 +02:00
data.duration_slider = duration_slider
2018-06-21 23:54:13 +02:00
local duration_label = duration_flow.add {type = 'label'}
2018-06-21 19:01:43 +02:00
Gui.set_data(duration_slider, {duration_label = duration_label, data = data})
update_duration(duration_slider)
2018-06-20 18:15:21 +02:00
grid.add {type = 'flow'}
2018-06-19 20:47:01 +02:00
local question_label =
grid.add({type = 'flow'}).add {type = 'label', name = create_poll_label_name, caption = 'Question:'}
2018-06-20 18:15:21 +02:00
local question_textfield =
grid.add({type = 'flow'}).add {type = 'textfield', name = create_poll_question_name, text = data.question}
2018-06-22 12:38:40 +02:00
question_textfield.style.width = 400
2018-06-19 20:47:01 +02:00
Gui.set_data(question_label, question_textfield)
2018-06-20 18:15:21 +02:00
Gui.set_data(question_textfield, data)
2018-06-22 12:38:40 +02:00
local edit_mode = data.edit_mode
2018-06-22 01:34:37 +02:00
for count, answer in ipairs(answers) do
2018-06-20 18:15:21 +02:00
local delete_flow = grid.add {type = 'flow'}
local delete_button
2018-06-22 12:38:40 +02:00
if edit_mode or count ~= 1 then
2018-06-20 18:15:21 +02:00
delete_button =
delete_flow.add {
type = 'sprite-button',
name = create_poll_delete_answer_name,
sprite = 'utility/remove',
tooltip = 'Delete answer field.'
}
delete_button.style.height = 26
delete_button.style.width = 26
2018-06-21 11:20:07 +02:00
else
delete_flow.style.height = 26
delete_flow.style.width = 26
2018-06-20 18:15:21 +02:00
end
local label_flow = grid.add {type = 'flow'}
local label =
label_flow.add {
type = 'label',
name = create_poll_label_name,
2018-06-27 21:57:30 +02:00
caption = table.concat {'Answer #', count, ':'}
2018-06-20 18:15:21 +02:00
}
local textfield_flow = grid.add {type = 'flow'}
2018-06-22 01:34:37 +02:00
local textfield = textfield_flow.add {type = 'textfield', name = create_poll_answer_name, text = answer.text}
2018-06-22 12:38:40 +02:00
textfield.style.width = 400
2018-06-20 18:15:21 +02:00
Gui.set_data(textfield, {answers = answers, count = count})
if delete_button then
Gui.set_data(delete_button, {data = data, count = count})
end
Gui.set_data(label, textfield)
end
end
2018-06-22 03:21:33 +02:00
local function draw_create_poll_frame(parent, player, previous_data)
previous_data = previous_data or player_create_poll_data[player.index]
local edit_mode
2018-06-20 18:15:21 +02:00
local question
local answers
2018-06-21 19:01:43 +02:00
local duration
2018-06-22 01:34:37 +02:00
local title_text
local confirm_text
local confirm_name
2018-06-20 18:15:21 +02:00
if previous_data then
2018-06-22 03:21:33 +02:00
edit_mode = previous_data.edit_mode
2018-06-20 18:15:21 +02:00
question = previous_data.question
2018-06-22 01:34:37 +02:00
answers = {}
for i, a in ipairs(previous_data.answers) do
answers[i] = {text = a.text, source = a}
end
2018-06-21 19:01:43 +02:00
duration = previous_data.duration
2018-06-22 01:34:37 +02:00
else
question = ''
answers = {{text = ''}, {text = ''}, {text = ''}}
duration = default_poll_duration
2018-06-22 03:21:33 +02:00
end
2018-06-22 01:34:37 +02:00
2018-06-22 03:21:33 +02:00
if edit_mode then
title_text = 'Edit Poll #' .. previous_data.id
confirm_text = 'Edit Poll'
confirm_name = create_poll_edit_name
else
2018-06-22 01:34:37 +02:00
title_text = 'New Poll'
confirm_text = 'Create Poll'
confirm_name = create_poll_confirm_name
2018-06-20 18:15:21 +02:00
end
local frame =
2018-06-22 01:34:37 +02:00
parent.add {type = 'frame', name = create_poll_frame_name, caption = title_text, direction = 'vertical'}
2018-06-23 18:52:20 +02:00
frame.style.maximal_width = 320
2018-06-20 18:15:21 +02:00
local scroll_pane = frame.add {type = 'scroll-pane', vertical_scroll_policy = 'always'}
2018-06-21 11:20:07 +02:00
scroll_pane.style.maximal_height = 250
2018-06-20 18:15:21 +02:00
scroll_pane.style.maximal_width = 300
local grid = scroll_pane.add {type = 'table', column_count = 3}
2018-06-19 20:47:01 +02:00
local data = {
frame = frame,
grid = grid,
2018-06-20 18:15:21 +02:00
question = question,
2018-06-21 19:01:43 +02:00
answers = answers,
2018-06-22 01:34:37 +02:00
duration = duration,
2018-06-22 12:38:40 +02:00
previous_data = previous_data,
edit_mode = edit_mode
2018-06-19 20:47:01 +02:00
}
2018-06-22 03:21:33 +02:00
Gui.set_data(frame, data)
2018-06-20 18:15:21 +02:00
redraw_create_poll_content(data)
2018-06-19 20:47:01 +02:00
2018-06-20 18:15:21 +02:00
local add_answer_button =
2018-06-23 18:52:20 +02:00
scroll_pane.add {
type = 'button',
name = create_poll_add_answer_name,
caption = 'Add Answer'
}
apply_button_style(add_answer_button)
2018-06-20 18:15:21 +02:00
Gui.set_data(add_answer_button, data)
2018-06-17 15:51:06 +02:00
2018-06-20 18:15:21 +02:00
local bottom_flow = frame.add {type = 'flow', direction = 'horizontal'}
2018-06-18 20:38:10 +02:00
2018-06-20 18:15:21 +02:00
local left_flow = bottom_flow.add {type = 'flow'}
left_flow.style.align = 'left'
left_flow.style.horizontally_stretchable = true
2018-06-18 20:38:10 +02:00
2018-06-20 18:15:21 +02:00
local close_button = left_flow.add {type = 'button', name = create_poll_close_name, caption = 'Close'}
2018-06-23 18:52:20 +02:00
apply_button_style(close_button)
2018-06-20 18:15:21 +02:00
Gui.set_data(close_button, frame)
2018-06-17 15:51:06 +02:00
2018-06-20 18:15:21 +02:00
local clear_button = left_flow.add {type = 'button', name = create_poll_clear_name, caption = 'Clear'}
2018-06-23 18:52:20 +02:00
apply_button_style(clear_button)
2018-06-20 18:15:21 +02:00
Gui.set_data(clear_button, data)
2018-06-18 20:38:10 +02:00
2018-06-20 18:15:21 +02:00
local right_flow = bottom_flow.add {type = 'flow'}
right_flow.style.align = 'right'
2018-06-18 20:38:10 +02:00
2018-06-22 03:21:33 +02:00
if edit_mode then
2018-06-22 01:34:37 +02:00
local delete_button = right_flow.add {type = 'button', name = create_poll_delete_name, caption = 'Delete'}
2018-06-23 18:52:20 +02:00
apply_button_style(delete_button)
2018-06-22 01:34:37 +02:00
Gui.set_data(delete_button, data)
end
local confirm_button = right_flow.add {type = 'button', name = confirm_name, caption = confirm_text}
2018-06-23 18:52:20 +02:00
apply_button_style(confirm_button)
2018-06-20 18:15:21 +02:00
Gui.set_data(confirm_button, data)
2018-06-18 20:38:10 +02:00
end
2018-06-21 19:01:43 +02:00
local function show_new_poll(poll_data)
2018-06-27 21:57:30 +02:00
local message =
table.concat {poll_data.created_by.name, ' has created a new Poll #', poll_data.id, ': ', poll_data.question}
2018-06-18 20:38:10 +02:00
for _, p in ipairs(game.connected_players) do
2018-06-21 19:01:43 +02:00
local left = p.gui.left
local frame = left[main_frame_name]
2018-06-22 03:21:33 +02:00
if no_notify_players[p.index] then
if frame and frame.valid then
local data = Gui.get_data(frame)
update_poll_viewer(data)
end
else
2018-06-27 21:57:30 +02:00
p.print(message)
2018-06-21 19:01:43 +02:00
if frame and frame.valid then
local data = Gui.get_data(frame)
data.poll_index = #polls
update_poll_viewer(data)
else
2018-06-23 18:52:20 +02:00
player_poll_index[p.index] = nil
2018-06-21 19:01:43 +02:00
draw_main_frame(left, p)
end
2018-06-18 20:38:10 +02:00
end
end
end
local function create_poll(event)
2018-06-22 12:38:40 +02:00
local player = event.player
2018-06-18 20:38:10 +02:00
local data = Gui.get_data(event.element)
local frame = data.frame
2018-06-20 18:15:21 +02:00
local question = data.question
2018-06-18 20:38:10 +02:00
if not question:find('%S') then
event.player.print('Sorry, the poll needs a question.')
return
end
local answers = {}
2018-06-22 12:38:40 +02:00
for _, a in ipairs(data.answers) do
2018-06-22 01:34:37 +02:00
local text = a.text
if text:find('%S') then
2018-06-22 12:38:40 +02:00
local index = #answers + 1
answers[index] = {text = text, index = index, voted_count = 0}
2018-06-18 20:38:10 +02:00
end
end
if #answers < 1 then
2018-06-22 12:38:40 +02:00
player.print('Sorry, the poll needs at least one answer.')
2018-06-18 20:38:10 +02:00
return
end
2018-06-22 12:38:40 +02:00
player_create_poll_data[player.index] = nil
2018-06-18 20:38:10 +02:00
local tick = game.tick
2018-06-21 19:01:43 +02:00
local duration = data.duration
local end_tick
if duration == 0 then
end_tick = -1
else
end_tick = tick + duration
end
2018-06-18 20:38:10 +02:00
local poll_data = {
2018-06-21 11:20:07 +02:00
id = poll_id(),
2018-06-18 20:38:10 +02:00
question = question,
answers = answers,
voters = {},
start_tick = tick,
2018-06-21 19:01:43 +02:00
end_tick = end_tick,
duration = duration,
2018-06-18 20:38:10 +02:00
created_by = event.player,
edited_by = {}
}
table.insert(polls, poll_data)
2018-06-21 19:01:43 +02:00
show_new_poll(poll_data)
2018-06-18 20:38:10 +02:00
Gui.remove_data_recursivly(frame)
frame.destroy()
2018-06-17 15:51:06 +02:00
end
2018-06-22 03:21:33 +02:00
local function update_vote(voters, answer, direction)
local count = answer.voted_count + direction
answer.voted_count = count
2018-06-21 11:20:07 +02:00
local tooltip = {}
2018-06-22 03:21:33 +02:00
for pi, a in pairs(voters) do
if a == answer then
2018-06-21 11:20:07 +02:00
local player = game.players[pi]
table.insert(tooltip, player.name)
end
end
return tostring(count), table.concat(tooltip, ', ')
end
2018-06-19 17:33:33 +02:00
local function vote(event)
local player_index = event.player_index
local voted_button = event.element
local button_data = Gui.get_data(voted_button)
2018-06-22 03:21:33 +02:00
local answer = button_data.answer
2018-06-21 11:20:07 +02:00
local poll_index = button_data.data.poll_index
2018-06-19 17:33:33 +02:00
local poll = polls[poll_index]
local voters = poll.voters
2018-06-22 03:21:33 +02:00
local previous_vote_answer = voters[player_index]
if previous_vote_answer == answer then
2018-06-19 17:33:33 +02:00
return
end
2018-06-22 03:21:33 +02:00
local vote_index = answer.index
2018-06-21 11:20:07 +02:00
2018-06-22 03:21:33 +02:00
voters[player_index] = answer
2018-06-19 17:33:33 +02:00
2018-06-21 11:20:07 +02:00
local previous_vote_button_count
local previous_vote_button_tooltip
2018-06-22 03:21:33 +02:00
local previous_vote_index
if previous_vote_answer then
previous_vote_button_count, previous_vote_button_tooltip = update_vote(voters, previous_vote_answer, -1)
previous_vote_index = previous_vote_answer.index
2018-06-19 17:33:33 +02:00
end
2018-06-22 03:21:33 +02:00
local vote_button_count, vote_button_tooltip = update_vote(voters, answer, 1)
2018-06-21 11:20:07 +02:00
for _, p in ipairs(game.connected_players) do
local frame = p.gui.left[main_frame_name]
if frame and frame.valid then
local data = Gui.get_data(frame)
2018-06-19 17:33:33 +02:00
2018-06-21 11:20:07 +02:00
if data.poll_index == poll_index then
local vote_buttons = data.vote_buttons
2018-06-22 03:21:33 +02:00
if previous_vote_answer then
2018-06-21 11:20:07 +02:00
local vote_button = vote_buttons[previous_vote_index]
vote_button.caption = previous_vote_button_count
vote_button.tooltip = previous_vote_button_tooltip
2018-06-23 18:52:20 +02:00
if p.index == player_index then
2018-06-25 22:29:18 +02:00
local vote_button_style = vote_button.style
vote_button_style.font_color = normal_color
vote_button_style.disabled_font_color = normal_color
2018-06-23 18:52:20 +02:00
end
2018-06-21 11:20:07 +02:00
end
local vote_button = vote_buttons[vote_index]
vote_button.caption = vote_button_count
vote_button.tooltip = vote_button_tooltip
2018-06-23 18:52:20 +02:00
if p.index == player_index then
2018-06-25 22:29:18 +02:00
local vote_button_style = vote_button.style
vote_button_style.font_color = focus_color
vote_button_style.disabled_font_color = focus_color
2018-06-23 18:52:20 +02:00
end
2018-06-21 11:20:07 +02:00
end
end
end
2018-06-19 17:33:33 +02:00
end
2018-06-21 19:01:43 +02:00
local function player_joined(event)
local player = game.players[event.player_index]
if not player or not player.valid then
return
end
local gui = player.gui
if gui.top[main_button_name] ~= nil then
local frame = gui.left[main_frame_name]
if frame and frame.valid then
local data = Gui.get_data(frame)
update_poll_viewer(data)
end
else
gui.top.add {type = 'sprite-button', name = main_button_name, sprite = 'item/programmable-speaker'}
end
end
local function tick()
for _, p in ipairs(game.connected_players) do
local frame = p.gui.left[main_frame_name]
if frame and frame.valid then
local data = Gui.get_data(frame)
local poll = polls[data.poll_index]
if poll then
local poll_enabled = do_remaining_time(poll, data.remaining_time_label)
if not poll_enabled then
for _, v in ipairs(data.vote_buttons) do
v.enabled = poll_enabled
end
end
end
end
end
end
2018-06-17 15:51:06 +02:00
Event.add(defines.events.on_player_joined_game, player_joined)
2018-06-21 19:01:43 +02:00
Event.on_nth_tick(60, tick)
2018-06-17 15:51:06 +02:00
Gui.on_click(main_button_name, toggle)
2018-06-20 18:15:21 +02:00
Gui.on_click(
create_poll_button_name,
function(event)
2018-06-22 03:21:33 +02:00
local player = event.player
local left = player.gui.left
2018-06-20 18:15:21 +02:00
local frame = left[create_poll_frame_name]
if frame and frame.valid then
2018-06-22 03:21:33 +02:00
remove_create_poll_frame(frame, player.index)
2018-06-20 18:15:21 +02:00
else
2018-06-22 03:21:33 +02:00
draw_create_poll_frame(left, player)
2018-06-20 18:15:21 +02:00
end
end
)
2018-06-22 01:34:37 +02:00
Gui.on_click(
poll_view_edit_name,
function(event)
2018-06-22 03:21:33 +02:00
local player = event.player
local left = player.gui.left
2018-06-22 01:34:37 +02:00
local frame = left[create_poll_frame_name]
if frame and frame.valid then
Gui.remove_data_recursivly(frame)
frame.destroy()
end
local main_frame = left[main_frame_name]
local frame_data = Gui.get_data(main_frame)
local poll = polls[frame_data.poll_index]
2018-06-22 03:21:33 +02:00
poll.edit_mode = true
draw_create_poll_frame(left, player, poll)
2018-06-22 01:34:37 +02:00
end
)
2018-06-21 19:01:43 +02:00
Gui.on_value_changed(
create_poll_duration_name,
function(event)
update_duration(event.element)
end
)
2018-06-20 18:15:21 +02:00
Gui.on_click(
create_poll_delete_answer_name,
function(event)
local button_data = Gui.get_data(event.element)
local data = button_data.data
table.remove(data.answers, button_data.count)
redraw_create_poll_content(data)
end
)
2018-06-17 15:51:06 +02:00
2018-06-18 20:38:10 +02:00
Gui.on_click(
create_poll_label_name,
function(event)
local textfield = Gui.get_data(event.element)
textfield.focus()
end
)
2018-06-20 18:15:21 +02:00
Gui.on_text_changed(
create_poll_question_name,
function(event)
local textfield = event.element
local data = Gui.get_data(textfield)
data.question = textfield.text
end
)
Gui.on_text_changed(
create_poll_answer_name,
function(event)
local textfield = event.element
local data = Gui.get_data(textfield)
2018-06-22 01:34:37 +02:00
data.answers[data.count].text = textfield.text
2018-06-20 18:15:21 +02:00
end
)
Gui.on_click(
create_poll_add_answer_name,
function(event)
local data = Gui.get_data(event.element)
2018-06-22 01:34:37 +02:00
table.insert(data.answers, {text = ''})
2018-06-20 18:15:21 +02:00
redraw_create_poll_content(data)
end
)
2018-06-17 15:51:06 +02:00
Gui.on_click(
create_poll_close_name,
function(event)
2018-06-22 03:21:33 +02:00
local frame = Gui.get_data(event.element)
remove_create_poll_frame(frame, event.player_index)
2018-06-17 15:51:06 +02:00
end
)
2018-06-18 20:38:10 +02:00
Gui.on_click(
create_poll_clear_name,
function(event)
local data = Gui.get_data(event.element)
2018-06-22 03:21:33 +02:00
local slider = data.duration_slider
slider.slider_value = math.floor(default_poll_duration * inv_tick_duration_step)
update_duration(slider)
2018-06-20 18:15:21 +02:00
data.question = ''
2018-06-22 03:21:33 +02:00
2018-06-20 18:15:21 +02:00
local answers = data.answers
for i = 1, #answers do
2018-06-22 01:34:37 +02:00
answers[i].text = ''
2018-06-18 20:38:10 +02:00
end
2018-06-20 18:15:21 +02:00
redraw_create_poll_content(data)
2018-06-18 20:38:10 +02:00
end
)
Gui.on_click(create_poll_confirm_name, create_poll)
2018-06-22 01:34:37 +02:00
Gui.on_click(
create_poll_delete_name,
function(event)
2018-06-22 13:31:05 +02:00
local player = event.player
2018-06-22 01:34:37 +02:00
local data = Gui.get_data(event.element)
local frame = data.frame
local poll = data.previous_data
Gui.remove_data_recursivly(frame)
frame.destroy()
2018-06-22 13:31:05 +02:00
player_create_poll_data[player.index] = nil
2018-06-22 01:34:37 +02:00
local removed_index
for i, p in ipairs(polls) do
if p == poll then
table.remove(polls, i)
removed_index = i
break
end
end
if not removed_index then
return
end
2018-06-27 21:57:30 +02:00
local message = table.concat {player.name, ' has deleted Poll #', poll.id, ': ', poll.question}
2018-06-22 01:34:37 +02:00
for _, p in ipairs(game.connected_players) do
if not no_notify_players[p.index] then
p.print(message)
end
local main_frame = p.gui.left[main_frame_name]
if main_frame and main_frame.valid then
local main_frame_data = Gui.get_data(main_frame)
local poll_index = main_frame_data.poll_index
2018-07-04 17:22:26 +02:00
if removed_index < poll_index then
2018-06-22 01:34:37 +02:00
main_frame_data.poll_index = poll_index - 1
end
update_poll_viewer(main_frame_data)
end
end
end
)
Gui.on_click(
create_poll_edit_name,
function(event)
local player = event.player
local data = Gui.get_data(event.element)
local frame = data.frame
local poll = data.previous_data
local new_question = data.question
if not new_question:find('%S') then
player.print('Sorry, the poll needs a question.')
return
end
local new_answer_set = {}
2018-06-22 03:21:33 +02:00
local new_answers = {}
2018-06-22 12:38:40 +02:00
for _, a in ipairs(data.answers) do
2018-06-22 01:34:37 +02:00
if a.text:find('%S') then
2018-06-22 03:21:33 +02:00
local source = a.source
2018-06-22 12:38:40 +02:00
local index = #new_answers + 1
2018-06-22 03:21:33 +02:00
if source then
new_answer_set[source] = a
source.text = a.text
2018-06-22 12:38:40 +02:00
source.index = index
new_answers[index] = source
2018-06-22 03:21:33 +02:00
else
2018-06-22 12:38:40 +02:00
new_answers[index] = {text = a.text, index = index, voted_count = 0}
2018-06-22 03:21:33 +02:00
end
2018-06-22 01:34:37 +02:00
end
end
2018-06-22 03:21:33 +02:00
if not next(new_answers) then
2018-06-22 01:34:37 +02:00
player.print('Sorry, the poll needs at least one answer.')
return
end
Gui.remove_data_recursivly(frame)
frame.destroy()
2018-06-27 21:57:30 +02:00
local player_index = player.index
player_create_poll_data[player_index] = nil
2018-06-22 13:31:05 +02:00
2018-06-22 01:34:37 +02:00
local old_answers = poll.answers
2018-06-22 03:21:33 +02:00
local voters = poll.voters
for _, a in ipairs(old_answers) do
if not new_answer_set[a] then
for pi, a2 in pairs(voters) do
if a == a2 then
voters[pi] = nil
end
end
2018-06-22 01:34:37 +02:00
end
end
2018-06-22 03:21:33 +02:00
poll.question = new_question
poll.answers = new_answers
2018-06-27 21:57:30 +02:00
poll.edited_by[player_index] = true
2018-06-22 03:21:33 +02:00
2018-06-22 13:31:05 +02:00
local start_tick = game.tick
local duration = data.duration
local end_tick
if duration == 0 then
end_tick = -1
else
end_tick = start_tick + duration
end
poll.start_tick = start_tick
poll.end_tick = end_tick
poll.duration = duration
2018-06-27 21:57:30 +02:00
local poll_index
for i, p in ipairs(polls) do
if poll == p then
poll_index = i
break
end
end
if not poll_index then
table.insert(polls, poll)
poll_index = #polls
end
local message = table.concat {player.name, ' has edited Poll #', poll.id, ': ', poll.question}
2018-06-22 01:34:37 +02:00
for _, p in ipairs(game.connected_players) do
local main_frame = p.gui.left[main_frame_name]
2018-06-22 03:21:33 +02:00
if no_notify_players[p.index] then
if main_frame and main_frame.valid then
local main_frame_data = Gui.get_data(main_frame)
update_poll_viewer(main_frame_data)
end
else
p.print(message)
if main_frame and main_frame.valid then
local main_frame_data = Gui.get_data(main_frame)
2018-06-27 21:57:30 +02:00
main_frame_data.poll_index = poll_index
2018-06-22 03:21:33 +02:00
update_poll_viewer(main_frame_data)
else
draw_main_frame(p.gui.left, p)
end
2018-06-22 01:34:37 +02:00
end
end
end
)
2018-06-17 15:51:06 +02:00
Gui.on_click(
notify_checkbox_name,
function(event)
local player_index = event.player_index
local checkbox = event.element
local new_state
if checkbox.state then
new_state = nil
else
new_state = true
end
no_notify_players[player_index] = new_state
end
)
2018-04-06 21:58:50 +02:00
2018-06-21 19:01:43 +02:00
local function do_direction(event, sign)
local count
2018-06-21 11:20:07 +02:00
if event.shift then
2018-06-25 22:29:18 +02:00
count = #polls
2018-06-21 11:20:07 +02:00
else
2018-06-21 19:01:43 +02:00
local button = event.button
if button == defines.mouse_button_type.right then
count = 5
else
count = 1
end
2018-06-21 11:20:07 +02:00
end
2018-06-21 19:01:43 +02:00
count = count * sign
local data = Gui.get_data(event.element)
data.poll_index = data.poll_index + count
update_poll_viewer(data)
2018-06-21 11:20:07 +02:00
end
2018-06-19 17:33:33 +02:00
Gui.on_click(
poll_view_back_name,
function(event)
2018-06-21 19:01:43 +02:00
do_direction(event, -1)
2018-06-19 17:33:33 +02:00
end
)
2017-06-13 13:16:07 +02:00
2018-06-19 17:33:33 +02:00
Gui.on_click(
poll_view_forward_name,
function(event)
2018-06-21 19:01:43 +02:00
do_direction(event, 1)
2018-06-19 17:33:33 +02:00
end
)
2017-06-13 13:16:07 +02:00
2018-06-19 17:33:33 +02:00
Gui.on_click(poll_view_vote_name, vote)
2018-06-21 19:01:43 +02:00
2018-06-23 18:52:20 +02:00
local Class = {}
function Class.validate(data)
if type(data) ~= 'table' then
return false, 'argument must be of type table'
end
local question = data.question
if type(question) ~= 'string' or question == '' then
return false, 'field question must be a non empty string.'
end
local answers = data.answers
if type(answers) ~= 'table' then
return false, 'answers field must be an array.'
end
if #answers == 0 then
return false, 'answer array must contain at least one entry.'
end
for _, a in ipairs(answers) do
2018-06-25 22:43:51 +02:00
if type(a) ~= 'string' or a == '' then
return false, 'answers must be a non empty string.'
2018-06-23 18:52:20 +02:00
end
end
local duration = data.duration
local duration_type = type(duration)
if duration_type == 'number' then
if duration < 0 then
return false, 'duration cannot be negative, set duration to 0 for endless poll.'
end
elseif duration_type ~= 'nil' then
return false, 'duration must be of type number or nil'
end
return true
end
function Class.poll(data)
local suc, error = Class.validate(data)
if not suc then
return false, error
end
local answers = {}
for index, a in ipairs(data.answers) do
if a ~= '' then
table.insert(answers, {text = a, index = index, voted_count = 0})
end
end
local duration = data.duration
if duration then
duration = duration * 60
else
duration = default_poll_duration
end
local start_tick = game.tick
local end_tick
if duration == 0 then
end_tick = -1
else
end_tick = start_tick + duration
end
local id = poll_id()
2018-06-21 19:01:43 +02:00
local poll_data = {
2018-06-23 18:52:20 +02:00
id = id,
question = data.question,
answers = answers,
2018-06-21 19:01:43 +02:00
voters = {},
2018-06-23 18:52:20 +02:00
start_tick = start_tick,
end_tick = end_tick,
2018-06-21 19:01:43 +02:00
duration = duration,
2018-06-23 18:52:20 +02:00
created_by = game.player or {name = '<server>', valid = true},
2018-06-21 19:01:43 +02:00
edited_by = {}
}
table.insert(polls, poll_data)
show_new_poll(poll_data)
2018-06-23 18:52:20 +02:00
return true, id
end
function Class.poll_result(id)
if type(id) ~= 'number' then
return 'poll-id must be a number'
end
for _, poll_data in ipairs(polls) do
if poll_data.id == id then
local result = {'Question: ', poll_data.question, ' Answers: '}
local answers = poll_data.answers
local answers_count = #answers
for i, a in ipairs(answers) do
table.insert(result, '( [')
table.insert(result, a.voted_count)
table.insert(result, '] - ')
table.insert(result, a.text)
table.insert(result, ' )')
if i ~= answers_count then
table.insert(result, ', ')
end
end
return table.concat(result)
end
end
2018-06-27 21:57:30 +02:00
return table.concat {'poll #', id, ' not found'}
2018-06-23 18:52:20 +02:00
end
local function poll_command(cmd)
local player = game.player
if player and not (player.admin or UserGroups.is_regular(player.name)) then
cant_run(cmd.name)
end
local param = cmd.parameter
if not param then
2018-06-25 22:43:51 +02:00
player_print('Usage: /poll <{question = "question", answers = {"answer 1", "answer 2"}, duration = 300 | nil}>')
2018-06-23 18:52:20 +02:00
return
end
param = 'return ' .. param
2018-06-25 16:53:35 +02:00
local func, error = loadstring(param)
if not func then
player_print(error)
2018-06-23 18:52:20 +02:00
return
end
2018-06-25 16:53:35 +02:00
local suc, result = Class.poll(func())
2018-06-23 18:52:20 +02:00
if not suc then
2018-06-25 16:53:35 +02:00
player_print(result)
2018-06-23 18:52:20 +02:00
else
2018-06-27 21:57:30 +02:00
player_print(table.concat {'Poll #', result, ' successfully created.'})
2018-06-23 18:52:20 +02:00
end
end
local function poll_result_command(cmd)
local param = cmd.parameter
if not param then
player_print('Usage: /poll-result <poll#>')
return
end
local id = tonumber(param)
local result = Class.poll_result(id)
player_print(result)
end
commands.add_command(
'poll',
2018-06-25 22:43:51 +02:00
'<{question = "question", answers = {"answer 1", "answer 2"}, duration = 300 | nil}> - Creates a new poll (Admin and regulars only).',
2018-06-23 18:52:20 +02:00
poll_command
)
commands.add_command('poll-result', '<poll#> - prints the result for the poll.', poll_result_command)
return Class