Implemented the [unit_input] message subtag...

...and replaced the old recruit dialog with a gui2 one.
This commit is contained in:
Fabian Müller 2011-02-11 19:01:16 +00:00
parent 0278e8b181
commit 7725e75a07
5 changed files with 524 additions and 15 deletions

View file

@ -289,6 +289,162 @@
[/listbox]
#enddef
#define _GUI_UNIT_LIST
[listbox]
id = "unit_list"
definition = "wml_message"
[list_definition]
[row]
[column]
grow_factor = 1
horizontal_grow = "true"
[toggle_panel]
definition = "wml_message"
return_value_id = "ok"
[grid]
[row]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 5
[image]
id = "icon"
definition = "default"
linked_group = "icon"
[/image]
[/column]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 5
[label]
id = "type"
definition = "default"
linked_group = "type"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "name"
definition = "default"
linked_group = "name"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "level"
definition = "default"
linked_group = "level"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "xp"
definition = "default"
linked_group = "xp"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "traits"
definition = "default"
linked_group = "traits"
[/label]
[/column]
[column]
grow_factor = 0
horizontal_alignment = "left"
border = "all"
border_size = 5
[label]
id = "label"
definition = "default"
linked_group = "label"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "description"
definition = "default"
linked_group = "description"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
#enddef
[window]
id = "wml_message_left"
description = "Dialog showing a unit portrait on the left side"
@ -323,6 +479,42 @@
fixed_width = "true"
[/linked_group]
[linked_group]
id = "traits"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "xp"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "type"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "cost"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "level"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "name"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "usage"
fixed_width = "true"
[/linked_group]
[grid]
[row]
@ -452,6 +644,20 @@
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
{_GUI_UNIT_LIST}
[/column]
[/row]
[row]
@ -673,6 +879,19 @@ if(gamemap_width - ({__GUI_IMAGE_WIDTH}) > {MAX_TEXT_WIDTH}
[/column]
[/row]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
{_GUI_UNIT_LIST}
[/column]
[/row]
[row]

View file

@ -2446,12 +2446,14 @@ struct message_user_choice : mp_sync::user_choice
unit_map::iterator speaker;
vconfig text_input_element;
bool has_text_input;
vconfig unit_input_element;
bool has_unit_input;
const std::vector<std::string> &options;
message_user_choice(const vconfig &c, const unit_map::iterator &s,
const vconfig &t, bool ht, const std::vector<std::string> &o)
const vconfig &t, bool ht, const vconfig &u, bool hu, const std::vector<std::string> &o)
: cfg(c), speaker(s), text_input_element(t)
, has_text_input(ht), options(o)
, has_text_input(ht), unit_input_element(u), has_unit_input(hu), options(o)
{}
virtual config query_user() const
@ -2475,12 +2477,35 @@ struct message_user_choice : mp_sync::user_choice
input_max_size = 256;
}
// TODO Parse unit input, here?
std::string unit_input_content; // = unit_input_element[""]; // default?
std::string unit_input_types = unit_input_element["types"];
std::vector<unit> unit_list;
if (has_unit_input) {
const config empty_filter;
vconfig filter = unit_input_element.child("filter");
// if(filter.null()) {
// filter = empty_filter;
// lg::wml_error << "[unit_input] missing required [filter] tag\n";
// }
for(unit_map::iterator i = resources::units->begin(); i != resources::units->end(); i++) {
if(game_events::unit_matches_filter(*i,filter) == true) {
unit_list.push_back(*i);
}
}
unit_input_content = unit_list.front().id();
}
int option_chosen;
int dlg_result = gui2::show_wml_message(left_side,
resources::screen->video(), caption, cfg["message"],
image, false, has_text_input, text_input_label,
&text_input_content, input_max_size, options,
&option_chosen);
&text_input_content, input_max_size,
has_unit_input, &unit_input_content, unit_list,
options, &option_chosen);
/* Since gui2::show_wml_message needs to do undrawing the
chatlines can get garbled and look dirty on screen. Force a
@ -2496,6 +2521,7 @@ struct message_user_choice : mp_sync::user_choice
config cfg;
if (!options.empty()) cfg["value"] = option_chosen;
if (has_text_input) cfg["text"] = text_input_content;
if (has_unit_input) cfg["unit"] = unit_input_content;
return cfg;
}
@ -2510,11 +2536,12 @@ WML_HANDLER_FUNCTION(message, event_info, cfg)
{
// Check if there is any input to be made, if not the message may be skipped
const vconfig::child_list menu_items = cfg.get_children("option");
const vconfig::child_list unit_input_elements = cfg.get_children("unit_input");
const vconfig::child_list text_input_elements = cfg.get_children("text_input");
const bool has_text_input = (text_input_elements.size() == 1);
const bool has_unit_input = (unit_input_elements.size() == 1);
bool has_input= (has_text_input || !menu_items.empty() );
const bool has_input = (has_text_input || has_unit_input || !menu_items.empty() );
// skip messages during quick replay
play_controller *controller = resources::controller;
@ -2584,7 +2611,8 @@ WML_HANDLER_FUNCTION(message, event_info, cfg)
}
}
has_input = !options.empty() || has_text_input;
//TODO I think that redeclaration of has_input is obsolete and dangerous
//has_input = !options.empty() || has_text_input;
if (!has_input && get_replay_source().is_skipping()) {
// No input to get and the user is not interested either.
return;
@ -2598,15 +2626,23 @@ WML_HANDLER_FUNCTION(message, event_info, cfg)
lg::wml_error << "too many text_input tags, only one accepted\n";
}
if(unit_input_elements.size()>1) {
lg::wml_error << "too many unit_input tags, only one accepted\n";
}
const vconfig text_input_element = has_text_input ?
text_input_elements.front() : vconfig::empty_vconfig();
const vconfig unit_input_element = has_unit_input ?
unit_input_elements.front() : vconfig::empty_vconfig();
int option_chosen = 0;
std::string unit_input_result;
std::string text_input_result;
DBG_DP << "showing dialog...\n";
message_user_choice msg(cfg, speaker, text_input_element, has_text_input,
message_user_choice msg(cfg, speaker, text_input_element, has_text_input, unit_input_element, has_unit_input,
options);
if (!has_input)
{
@ -2618,6 +2654,7 @@ WML_HANDLER_FUNCTION(message, event_info, cfg)
{
config choice = mp_sync::get_user_choice("input", msg, 0, true);
option_chosen = choice["value"];
unit_input_result = choice["unit"].str();
text_input_result = choice["text"].str();
}
@ -2642,6 +2679,12 @@ WML_HANDLER_FUNCTION(message, event_info, cfg)
variable_name="input";
resources::state_of_game->set_variable(variable_name, text_input_result);
}
if(has_unit_input) {
std::string variable_name=unit_input_element["variable"];
if(variable_name.empty())
variable_name="unit_input";
resources::state_of_game->set_variable(variable_name, unit_input_result);
}
}
// Adding/removing new time_areas dynamically with Standard Location Filters.

View file

@ -18,6 +18,7 @@
#include "gui/dialogs/wml_message.hpp"
#include "foreach.hpp"
#include "gui/dialogs/helper.hpp"
#include "gui/auxiliary/old_markup.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/label.hpp"
@ -30,8 +31,49 @@
#include "gui/widgets/text_box.hpp"
#include "gui/widgets/window.hpp"
//TODO let's see if we need all of those
#include "resources.hpp"
#include "game_display.hpp"
#include "map.hpp"
#include "help.hpp"
#include "gettext.hpp" //could be done in menu_events
namespace gui2 {
//should be active in every dialog that involves units.
void twml_message_::profile_pressed() {
assert(chosen_unit_);
const unit_type& t = *chosen_unit_->type();
help::show_unit_help(*resources::screen, t.id(), t.hide_help());
}
//TODO this is very specific, might need to go into another class
void twml_message_::help_pressed() {
help::show_help(*resources::screen,"recruit_and_recall");
}
void twml_message_::update_unit_list(twindow& window) {
tlistbox& unit_listbox = find_widget<tlistbox> (&window, "unit_list", false);
//TODO this hack does not respect the sorting of the list.
chosen_unit_ = &unit_list_[unit_listbox.get_selected_row()];
const map_location& loc = chosen_unit_->get_location();
if (resources::game_map->on_board(loc)) {
resources::screen->highlight_hex(loc);
//TODO is false better?
resources::screen->scroll_to_tile(loc,
game_display::SCROLL, true);
} else {
//TODO add code to draw units we can't scroll to.
}
window.canvas(1).set_variable("portrait_image", variant(
chosen_unit_->big_profile()));
window.set_dirty();
}
void twml_message_::set_input(const std::string& caption,
std::string* text, const unsigned maximum_length)
{
@ -53,6 +95,38 @@ void twml_message_::set_option_list(
chosen_option_ = chosen_option;
}
void twml_message_::set_unit_list(
const std::vector<unit>& unit_list, std::string* unit_id)
{
assert(unit_id);
assert(!unit_list.empty());
unit_id_ = unit_id;
unit_list_ = unit_list;
}
void twml_message_::set_type_list(
std::vector<const unit_type*> type_list, std::string* type_id, int side_num, int gold)
{
assert(!type_list.empty());
assert(type_id);
gold_ = gold;
unit_id_ = type_id;
std::vector<const unit_type*>::const_iterator it;
it = type_list.begin();
for (it = type_list.begin(); it != type_list.end(); it++)
{
// TODO false is the right value
//unit new_unit(*it, side_num, false);
unit new_unit(*it, side_num, true);
//new_unit.set_
unit_list_.push_back(new_unit);
}
}
/**
* @todo This function enables the wml markup for all items, but the interface
* is a bit hacky. Especially the fiddling in the internals of the listbox is
@ -94,6 +168,71 @@ void twml_message_::pre_show(CVideo& /*video*/, twindow& window)
input.set_visible(twidget::INVISIBLE);
}
// Find the unit list related fields:
tlistbox& units = find_widget<tlistbox>(&window, "unit_list", true);
units.set_callback_value_change(dialog_callback<twml_message_,
&twml_message_::update_unit_list> );
if(!unit_list_.empty()) {
std::map<std::string, string_map> data;
for(size_t i = 0; i < unit_list_.size(); ++i) {
unit& unit = unit_list_[i];
bool affordable = unit.cost() <= gold_ ;
std::string unit_mod = affordable ? unit.image_mods() : "~GS()" ;
std::string icon = (unit.absolute_image() + unit_mod);
std::string type = unit.type_name();
std::string name = unit.name();
//TODO handle traits in another way
//std::string traits = unit.trait_descriptions();
std::ostringstream level;
std::ostringstream xp;
xp << unit.experience() << "/" << unit.max_experience();
// Show units of level (0=gray, 1 normal, 2 bold, 2+ bold&wbright)
const int level_number = unit.level();
//TODO enabe the switch construct after replacing the font::NORMAL_TEXT etc.
// switch(level_number)
// {
// case 0: level << "<150,150,150>";
// break;
// case 1: level << font::NORMAL_TEXT;
// break;
// case 2: level << font::BOLD_TEXT;
// break;
// default: level << font::BOLD_TEXT << "<255,255,255>";
// }
level << level_number;
std::string gold_color;
gold_color = affordable ? "green" : "red" ;
std::ostringstream cost;
cost << "<span color=\"" << gold_color << "\">" << unit.cost() << " " << "Gold" << "</span>" ;
// Add the data.
data["cost"]["label"] = cost.str();
data["cost"]["use_markup"] = "true";
data["usage"]["label"] = unit.usage();
data["icon"]["label"] = icon;
data["icon"]["use_markup"] = "true";
data["name"]["label"] = name;
data["type"]["label"] = type;
data["label"]["use_markup"] = "true";
data["level"]["label"] = level.str();
data["xp"]["label"] = xp.str();
//data["traits"]["label"] = unit.traits_description();
units.add_row(data);
}
} else {
units.set_visible(twidget::INVISIBLE);
}
// Find the option list related fields.
tlistbox& options = find_widget<tlistbox>(&window, "input_list", true);
@ -140,7 +279,7 @@ void twml_message_::pre_show(CVideo& /*video*/, twindow& window)
} else {
options.set_visible(twidget::INVISIBLE);
}
window.set_click_dismiss(!has_input_ && option_list_.empty());
window.set_click_dismiss(!has_input_ && option_list_.empty() && unit_list_.empty());
}
void twml_message_::post_show(twindow& window)
@ -151,8 +290,12 @@ void twml_message_::post_show(twindow& window)
}
if(!option_list_.empty()) {
*chosen_option_ = find_widget<tlistbox>(
&window, "input_list", true).get_selected_row();
*chosen_option_ =
find_widget<tlistbox>(&window, "input_list", true).get_selected_row();
}
if(!unit_list_.empty()) {
*unit_id_ = chosen_unit_->type_id();
}
}
@ -160,6 +303,32 @@ REGISTER_DIALOG(wml_message_left)
REGISTER_DIALOG(wml_message_right)
int show_recruit_message(const bool left_side
, CVideo& video
, std::vector<const unit_type*> type_list
, std::string* type_id
, int side_num
, int gold)
{
const std::string title = _("Recruit");
const std::string message = _("Select unit:");
//TODO correct fetching the portrait
const std::string portrait = "";//type_list.begin()->big_profile(); //.begin().big_profile();
const bool mirror = false;
std::auto_ptr<twml_message_> dlg;
if(left_side) {
dlg.reset(new twml_message_left(title, message, portrait, mirror));
} else {
dlg.reset(new twml_message_right(title, message, portrait, mirror));
}
assert(dlg.get());
dlg->set_type_list(type_list, type_id, side_num, gold);
dlg->show(video);
return dlg->get_retval();
}
int show_wml_message(const bool left_side
, CVideo& video
, const std::string& title
@ -170,6 +339,9 @@ int show_wml_message(const bool left_side
, const std::string& input_caption
, std::string* input_text
, const unsigned maximum_length
, const bool has_unit
, std::string* unit_id
, const std::vector<unit>& unit_list
, const std::vector<std::string>& option_list
, int* chosen_option)
{
@ -185,6 +357,10 @@ int show_wml_message(const bool left_side
dlg->set_input(input_caption, input_text, maximum_length);
}
if(has_unit) {
dlg->set_unit_list(unit_list, unit_id);
}
if(!option_list.empty()) {
dlg->set_option_list(option_list, chosen_option);
}

View file

@ -17,6 +17,8 @@
#define GUI_DIALOGS_WML_MESSAGE_HPP_INCLUDED
#include "gui/dialogs/dialog.hpp"
//TODO get rid of this here
#include "unit.hpp"
namespace gui2 {
@ -56,11 +58,46 @@ public:
void set_input(const std::string& caption,
std::string* text, const unsigned maximum_length);
/**
* Sets the option list.
*
* @param option_list Vector of options to choice from.
* @param chosen_option Number of the option that was chosen.
*/
void set_option_list(
const std::vector<std::string>& option_list, int* chosen_option);
/**
* Sets the unit list.
*
* @param unit_list TODO
* @param chosen_unit TODO
*/
void set_unit_list(
const std::vector<unit>& unit_list, std::string* chosen_unit);
/**
* Sets the type list
*
* @param type_list TODO
* @param type_id TODO
* @param side_num TODO
* @param gold TODO
*/
void set_type_list(
std::vector<const unit_type*> type_list, std::string* type_id, int side_num, int gold);
private:
/** Handler for changed unit selection. */
void update_unit_list(twindow& window);
/** Handler for the profile button event. */
void profile_pressed();
/** Handler for the help button event */
void help_pressed();
/** The title for the dialog. */
std::string title_;
@ -91,12 +128,27 @@ private:
/** The maximum length of the input text. */
unsigned input_maximum_lenght_;
/** The list of options the user can choose. */
/** The unit id. */
std::string* unit_id_;
/** The list of units the player can choose. */
std::vector<unit> unit_list_;
/** The list of unit_types the player can choose. */
//std::vector<const unit_type*> type_list_;
/** The list of options the player can choose. */
std::vector<std::string> option_list_;
/** The chosen option. */
int *chosen_option_;
/** The chosen unit. */
unit *chosen_unit_;
/** Gold */
int gold_;
/** Inherited from tdialog. */
void pre_show(CVideo& video, twindow& window);
@ -161,6 +213,13 @@ private:
* Will be set to the chosen_option when the
* dialog closes.
*/
int show_recruit_message(const bool left_side
, CVideo& video
, std::vector<const unit_type*> type_list
, std::string* type_id
, int side_num
, int gold);
int show_wml_message(const bool left_side
, CVideo& video
, const std::string& title
@ -171,6 +230,9 @@ int show_wml_message(const bool left_side
, const std::string& input_caption
, std::string* input_text
, const unsigned maximum_length
, const bool has_unit
, std::string* unit_id
, const std::vector<unit>& unit_list
, const std::vector<std::string>& option_list
, int* chosen_option);

View file

@ -712,7 +712,13 @@ void menu_handler::recruit(int side_num, const map_location &last_hex)
}
int recruit_res = 0;
bool left_side = true;
int gold = current_team.gold();
std::string unit_type = "Elvish Fighter";
recruit_res = gui2::show_recruit_message(left_side, gui_->video(),
sample_units, &unit_type, side_num, gold);
/* TODO old gui1 call, can be removed
{
dialogs::unit_types_preview_pane unit_preview(
sample_units, NULL, side_num);
@ -729,12 +735,15 @@ void menu_handler::recruit(int side_num, const map_location &last_hex)
rmenu.set_panes(preview_panes);
recruit_res = rmenu.show();
}
*/
if(recruit_res != -1) {
do_recruit(item_keys[recruit_res], side_num, last_hex);
//TODO fix the dialog and enable again
// if(recruit_res != -1) {
if(recruit_res == -1) {
do_recruit(unit_type, side_num, last_hex);
}
}
}
void menu_handler::repeat_recruit(int side_num, const map_location &last_hex)
{