MP Staging: redesigned dialog to group sides by team

This commit is contained in:
Charles Dang 2016-10-09 21:57:37 +11:00
parent 41a49f74ac
commit aabc655c6c
5 changed files with 646 additions and 523 deletions

View file

@ -94,5 +94,15 @@
[/panel_definition]
[panel_definition]
id = "box_display_no_blur_no_border"
description = "Definition of the panel for the title screen"
{_GUI_RESOLUTION (window_width,window_height = 850, 650) 10 5 10 5 () }
{_GUI_RESOLUTION () 3 5 9 14 () }
[/panel_definition]
#undef _GUI_RESOLUTION
#undef _PANEL_BLUR

View file

@ -4,172 +4,155 @@
###
#define _GUI_SIDE_LIST
[listbox]
[tree_view]
id = "side_list"
definition = "default"
vertical_scrollbar_mode = "always"
horizontal_scrollbar_mode = "never"
vertical_scrollbar_mode = "auto"
[header]
[node]
id = "team_header"
unfolded = true
[row]
grow_factor = 1
[node_definition]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 10
[row]
[spacer]
definition = "default"
linked_group = "side_number"
[/spacer]
[column]
grow_factor = 1
border = "all"
border_size = 10
horizontal_grow = "true"
[/column]
[label]
id = "tree_view_node_label"
definition = "default_large"
use_markup = "true"
[/label]
[column]
grow_factor = 1
border = "top,bottom"
border_size = 5
horizontal_alignment = "left"
[/column]
[label]
definition = "default_small"
label = _ "Leader"
linked_group = "leader"
[/label]
[/row]
[/column]
[/node_definition]
[column]
grow_factor = 0
border = "top,bottom"
border_size = 5
horizontal_alignment = "left"
[/node]
[label]
definition = "default_small"
label = _ "Player/Type"
linked_group = "controller"
[/label]
[node]
id = "side_panel"
unfolded = true
[/column]
[node_definition]
[column]
grow_factor = 0
border = "top,bottom"
border_size = 5
horizontal_alignment = "left"
[row]
[label]
definition = "default_small"
label = _ "Team/Color"
linked_group = "team_and_color"
[/label]
[column]
grow_factor = 0
border = "all"
border_size = 20
horizontal_grow = "true"
[/column]
[label]
id = "side_number"
definition = "default_huge"
linked_group = "side_number"
[/label]
[/column]
[column]
grow_factor = 0
border = "top,bottom"
border_size = 5
horizontal_alignment = "left"
[column]
grow_factor = 0
vertical_alignment = "center"
[label]
definition = "default_small"
label = _ "Gold/Income"
linked_group = "gold_and_income"
[/label]
[button]
id = "select_leader"
definition = "minimal_arrow"
[/button]
[/column]
[/column]
[/row]
[/header]
[list_definition]
[row]
[column]
horizontal_grow = "true"
vertical_grow = "true"
[toggle_panel]
id = "panel"
definition = "default"
[column]
grow_factor = 1
horizontal_grow = "true"
#vertical_grow = "true"
[grid]
linked_group = "leader"
[row]
[column]
grow_factor = 0
border = "all"
border_size = 20
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "side_number"
definition = "default_huge"
linked_group = "side_number"
[/label]
[/column]
[column]
grow_factor = 0
vertical_alignment = "center"
[button]
id = "select_leader"
definition = "minimal_arrow"
[/button]
[image]
id = "leader_image"
definition = "default"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
#vertical_grow = "true"
vertical_grow = "true"
[grid]
linked_group = "leader"
[row]
grow_factor = 1
[column]
grow_factor = 0
horizontal_grow = "true"
border = "all"
border_size = 5
[image]
id = "leader_image"
definition = "default"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
vertical_grow = "true"
[label]
id = "leader_type"
definition = "default_large"
use_markup = "true"
[/label]
[/column]
[/row]
[row]
grow_factor = 0
[column]
horizontal_grow = "true"
#vertical_grow = "true"
[grid]
[row]
grow_factor = 1
[column]
border = "all"
grow_factor = 0
border = "left,bottom"
border_size = 5
[label]
definition = "default_small"
label = _ "<b>Faction:</b>"
use_markup = "true"
[/label]
[/column]
[column]
grow_factor = 1
border = "left,bottom,right"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[label]
id = "leader_type"
definition = "default_large"
id = "leader_faction"
definition = "default_small"
use_markup = "true"
[/label]
@ -178,78 +161,31 @@
[/row]
[row]
grow_factor = 0
[column]
grow_factor = 0
border = "left,bottom"
border_size = 5
[label]
definition = "default_small"
label = _ "<b>Gender:</b>"
use_markup = "true"
[/label]
[/column]
[column]
grow_factor = 1
border = "left,bottom,right"
border_size = 5
horizontal_grow = "true"
#vertical_grow = "true"
vertical_grow = "true"
[grid]
[row]
[column]
grow_factor = 0
border = "left,bottom"
border_size = 5
[label]
definition = "default_small"
label = _ "<b>Faction:</b>"
use_markup = "true"
[/label]
[/column]
[column]
grow_factor = 1
border = "left,bottom,right"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[label]
id = "leader_faction"
definition = "default_small"
use_markup = "true"
[/label]
[/column]
[/row]
[row]
[column]
grow_factor = 0
border = "left,bottom"
border_size = 5
[label]
definition = "default_small"
label = _ "<b>Gender:</b>"
use_markup = "true"
[/label]
[/column]
[column]
grow_factor = 1
border = "left,bottom,right"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[image]
id = "leader_gender"
definition = "default_small"
[/image]
[/column]
[/row]
[/grid]
[image]
id = "leader_gender"
definition = "default_small"
[/image]
[/column]
@ -265,136 +201,45 @@
[/column]
[/row]
[/grid]
[/column]
[column]
grow_factor = 0
horizontal_grow = "true"
[grid]
linked_group = "controller"
[row]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[grid]
linked_group = "controller"
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[menu_button]
id = "controller"
definition = "default"
[/menu_button]
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[menu_button]
id = "ai_controller"
definition = "default"
[/menu_button]
[/column]
[/row]
[/grid]
[menu_button]
id = "controller"
definition = "default"
[/menu_button]
[/column]
[column]
grow_factor = 0
[/row]
[grid]
linked_group = "team_and_color"
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[menu_button]
id = "side_team"
definition = "default"
[/menu_button]
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[menu_button]
id = "side_color"
definition = "default"
[/menu_button]
[/column]
[/row]
[/grid]
[/column]
[row]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[grid]
linked_group = "gold_and_income"
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[slider]
id = "side_gold_slider"
definition = "short"
# TODO: the GUI1 dialog had a min of 20, but that meant the slider was never reaching max...
minimum_value = 25
maximum_value = 800
step_size = 25
[/slider]
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[slider]
id = "side_income_slider"
definition = "short"
minimum_value = -2
maximum_value = 18
step_size = 1
[/slider]
[/column]
[/row]
[/grid]
[menu_button]
id = "ai_controller"
definition = "default"
[/menu_button]
[/column]
@ -402,15 +247,142 @@
[/grid]
[/toggle_panel]
[/column]
[/column]
[column]
grow_factor = 0
[/row]
[grid]
linked_group = "team_and_color"
[/list_definition]
[row]
[/listbox]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[menu_button]
id = "side_team"
definition = "default"
[/menu_button]
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[menu_button]
id = "side_color"
definition = "default"
[/menu_button]
[/column]
[/row]
[/grid]
[/column]
[column]
grow_factor = 0
[grid]
linked_group = "gold_and_income"
[row]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
definition = "default_small"
label = _ "Gold:"
[/label]
[/column]
[column]
grow_factor = 1
border = "all"
border_size = 5
horizontal_grow = "true"
[slider]
id = "side_gold_slider"
definition = "short"
# TODO: the GUI1 dialog had a min of 20, but that meant the slider was never reaching max...
minimum_value = 25
maximum_value = 800
step_size = 25
[/slider]
[/column]
[/row]
[row]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
definition = "default_small"
label = _ "Income:"
[/label]
[/column]
[column]
grow_factor = 1
border = "all"
border_size = 5
horizontal_grow = "true"
[slider]
id = "side_income_slider"
definition = "short"
minimum_value = -2
maximum_value = 18
step_size = 1
[/slider]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/node_definition]
[/node]
[node]
id = "side_spacer"
unfolded = "true"
[node_definition]
{GUI_HORIZONTAL_SPACER_LINE}
[/node_definition]
[/node]
[/tree_view]
#enddef
#define _GUI_CONTROL_AREA
@ -425,52 +397,89 @@
horizontal_grow = "true"
vertical_grow = "true"
[listbox]
id = "player_list"
definition = "default"
[panel]
definition = "box_display_no_blur_no_border"
horizontal_scrollbar_mode = "never"
[list_definition]
[grid]
[row]
grow_factor = 0
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[toggle_panel]
id = "panel"
[label]
definition = "default"
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "player_name"
definition = "default"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
label = _ "Players"
[/label]
[/column]
[/row]
[/list_definition]
[row]
grow_factor = 1
[/listbox]
[column]
horizontal_grow = "true"
vertical_grow = "true"
[listbox]
id = "player_list"
definition = "default"
horizontal_scrollbar_mode = "never"
[list_definition]
[row]
[column]
horizontal_grow = "true"
[toggle_panel]
id = "panel"
definition = "default"
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "player_name"
definition = "default"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[/row]
[/grid]
[/panel]
[/column]
@ -518,11 +527,50 @@
[/grid]
#enddef
[window_definition]
id = "mp_staging"
description = "A simple window without border decorations and the ability to set a custom background."
{_GUI_RESOLUTION_BORDERLESS_BASE () 10 13 (
[image]
x = "(width - image_width)"
y = 0
w = "(image_width)"
h = "(height)"
# TODO: this should be generated with IPFs once we get a gradient function
name = "dialogs/multi_create/background.png"
[/image]
#
# Corners
#
[image]
x = 0
y = 0
w = "(image_width)"
h = "(image_height)"
name = "dialogs/multi_create/corner.png~ROTATE(90)"
[/image]
[image]
x = "(width - image_width)"
y = "(height - image_height)"
w = "(image_width)"
h = "(image_height)"
name = "dialogs/multi_create/corner.png~ROTATE(-90)"
[/image]
)}
[/window_definition]
[window]
id = "mp_staging"
description = "Game staging area."
[resolution]
# TODO: decide about background
#definition = "mp_staging"
definition = "borderless"
{GUI_WINDOW_FULLSCREEN}
@ -602,14 +650,33 @@
grow_factor = 1
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
{GUI_FORCE_WIDGET_MINIMUM_SIZE 0 "((screen_height * 55) / 100)" (
border = "all"
border_size = 5
{_GUI_SIDE_LIST}
)}
[panel]
definition = "box_display_no_blur_no_border"
[grid]
[row]
[column]
horizontal_grow = "true"
vertical_grow = "true"
{GUI_FORCE_WIDGET_MINIMUM_SIZE 0 "((screen_height * 55) / 100)" (
{_GUI_SIDE_LIST}
)}
[/column]
[/row]
[/grid]
[/panel]
[/column]
[/row]

