From 429b2b6d866ce50308ebb366ba239d6a397b1943 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 24 Apr 2010 20:39:25 +0000 Subject: [PATCH] Added a new attack dialog. This initial version is just a small proof of concept thing, its main goal is to write a new chapter in the design documentation. The dialog is available when started with --new-widgets. --- changelog | 1 + data/gui/default/window/unit_attack.cfg | 293 ++++++++++++++++++++++++ po/wesnoth-lib/POTFILES.in | 1 + src/CMakeLists.txt | 1 + src/Makefile.am | 1 + src/SConscript | 1 + src/gui/dialogs/unit_attack.cpp | 152 ++++++++++++ src/gui/dialogs/unit_attack.hpp | 68 ++++++ src/mouse_events.cpp | 27 +++ 9 files changed, 545 insertions(+) create mode 100644 data/gui/default/window/unit_attack.cfg create mode 100644 src/gui/dialogs/unit_attack.cpp create mode 100644 src/gui/dialogs/unit_attack.hpp diff --git a/changelog b/changelog index 68f2babaf7f..2e63d01869d 100644 --- a/changelog +++ b/changelog @@ -37,6 +37,7 @@ Version 1.9.0-svn: * Fixed bug #15727: Allow wml message titles to wrap screen * Added the total number of villages to the status table lists + * Added a new attack dialog, available for testing with --new-widgets * WML Engine: * Deprecated [set_variable]'s random key, use rand instead * Renamed [unit][status] healable to unhealable so it can default to 'no' diff --git a/data/gui/default/window/unit_attack.cfg b/data/gui/default/window/unit_attack.cfg new file mode 100644 index 00000000000..10e6bb681d4 --- /dev/null +++ b/data/gui/default/window/unit_attack.cfg @@ -0,0 +1,293 @@ +#textdomain wesnoth-lib +### +### Definition of the window select which unit to attack +### + +#define _GUI_BIG_ATTACKER_PANEL +[grid] + id = "attacker" + linked_group = "unit" + + [row] + + [column] + border = "all" + border_size = 5 + + [image] + id = "attacker_portrait" + [/image] + + [/column] + + [column] + grow_factor = 1 + horizontal_grow = "true" + + border = "all" + border_size = 5 + + [label] + id = "attacker_name" + definition = "alignment" + [/label] + + [/column] + + [/row] + +[/grid] +#enddef + +#define _GUI_BIG_DEFENDER_PANEL +[grid] + id = "defender" + linked_group = "unit" + + [row] + + [column] + grow_factor = 1 + horizontal_grow = "true" + + border = "all" + border_size = 5 + + [label] + id = "defender_name" + definition = "alignment" + + text_alignment = "right" + [/label] + + [/column] + + [column] + border = "all" + border_size = 5 + + [image] + id = "defender_portrait" + [/image] + + [/column] + + [/row] + +[/grid] +#enddef + +#define _GUI_BIG_UNIT_PANEL +[grid] + + [row] + + [column] + {_GUI_BIG_ATTACKER_PANEL} + [/column] + + [column] + {_GUI_BIG_DEFENDER_PANEL} + [/column] + + [/row] + +[/grid] +#enddef + +#define _GUI_BIG_WEAPON_PANEL +[grid] + + [row] + + [column] + horizontal_grow = "true" + + [listbox] + id = "weapon_list" + definition = "default" + + [list_definition] + + [row] + + [column] + vertical_grow = "true" + horizontal_grow = "true" + + [toggle_panel] + definition = "default" + + return_value_id = "ok" + [grid] + + [row] + + [column] + grow_factor = 1 + horizontal_grow = "true" + + border = "all" + border_size = 5 + + [label] + id = "attacker_weapon" + definition = "alignment" + linked_group = "weapon" + [/label] + + [/column] + + [column] + grow_factor = 1 + horizontal_grow = "true" + + border = "all" + border_size = 5 + + [label] + id = "defender_weapon" + definition = "alignment" + linked_group = "weapon" + + text_alignment = "right" + [/label] + + [/column] + + [/row] + + [/grid] + + [/toggle_panel] + + [/column] + + [/row] + + [/list_definition] + + [/listbox] + + [/column] + + [/row] + +[/grid] +#enddef + +#define _GUI_BUTTON_ROW +[grid] + + [row] + + [column] + grow_factor = 1 + + border = "all" + border_size = 5 + horizontal_alignment = "right" + + [button] + id = "ok" + definition = "default" + + label = _ "Attack" + [/button] + + [/column] + + [column] + border = "all" + border_size = 5 + + [button] + id = "cancel" + definition = "default" + + label = _ "Cancel" + [/button] + + [/column] + + [/row] + +[/grid] +#enddef + +[window] + id = "unit_attack" + description = "Unit attack dialog." + + [resolution] + definition = "default" + + automatic_placement = "true" + vertical_placement = "center" + horizontal_placement = "center" + + # Both unit panels are the same width. + [linked_group] + id = "unit" + fixed_width = "true" + [/linked_group] + + # All weapons share the same size, regardless whether attacker or + # defender. + [linked_group] + id = "weapon" + fixed_width = "true" + [/linked_group] + + [grid] + + [row] + + [column] + grow_factor = 1 + + border = "all" + border_size = 5 + horizontal_alignment = "left" + [label] + definition = "title" + + label = _ "Attack enemy" + [/label] + + [/column] + + [/row] + + [row] + + [column] + horizontal_grow = "true" + {_GUI_BIG_UNIT_PANEL} + [/column] + + [/row] + + [row] + + [column] + horizontal_grow = "true" + {_GUI_BIG_WEAPON_PANEL} + [/column] + + [/row] + + [row] + + [column] + horizontal_grow = "true" + {_GUI_BUTTON_ROW} + [/column] + + [/row] + + [/grid] + + [/resolution] + +[/window] diff --git a/po/wesnoth-lib/POTFILES.in b/po/wesnoth-lib/POTFILES.in index bfecbae79ee..db2eaf43ebc 100644 --- a/po/wesnoth-lib/POTFILES.in +++ b/po/wesnoth-lib/POTFILES.in @@ -74,6 +74,7 @@ src/gui/dialogs/mp_create_game.cpp src/gui/dialogs/mp_method_selection.cpp src/gui/dialogs/title_screen.cpp src/gui/dialogs/transient_message.cpp +src/gui/dialogs/unit_attack.cpp src/gui/dialogs/unit_create.cpp src/gui/dialogs/wml_message.cpp src/gui/widgets/button.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 44a5293a806..f554a4467bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -349,6 +349,7 @@ set(wesnoth-main_SRC gui/dialogs/mp_cmd_wrapper.cpp gui/dialogs/title_screen.cpp gui/dialogs/transient_message.cpp + gui/dialogs/unit_attack.cpp gui/dialogs/unit_create.cpp gui/dialogs/wml_message.cpp gui/widgets/button.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 730adbd265e..e3a66e61276 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -175,6 +175,7 @@ wesnoth_source = \ gui/dialogs/mp_cmd_wrapper.cpp \ gui/dialogs/title_screen.cpp \ gui/dialogs/transient_message.cpp \ + gui/dialogs/unit_attack.cpp \ gui/dialogs/unit_create.cpp \ gui/dialogs/wml_message.cpp \ gui/widgets/button.cpp \ diff --git a/src/SConscript b/src/SConscript index 59fb2387d0b..f70822eea3d 100644 --- a/src/SConscript +++ b/src/SConscript @@ -334,6 +334,7 @@ wesnoth_sources = Split(""" gui/dialogs/mp_cmd_wrapper.cpp gui/dialogs/title_screen.cpp gui/dialogs/transient_message.cpp + gui/dialogs/unit_attack.cpp gui/dialogs/unit_create.cpp gui/dialogs/wml_message.cpp gui/dialogs/icon_message.cpp diff --git a/src/gui/dialogs/unit_attack.cpp b/src/gui/dialogs/unit_attack.cpp new file mode 100644 index 00000000000..2baf59c4e8c --- /dev/null +++ b/src/gui/dialogs/unit_attack.cpp @@ -0,0 +1,152 @@ +/* $Id$ */ +/* + Copyright (C) 2010 by Mark de Wever + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + or at your option any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#define GETTEXT_DOMAIN "wesnoth-lib" + +#include "gui/dialogs/unit_attack.hpp" + +#include "gui/widgets/image.hpp" +#include "gui/widgets/listbox.hpp" +#include "gui/widgets/settings.hpp" +#include "gui/widgets/window.hpp" +#include "unit.hpp" + +namespace gui2 { + +/*WIKI + * @page = GUIWindowDefinitionWML + * @order = 2_unit_attack + * + * == Unit attack == + * + * This shows the dialog for attacking units. + * + * @start_table = grid + * + * attacker_portrait (image) Shows the portrait of the attacking unit. + * attacker_icon (image) Shows the icon of the attacking unit. + * attacker_name (control) Shows the name of the attacking unit. + * + * + * defender_portrait (image) Shows the portrait of the defending unit. + * defender_icon (image) Shows the icon of the defending unit. + * defender_name (control) Shows the name of the defending unit. + * + * + * (weapon_list) (listbox) The list with weapons to choos from. + * -[attacker_weapon] (control) The weapon for the attacker to use. + * -[defender_weapon] (control) The weapon for the defender to use. + * + * @end_table + */ + +REGISTER_WINDOW(unit_attack) + +tunit_attack::tunit_attack( + const unit_map::iterator& attacker_itor + , const unit_map::iterator& defender_itor + , const std::vector& weapons + , const int best_weapon) + : selected_weapon_(-1) + , attacker_itor_(attacker_itor) + , defender_itor_(defender_itor) + , weapons_(weapons) + , best_weapon_(best_weapon) +{ +} + +template +static void set_label( + twindow& window + , const std::string& id + , const std::string& label) +{ + T* widget = find_widget(&window, id, false, false); + if(widget) { + widget->set_label(label); + } +} + +static void set_attacker_info(twindow& w, unit& u) +{ + set_label(w, "attacker_portrait", u.absolute_image()); + set_label(w, "attacker_icon", u.absolute_image()); + set_label(w, "attacker_name", u.name()); +} + +static void set_defender_info(twindow& w, unit& u) +{ + set_label(w, "defender_portrait", u.absolute_image()); + set_label(w, "defender_icon", u.absolute_image()); + set_label(w, "defender_name", u.name()); +} + +static void set_weapon_info(twindow& window + , const std::vector& weapons + , const int best_weapon) +{ + tlistbox& weapon_list = + find_widget(&window, "weapon_list", false); + window.keyboard_capture(&weapon_list); + + const config empty; + attack_type no_weapon(empty); + + for (size_t i = 0; i < weapons.size(); ++i) { + const battle_context::unit_stats& attacker = + weapons[i].get_attacker_stats(); + + const battle_context::unit_stats& defender = + weapons[i].get_defender_stats(); + + const attack_type& attacker_weapon = attack_type(*attacker.weapon); + const attack_type& defender_weapon = attack_type( + defender.weapon ? *defender.weapon : no_weapon); + + std::map data; + string_map item; + + item["label"] = attacker_weapon.name(); + data.insert(std::make_pair("attacker_weapon", item)); + + item["label"] = defender_weapon.name(); + data.insert(std::make_pair("defender_weapon", item)); + + weapon_list.add_row(data); + + } + + assert(best_weapon < static_cast(weapon_list.get_item_count())); + weapon_list.select_row(best_weapon); +} + +void tunit_attack::pre_show(CVideo& /*video*/, twindow& window) +{ + set_attacker_info(window, *attacker_itor_); + set_defender_info(window, *defender_itor_); + + selected_weapon_ = -1; + set_weapon_info(window, weapons_, best_weapon_); +} + +void tunit_attack::post_show(twindow& window) +{ + if(get_retval() == twindow::OK) { + selected_weapon_ = find_widget(&window, "weapon_list", false) + .get_selected_row(); + } +} + +} // namespace gui2 + diff --git a/src/gui/dialogs/unit_attack.hpp b/src/gui/dialogs/unit_attack.hpp new file mode 100644 index 00000000000..fae5dcd8c9f --- /dev/null +++ b/src/gui/dialogs/unit_attack.hpp @@ -0,0 +1,68 @@ +/* $Id$ */ +/* + Copyright (C) 2010 by Mark de Wever + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + or at your option any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#ifndef GUI_DIALOGS_UNIT_ATTACK_HPP_INCLUDED +#define GUI_DIALOGS_UNIT_ATTACK_HPP_INCLUDED + +#include "actions.hpp" +#include "gui/dialogs/dialog.hpp" +#include "unit_map.hpp" + +namespace gui2 { + +class tunit_attack + : public tdialog +{ +public: + tunit_attack( + const unit_map::iterator& attacker_itor + , const unit_map::iterator& defender_itor + , const std::vector& weapons + , const int best_weapon); + + /***** ***** ***** setters / getters for members ***** ****** *****/ + + int get_selected_weapon() const { return selected_weapon_; } + +private: + + /** Inherited from tdialog, implemented by REGISTER_WINDOW. */ + virtual const std::string& window_id() const; + + /** Inherited from tdialog. */ + void pre_show(CVideo& video, twindow& window); + + /** Inherited from tdialog. */ + void post_show(twindow& window); + + /** The index of the selected weapon. */ + int selected_weapon_; + + /** Iterator pointing to the attacker. */ + unit_map::iterator attacker_itor_; + + /** Iterator pointing to the defender. */ + unit_map::iterator defender_itor_; + + /** List of all battle contexts used for getting the weapons. */ + std::vector weapons_; + + /** The best weapon, aka the one high-lighted. */ + int best_weapon_; +}; + +} // namespace gui2 + +#endif + diff --git a/src/mouse_events.cpp b/src/mouse_events.cpp index 09bea548697..bbd83c38b53 100644 --- a/src/mouse_events.cpp +++ b/src/mouse_events.cpp @@ -23,6 +23,9 @@ #include "game_end_exceptions.hpp" #include "game_events.hpp" #include "gettext.hpp" +#include "gui/dialogs/unit_attack.hpp" +#include "gui/widgets/settings.hpp" +#include "gui/widgets/window.hpp" #include "log.hpp" #include "map.hpp" #include "marked-up_text.hpp" @@ -647,6 +650,30 @@ int mouse_handler::fill_weapon_choices(std::vector& bc_vector, u int mouse_handler::show_attack_dialog(const map_location& attacker_loc, const map_location& defender_loc) { + if(gui2::new_widgets) { + + unit_map::iterator attacker = find_unit(attacker_loc); + unit_map::iterator defender = find_unit(defender_loc); + + std::vector weapons; + const int best_weapon = + fill_weapon_choices(weapons, attacker, defender); + + gui2::tunit_attack dlg( + attacker + , defender + , weapons + , best_weapon); + + dlg.show(gui_->video()); + + if(dlg.get_retval() == gui2::twindow::OK) { + return dlg.get_selected_weapon(); + } else { + return -1; + } + } + unit_map::iterator attacker = find_unit(attacker_loc); unit_map::iterator defender = find_unit(defender_loc);