View file

@ -226,6 +226,17 @@ public:
std::map<std::string, std::string> get_colors_pango() const;
std::string get_color(int index = -1) const;
int num_colors() const;
const std::string team_name() const
{
return parent_.team_names_[team_];
}
const std::string user_team_name() const
{
return t_string::from_serialized(parent_.user_team_names_[team_]);
}
private:
side_engine(const side_engine& engine) = delete;
void operator=(const side_engine&) = delete;

View file

@ -36,6 +36,8 @@
#include "gui/widgets/slider.hpp"
#include "gui/widgets/status_label_helper.hpp"
#include "gui/widgets/toggle_panel.hpp"
#include "gui/widgets/tree_view.hpp"
#include "gui/widgets/tree_view_node.hpp"
#include "mp_ui_alerts.hpp"
#include "units/types.hpp"
#include "wesnothd_connection.hpp"
@ -52,6 +54,8 @@ tmp_staging::tmp_staging(ng::connect_engine& connect_engine, lobby_info& lobby_i
, wesnothd_connection_(wesnothd_connection)
, update_timer_(0)
, state_changed_(false)
, team_tree_map_()
, side_tree_map_()
{
set_show_even_without_video(true);
@ -81,156 +85,28 @@ void tmp_staging::pre_show(twindow& window)
//
// Set up sides list
//
tlistbox& list = find_widget<tlistbox>(&window, "side_list", false);
ttree_view& tree = find_widget<ttree_view>(&window, "side_list", false);
window.keyboard_capture(&list);
for(const auto& side_ptr : connect_engine_.side_engines()) {
// Shorthand variable
ng::side_engine& side = *side_ptr.get();
if(!side.allow_player() && !game_config::debug) {
for(const auto& side : connect_engine_.side_engines()) {
if(!side->allow_player() && !game_config::debug) {
continue;
}
std::map<std::string, string_map> data;
string_map item;
// Check to see whether we've added a toplevel tree node for this team. If not, add one
if(team_tree_map_.find(side->team_name()) == team_tree_map_.end()) {
std::map<std::string, string_map> data;
string_map item;
item["label"] = std::to_string(side.index() + 1);
data.emplace("side_number", item);
item["label"] = (formatter() << _("Team:") << " " << side->user_team_name()).str();
data.emplace("tree_view_node_label", item);
// TODO: don't hardcode meganta?
item["label"] = "units/unknown-unit.png~RC(magenta>" + std::to_string(side.color() + 1) + ")";
data.emplace("leader_image", item);
ttree_view_node& team_node = tree.add_node("team_header", data);
team_node.add_sibling("side_spacer", {});
item["label"] = "icons/icon-random.png";
data.emplace("leader_gender", item);
tgrid& row_grid = list.add_row(data);
update_leader_display(side, row_grid);
// Status variables
const bool fls = connect_engine_.force_lock_settings();
const bool ums = connect_engine_.params().use_map_settings;
const bool lock_gold = side.cfg()["gold_lock"].to_bool(fls);
const bool lock_income = side.cfg()["income_lock"].to_bool(fls);
const bool lock_team = side.cfg()["team_lock"].to_bool(fls);
const bool lock_color = side.cfg()["color_lock"].to_bool(fls);
const bool saved_game = connect_engine_.params().saved_game;
//
// AI Algorithm
//
int selection = 0;
// We use an index-based loop in order to get the index of the selected option
std::vector<config> ai_options;
for(unsigned i = 0; i < ai_algorithms_.size(); i++) {
ai_options.push_back(config_of("label", ai_algorithms_[i]->text));
if(ai_algorithms_[i]->id == side.ai_algorithm()) {
selection = i;
}
team_tree_map_[side->team_name()] = &team_node;
}
tmenu_button& ai_selection = find_widget<tmenu_button>(&row_grid, "ai_controller", false);
ai_selection.set_values(ai_options, selection);
ai_selection.connect_click_handler(std::bind(&tmp_staging::on_ai_select, this, std::ref(side), std::ref(ai_selection)));
on_ai_select(side, ai_selection);
//
// Controller
//
std::vector<config> controller_names;
for(const auto& controller : side.controller_options()) {
controller_names.push_back(config_of("label", controller.second));
}
tmenu_button& controller_selection = find_widget<tmenu_button>(&row_grid, "controller", false);
controller_selection.set_values(controller_names, side.current_controller_index());
controller_selection.set_active(controller_names.size() > 1);
controller_selection.connect_click_handler(std::bind(&tmp_staging::on_controller_select, this, std::ref(side), std::ref(row_grid)));
on_controller_select(side, row_grid);
//
// Leader controls
//
connect_signal_mouse_left_click(
find_widget<tbutton>(&row_grid, "select_leader", false),
std::bind(&tmp_staging::select_leader_callback, this, std::ref(window), std::ref(side), std::ref(row_grid)));
//
// Team
//
std::vector<config> team_names;
for(const auto& team : side.player_teams()) {
team_names.push_back(config_of("label", team));
}
tmenu_button& team_selection = find_widget<tmenu_button>(&row_grid, "side_team", false);
// HACK: side.team() does not get its index from side.player_teams(), but rather side.team_names().
// As such, the index is off if there is only 1 playable team. This is a hack to make sure the menu_button
// widget doesn't assert with the invalid initial selection. The connect_engine should be fixed once the GUI1
// dialog is dropped
team_selection.set_values(team_names, std::min<int>(team_names.size() - 1, side.team()));
team_selection.set_active(!saved_game);
team_selection.connect_click_handler(std::bind(&tmp_staging::on_team_select, this, std::ref(side), std::ref(team_selection)));
//
// Colors
//
std::vector<config> color_options;
for(const auto& color : side.get_colors_pango()) {
color_options.push_back(config_of
("label", color.second)
("icon", (formatter() << "misc/status.png~RC(magenta>" << color.first << ")").str())
);
}
tmenu_button& color_selection = find_widget<tmenu_button>(&row_grid, "side_color", false);
color_selection.set_values(color_options, side.color());
color_selection.set_active(!saved_game);
color_selection.set_use_markup(true);
color_selection.connect_click_handler(std::bind(&tmp_staging::on_color_select, this, std::ref(side), std::ref(row_grid)));
//
// Gold and Income
//
tslider& slider_gold = find_widget<tslider>(&row_grid, "side_gold_slider", false);
slider_gold.set_value(side.cfg()["gold"].to_int(100));
connect_signal_notify_modified(slider_gold, std::bind([&]() { side.set_gold(slider_gold.get_value()); set_state_changed(); }));
tslider& slider_income = find_widget<tslider>(&row_grid, "side_income_slider", false);
slider_income.set_value(side.cfg()["income"]);
connect_signal_notify_modified(slider_income, std::bind([&]() { side.set_income(slider_income.get_value()); set_state_changed(); }));
// TODO: hide header, or maybe display the saved values
if(saved_game) {
slider_gold.set_visible(twidget::tvisible::invisible);
slider_income.set_visible(twidget::tvisible::invisible);
}
//
// Gold, income, team, and color are only suggestions unless explicitly locked
//
if(ums) {
team_selection.set_active(!lock_team);
color_selection.set_active(!lock_color);
slider_gold.set_active(!lock_gold);
slider_income.set_active(!lock_income);
}
add_side_node(window, side);
}
//
@ -269,6 +145,152 @@ void tmp_staging::pre_show(twindow& window)
plugins_context_->set_callback("chat", [&chat](const config& cfg) { chat.send_chat_message(cfg["message"], false); }, true);
}
void tmp_staging::add_side_node(twindow& window, ng::side_engine_ptr side)
{
std::map<std::string, string_map> data;
string_map item;
item["label"] = std::to_string(side->index() + 1);
data.emplace("side_number", item);
// TODO: don't hardcode meganta?
item["label"] = "units/unknown-unit.png~RC(magenta>" + std::to_string(side->color() + 1) + ")";
data.emplace("leader_image", item);
item["label"] = "icons/icon-random.png";
data.emplace("leader_gender", item);
ttree_view_node& node = team_tree_map_[side->team_name()]->add_child("side_panel", data);
side_tree_map_.emplace(side, &node);
tgrid& row_grid = node.get_grid();
update_leader_display(side, row_grid);
// Status variables
const bool fls = connect_engine_.force_lock_settings();
const bool ums = connect_engine_.params().use_map_settings;
const bool lock_gold = side->cfg()["gold_lock"].to_bool(fls);
const bool lock_income = side->cfg()["income_lock"].to_bool(fls);
const bool lock_team = side->cfg()["team_lock"].to_bool(fls);
const bool lock_color = side->cfg()["color_lock"].to_bool(fls);
const bool saved_game = connect_engine_.params().saved_game;
//
// AI Algorithm
//
int selection = 0;
// We use an index-based loop in order to get the index of the selected option
std::vector<config> ai_options;
for(unsigned i = 0; i < ai_algorithms_.size(); i++) {
ai_options.push_back(config_of("label", ai_algorithms_[i]->text));
if(ai_algorithms_[i]->id == side->ai_algorithm()) {
selection = i;
}
}
tmenu_button& ai_selection = find_widget<tmenu_button>(&row_grid, "ai_controller", false);
ai_selection.set_values(ai_options, selection);
ai_selection.connect_click_handler(std::bind(&tmp_staging::on_ai_select, this, std::ref(side), std::ref(ai_selection)));
on_ai_select(side, ai_selection);
//
// Controller
//
std::vector<config> controller_names;
for(const auto& controller : side->controller_options()) {
controller_names.push_back(config_of("label", controller.second));
}
tmenu_button& controller_selection = find_widget<tmenu_button>(&row_grid, "controller", false);
controller_selection.set_values(controller_names, side->current_controller_index());
controller_selection.set_active(controller_names.size() > 1);
controller_selection.connect_click_handler(std::bind(&tmp_staging::on_controller_select, this, std::ref(side), std::ref(row_grid)));
on_controller_select(side, row_grid);
//
// Leader controls
//
connect_signal_mouse_left_click(
find_widget<tbutton>(&row_grid, "select_leader", false),
std::bind(&tmp_staging::select_leader_callback, this, std::ref(window), std::ref(side), std::ref(row_grid)));
//
// Team
//
std::vector<config> team_names;
for(const auto& team : side->player_teams()) {
team_names.push_back(config_of("label", team));
}
tmenu_button& team_selection = find_widget<tmenu_button>(&row_grid, "side_team", false);
// HACK: side->team() does not get its index from side->player_teams(), but rather side->team_names().
// As such, the index is off if there is only 1 playable team. This is a hack to make sure the menu_button
// widget doesn't assert with the invalid initial selection. The connect_engine should be fixed once the GUI1
// dialog is dropped
team_selection.set_values(team_names, std::min<int>(team_names.size() - 1, side->team()));
team_selection.set_active(!saved_game);
team_selection.connect_click_handler(std::bind(&tmp_staging::on_team_select, this, std::ref(window), std::ref(side), std::ref(team_selection), _3, _4));
//
// Colors
//
std::vector<config> color_options;
for(const auto& color : side->get_colors_pango()) {
color_options.push_back(config_of
("label", color.second)
("icon", (formatter() << "misc/status.png~RC(magenta>" << color.first << ")").str())
);
}
tmenu_button& color_selection = find_widget<tmenu_button>(&row_grid, "side_color", false);
color_selection.set_values(color_options, side->color());
color_selection.set_active(!saved_game);
color_selection.set_use_markup(true);
color_selection.connect_click_handler(std::bind(&tmp_staging::on_color_select, this, std::ref(side), std::ref(row_grid)));
//
// Gold and Income
//
tslider& slider_gold = find_widget<tslider>(&row_grid, "side_gold_slider", false);
slider_gold.set_value(side->cfg()["gold"].to_int(100));
connect_signal_notify_modified(slider_gold, std::bind([&]() { side->set_gold(slider_gold.get_value()); set_state_changed(); }));
tslider& slider_income = find_widget<tslider>(&row_grid, "side_income_slider", false);
slider_income.set_value(side->cfg()["income"]);
connect_signal_notify_modified(slider_income, std::bind([&]() { side->set_income(slider_income.get_value()); set_state_changed(); }));
// TODO: hide header, or maybe display the saved values
if(saved_game) {
slider_gold.set_visible(twidget::tvisible::invisible);
slider_income.set_visible(twidget::tvisible::invisible);
}
//
// Gold, income, team, and color are only suggestions unless explicitly locked
//
if(ums) {
team_selection.set_active(!lock_team);
color_selection.set_active(!lock_color);
slider_gold.set_active(!lock_gold);
slider_income.set_active(!lock_income);
}
}
void tmp_staging::update_player_list(twindow& window)
{
tlistbox& player_list = find_widget<tlistbox>(&window, "player_list", false);
@ -286,44 +308,53 @@ void tmp_staging::update_player_list(twindow& window)
}
}
void tmp_staging::on_controller_select(ng::side_engine& side, tgrid& row_grid)
void tmp_staging::on_controller_select(ng::side_engine_ptr side, tgrid& row_grid)
{
tmenu_button& ai_selection = find_widget<tmenu_button>(&row_grid, "ai_controller", false);
tmenu_button& controller_selection = find_widget<tmenu_button>(&row_grid, "controller", false);
if(side.controller_changed(controller_selection.get_value())) {
ai_selection.set_visible(side.controller() == ng::CNTR_COMPUTER ? twidget::tvisible::visible : twidget::tvisible::hidden);
if(side->controller_changed(controller_selection.get_value())) {
ai_selection.set_visible(side->controller() == ng::CNTR_COMPUTER ? twidget::tvisible::visible : twidget::tvisible::hidden);
set_state_changed();
}
}
void tmp_staging::on_ai_select(ng::side_engine& side, tmenu_button& ai_menu)
void tmp_staging::on_ai_select(ng::side_engine_ptr side, tmenu_button& ai_menu)
{
side.set_ai_algorithm(ai_algorithms_[ai_menu.get_value()]->id);
side->set_ai_algorithm(ai_algorithms_[ai_menu.get_value()]->id);
set_state_changed();
}
void tmp_staging::on_color_select(ng::side_engine& side, tgrid& row_grid)
void tmp_staging::on_color_select(ng::side_engine_ptr side, tgrid& row_grid)
{
side.set_color(find_widget<tmenu_button>(&row_grid, "side_color", false).get_value());
side->set_color(find_widget<tmenu_button>(&row_grid, "side_color", false).get_value());
update_leader_display(side, row_grid);
set_state_changed();
}
void tmp_staging::on_team_select(ng::side_engine& side, tmenu_button& team_menu)
void tmp_staging::on_team_select(twindow& window, ng::side_engine_ptr side, tmenu_button& team_menu, bool& handled, bool& halt)
{
side.set_team(team_menu.get_value());
side->set_team(team_menu.get_value());
// First, remove the node from the tree
find_widget<ttree_view>(&window, "side_list", false).remove_node(side_tree_map_[side]);
// Then add a new node as a child to the appropriate team's node
add_side_node(window, side);
set_state_changed();
handled = true;
halt = true;
}
void tmp_staging::select_leader_callback(twindow& window, ng::side_engine& side, tgrid& row_grid)
void tmp_staging::select_leader_callback(twindow& window, ng::side_engine_ptr side, tgrid& row_grid)
{
gui2::tfaction_select dlg(side.flg(), std::to_string(side.color() + 1), side.index() + 1);
gui2::tfaction_select dlg(side->flg(), std::to_string(side->color() + 1), side->index() + 1);
dlg.show(window.video());
if(dlg.get_retval() == twindow::OK) {
@ -333,20 +364,20 @@ void tmp_staging::select_leader_callback(twindow& window, ng::side_engine& side,
}
}
void tmp_staging::update_leader_display(ng::side_engine& side, tgrid& row_grid)
void tmp_staging::update_leader_display(ng::side_engine_ptr side, tgrid& row_grid)
{
const std::string current_faction = (*side.flg().choosable_factions()[side.flg().current_faction_index()])["name"];
const std::string current_faction = (*side->flg().choosable_factions()[side->flg().current_faction_index()])["name"];
// BIG FAT TODO: get rid of this shitty "null" string value in the FLG manager
std::string current_leader = side.flg().current_leader() != "null" ? side.flg().current_leader() : utils::unicode_em_dash;
const std::string current_gender = side.flg().current_gender() != "null" ? side.flg().current_gender() : utils::unicode_em_dash;
std::string current_leader = side->flg().current_leader() != "null" ? side->flg().current_leader() : utils::unicode_em_dash;
const std::string current_gender = side->flg().current_gender() != "null" ? side->flg().current_gender() : utils::unicode_em_dash;
// Sprite
std::string new_image = "units/random-dice.png";
if(!side.flg().is_random_faction() && current_leader != "random") {
if(!side->flg().is_random_faction() && current_leader != "random") {
const unit_type& type = unit_types.find(current_leader)->get_gender_unit_type(current_gender);
new_image = formatter() << type.image() << "~RC(magenta>" << side.color() + 1 << ")";
new_image = formatter() << type.image() << "~RC(magenta>" << side->color() + 1 << ")";
// We don't need the unit type id anymore, and can now replace this variable with the type name
current_leader = type.type_name();
@ -355,8 +386,8 @@ void tmp_staging::update_leader_display(ng::side_engine& side, tgrid& row_grid)
find_widget<timage>(&row_grid, "leader_image", false).set_label(new_image);
// Faction and leader
if(!side.cfg()["name"].empty()) {
current_leader = formatter() << side.cfg()["name"] << " (<i>" << current_leader << "</i>)";
if(!side->cfg()["name"].empty()) {
current_leader = formatter() << side->cfg()["name"] << " (<i>" << current_leader << "</i>)";
}
find_widget<tlabel>(&row_grid, "leader_type", false).set_label(current_leader);
@ -414,21 +445,21 @@ void tmp_staging::network_handler(twindow& window)
// Update side leader displays
// This is basically only needed when a new player joins and selects their faction
for(unsigned i = 0; i < connect_engine_.side_engines().size(); i++) {
tgrid& row_grid = *find_widget<tlistbox>(&window, "side_list", false).get_row_grid(i);
for(auto& tree_entry : side_tree_map_) {
ng::side_engine_ptr side = tree_entry.first;
ng::side_engine& side = *connect_engine_.side_engines()[i].get();
tgrid& row_grid = tree_entry.second->get_grid();
update_leader_display(side, row_grid);
std::vector<config> controller_names;
for(const auto& controller : side.controller_options()) {
for(const auto& controller : side->controller_options()) {
controller_names.push_back(config_of("label", controller.second));
}
tmenu_button& controller_selection = find_widget<tmenu_button>(&row_grid, "controller", false);
controller_selection.set_values(controller_names, side.current_controller_index());
controller_selection.set_values(controller_names, side->current_controller_index());
controller_selection.set_active(controller_names.size() > 1);
}
@ -446,6 +477,11 @@ void tmp_staging::network_handler(twindow& window)
void tmp_staging::post_show(twindow& window)
{
if(update_timer_ != 0) {
remove_timer(update_timer_);
update_timer_ = 0;
}
if(window.get_retval() == twindow::OK) {
connect_engine_.start_game();
} else {

View file

@ -28,12 +28,8 @@ class config;
namespace gui2
{
class ttoggle_button;
class ttoggle_panel;
class tslider;
class tlabel;
class tmenu_button;
class twidget;
class ttree_view_node;
class tmp_staging : public tdialog, private plugin_executor
{
@ -52,26 +48,26 @@ private:
/** Inherited from tdialog. */
void post_show(twindow& window);
void add_side_node(twindow& window, ng::side_engine_ptr side);
void on_controller_select(ng::side_engine_ptr side, tgrid& row_grid);
void on_ai_select(ng::side_engine_ptr side, tmenu_button& ai_menu);
void on_color_select(ng::side_engine_ptr side, tgrid& row_grid);
void on_team_select(twindow& window, ng::side_engine_ptr side, tmenu_button& team_menu, bool& handled, bool& halt);
void select_leader_callback(twindow& window, ng::side_engine_ptr side, tgrid& row_grid);
void update_player_list(twindow& window);
void update_leader_display(ng::side_engine_ptr side, tgrid& row_grid);
void update_status_label_and_buttons(twindow& window);
void network_handler(twindow& window);
void set_state_changed()
{
state_changed_ = true;
};
void on_controller_select(ng::side_engine& side, tgrid& row_grid);
void on_ai_select(ng::side_engine& side, tmenu_button& ai_menu);
void on_color_select(ng::side_engine& side, tgrid& row_grid);
void on_team_select(ng::side_engine& side, tmenu_button& team_menu);
void select_leader_callback(twindow& window, ng::side_engine& side, tgrid& row_grid);
void update_leader_display(ng::side_engine& side, tgrid& row_grid);
void update_status_label_and_buttons(twindow& window);
void network_handler(twindow& window);
ng::connect_engine& connect_engine_;
std::vector<ai::description*> ai_algorithms_;
@ -83,6 +79,9 @@ private:
size_t update_timer_;
bool state_changed_;
std::map<std::string, ttree_view_node*> team_tree_map_;
std::map<ng::side_engine_ptr, ttree_view_node*> side_tree_map_;
};
} // namespace gui2