Support for [action] in theme WML.

[action] is the twin of [menu].
I splitted the codepaths for menu and action buttons.
This commit is contained in:
fendrin 2013-04-29 12:07:14 +02:00
parent c84190d3c5
commit e014493923
4 changed files with 187 additions and 22 deletions

View File

@ -638,6 +638,19 @@ std::string get_names(HOTKEY_COMMAND id) {
return boost::algorithm::join(names, ", ");
}
std::string get_names(std::string id) {
std::vector<std::string> names;
BOOST_FOREACH(const hotkey::hotkey_item& item, hotkeys_) {
if (item.get_command() == id && (!item.null()) ) {
names.push_back(item.get_name());
}
}
return boost::algorithm::join(names, ", ");
}
HOTKEY_COMMAND get_hotkey_command(const std::string& command)
{
if (command_map_.find(command) != command_map_.end()) {
@ -1223,17 +1236,25 @@ void command_executor::set_button_state(display& disp) {
BOOST_FOREACH(const theme::menu& menu, disp.get_theme().menus()) {
if (menu.items().size() == 1) {
hotkey::HOTKEY_COMMAND command = hotkey::get_id(menu.items().front());
gui::button* button = disp.find_button(menu.get_id());
bool enabled = false;
BOOST_FOREACH(const std::string& command, menu.items()) {
ACTION_STATE state = get_action_state(command, -1);
gui::button* button = disp.find_button(menu.get_id());
button->enable(can_execute_command(command));
hotkey::HOTKEY_COMMAND command_id = hotkey::get_id(command);
std::string tooltip = menu.tooltip();
bool can_execute = can_execute_command(command_id);
if (!can_execute) continue;
enabled = true;
ACTION_STATE state = get_action_state(command_id, -1);
switch (state) {
case ACTION_SELECTED:
case ACTION_ON:
button->set_check(true);
break;
case ACTION_OFF:
case ACTION_DESELECTED:
button->set_check(false);
break;
case ACTION_STATELESS:
@ -1241,23 +1262,29 @@ void command_executor::set_button_state(display& disp) {
default:
break;
}
break;
}
button->enable(enabled);
}
}
void command_executor::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& gui)
void command_executor::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool /*context_menu*/, display& gui)
{
std::vector<std::string> items = items_arg;
if (items.empty()) {
return;
}
//TODO this does not make sense anymore
if (can_execute_command(hotkey::get_id(items.front()), 0)) {
// If just one item is passed in, that means we should execute that item.
/*
if (!context_menu && items.size() == 1 && items_arg.size() == 1) {
hotkey::execute_command(gui,hotkey::get_id(items.front()), this);
set_button_state(gui);
return;
}
*/
std::vector<std::string> menu = get_menu_images(gui, items);
@ -1278,11 +1305,53 @@ void command_executor::show_menu(const std::vector<std::string>& items_arg, int
}
}
std::string command_executor::get_menu_image(hotkey::HOTKEY_COMMAND command, int index) const {
switch (get_action_state(command, index)) {
case ACTION_ON: return game_config::images::checked_menu;
case ACTION_OFF: return game_config::images::unchecked_menu;
default: return get_action_image(command, index);
void command_executor::execute_action(const std::vector<std::string>& items_arg, int /*xloc*/, int /*yloc*/, bool /*context_menu*/, display& gui)
{
std::vector<std::string> items = items_arg;
if (items.empty()) {
return;
}
hotkey::HOTKEY_COMMAND command;
std::vector<std::string>::iterator i = items.begin();
while(i != items.end()) {
command = hotkey::get_id(*i);
if (can_execute_command(command)) {
hotkey::execute_command(gui, command, this);
set_button_state(gui);
}
++i;
}
}
std::string command_executor::get_menu_image(const std::string& command, int index) const {
const std::string base_image_name = "icons/action/" + command + "_25.png";
const std::string pressed_image_name = "icons/action/" + command + "_25-pressed.png";
const hotkey::HOTKEY_COMMAND hk = hotkey::get_id(command);
const hotkey::ACTION_STATE state = get_action_state(hk, index);
if (file_exists("images/" + base_image_name)) {
switch (state) {
case ACTION_ON:
case ACTION_SELECTED:
return pressed_image_name;
default:
return base_image_name;
}
}
switch (get_action_state(hk, index)) {
case ACTION_ON:
return game_config::images::checked_menu;
case ACTION_OFF:
return game_config::images::unchecked_menu;
case ACTION_SELECTED:
return game_config::images::selected_menu;
case ACTION_DESELECTED:
return game_config::images::deselected_menu;
default: return get_action_image(hk, index);
}
}
@ -1296,7 +1365,7 @@ std::vector<std::string> command_executor::get_menu_images(display& disp, const
std::stringstream str;
//see if this menu item has an associated image
std::string img(get_menu_image(hk, i));
std::string img(get_menu_image(item, i));
if (img.empty() == false) {
has_image = true;
str << IMAGE_PREFIX << img << COLUMN_SEPARATOR;

View File

@ -287,11 +287,14 @@ void load_hotkeys(const config& cfg, bool set_as_default = false);
void reset_default_hotkeys();
void save_hotkeys(config& cfg);
//TODO they do the same?
HOTKEY_COMMAND get_id(const std::string& command);
HOTKEY_COMMAND get_hotkey_command(const std::string& command);
const std::string get_description(const std::string& command);
const std::string get_tooltip(const std::string& command);
std::string get_names(hotkey::HOTKEY_COMMAND id);
std::string get_names(std::string id);
void add_hotkey(const hotkey_item& item);
void clear_hotkeys(const std::string& command);
@ -305,11 +308,10 @@ hotkey_item& get_hotkey(const SDL_JoyButtonEvent& event);
hotkey_item& get_hotkey(const SDL_JoyHatEvent& event);
hotkey_item& get_hotkey(const SDL_KeyboardEvent& event);
HOTKEY_COMMAND get_hotkey_command(const std::string& command);
std::vector<hotkey_item>& get_hotkeys();
enum ACTION_STATE { ACTION_STATELESS, ACTION_ON, ACTION_OFF };
enum ACTION_STATE { ACTION_STATELESS, ACTION_ON, ACTION_OFF, ACTION_SELECTED, ACTION_DESELECTED };
// Abstract base class for objects that implement the ability
// to execute hotkey commands.
@ -387,11 +389,12 @@ public:
// Does the action control a toggle switch? If so, return the state of the action (on or off).
virtual ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND /*command*/, int /*index*/) const { return ACTION_STATELESS; }
// Returns the appropriate menu image. Checkable items will get a checked/unchecked image.
std::string get_menu_image(hotkey::HOTKEY_COMMAND command, int index=-1) const;
std::string get_menu_image(const std::string& command, int index=-1) const;
// Returns a vector of images for a given menu.
std::vector<std::string> get_menu_images(display &, const std::vector<std::string>& items_arg);
void show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& gui);
void execute_action(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu, display& gui);
/**
* Adjusts the state of those theme menu buttons which trigger hotkey events.

View File

@ -505,20 +505,46 @@ theme::menu::menu() :
title_(),
tooltip_(),
image_(),
type_(),
overlay_(),
items_()
{}
theme::menu::menu(const config &cfg):
object(cfg), context_(cfg["is_context_menu"].to_bool()),
title_(cfg["title"].str() + cfg["title_literal"].str()),
tooltip_(cfg["tooltip"]), image_(cfg["image"]), type_(cfg["type"]),
tooltip_(cfg["tooltip"]), image_(cfg["image"]), overlay_(cfg["overlay"]),
items_(utils::split(cfg["items"]))
{
if (cfg["auto_tooltip"].to_bool() && tooltip_.empty() && items_.size() == 1) {
tooltip_ = hotkey::get_description(items_[0]);
tooltip_ = hotkey::get_description(items_[0])
+ hotkey::get_names(items_[0]) + "\n" + hotkey::get_tooltip(items_[0]);
} else if (cfg["tooltip_name_prepend"].to_bool() && items_.size() == 1) {
tooltip_ = hotkey::get_description(items_[0]) + "\n" + tooltip_;
tooltip_ = hotkey::get_description(items_[0])
+ hotkey::get_names(items_[0]) + "\n" + tooltip_;
}
}
theme::action::action() :
object(),
context_(false),
title_(),
tooltip_(),
image_(),
overlay_(),
type_(),
items_()
{}
theme::action::action(const config &cfg):
object(cfg), context_(cfg["is_context_menu"].to_bool()),
title_(cfg["title"].str() + cfg["title_literal"].str()),
tooltip_(cfg["tooltip"]), image_(cfg["image"]), overlay_(cfg["overlay"]), type_(cfg["type"]),
items_(utils::split(cfg["items"]))
{
if (cfg["auto_tooltip"].to_bool() && tooltip_.empty() && items_.size() == 1) {
tooltip_ = hotkey::get_description(items_[0]) + " hotkeys: " + hotkey::get_names(items_[0]) + "\n" + hotkey::get_tooltip(items_[0]);
} else if (cfg["tooltip_name_prepend"].to_bool() && items_.size() == 1) {
tooltip_ = hotkey::get_description(items_[0]) + " hotkeys: " + hotkey::get_names(items_[0]) + "\n" + tooltip_;
}
}
@ -529,6 +555,7 @@ theme::theme(const config& cfg, const SDL_Rect& screen) :
panels_(),
labels_(),
menus_(),
actions_(),
context_(),
status_(),
main_map_(),
@ -586,6 +613,7 @@ bool theme::set_resolution(const SDL_Rect& screen)
labels_.clear();
status_.clear();
menus_.clear();
actions_.clear();
add_object(*current);
@ -651,6 +679,20 @@ void theme::add_object(const config& cfg)
DBG_DP << "done adding menu...\n";
}
BOOST_FOREACH(const config &a, cfg.child_range("action"))
{
action new_action(a);
DBG_DP << "adding action: " << (new_action.is_context() ? "is context" : "not context") << "\n";
if(new_action.is_context())
action_context_ = new_action;
else{
set_object_location(new_action, a["rect"], a["ref"]);
actions_.push_back(new_action);
}
DBG_DP << "done adding action...\n";
}
if (const config &c = cfg.child("main_map_border")) {
border_ = tborder(c);
} else {
@ -677,6 +719,12 @@ void theme::remove_object(std::string id){
return;
}
}
for(std::vector<theme::action>::iterator a = actions_.begin(); a != actions_.end(); ++a) {
if (a->get_id() == id){
actions_.erase(a);
return;
}
}
}
void theme::set_object_location(theme::object& element, std::string rect_str, std::string ref_id){
@ -702,6 +750,12 @@ void theme::modify(const config &cfg)
title_stash[m->get_id()] = m->title();
}
std::vector<theme::action>::iterator a;
for (a = actions_.begin(); a != actions_.end(); ++a) {
if (!a->title().empty() && !a->get_id().empty())
title_stash[a->get_id()] = a->title();
}
// Change existing theme objects.
BOOST_FOREACH(const config &c, cfg.child_range("change"))
{
@ -726,6 +780,10 @@ void theme::modify(const config &cfg)
if (title_stash.find(m->get_id()) != title_stash.end())
m->set_title(title_stash[m->get_id()]);
}
for (a = actions_.begin(); a != actions_.end(); ++a) {
if (title_stash.find(a->get_id()) != title_stash.end())
a->set_title(title_stash[a->get_id()]);
}
}
theme::object& theme::find_element(std::string id){
@ -740,6 +798,9 @@ theme::object& theme::find_element(std::string id){
for (std::vector<theme::menu>::iterator m = menus_.begin(); m != menus_.end(); ++m){
if (m->get_id() == id) { res = &(*m); }
}
for (std::vector<theme::action>::iterator a = actions_.begin(); a != actions_.end(); ++a){
if (a->get_id() == id) { res = &(*a); }
}
if (id == "main-map") { res = &main_map_; }
if (id == "mini-map") { res = &mini_map_; }
if (id == "palette") { res = &palette_; }

View File

@ -163,6 +163,35 @@ public:
std::string image_;
};
class action : public object
{
public:
action();
explicit action(const config& cfg);
using object::location;
bool is_context() const { return context_; }
const std::string& title() const { return title_; }
const std::string& tooltip() const { return tooltip_; }
const std::string& type() const { return type_; }
const std::string& image() const { return image_; }
const std::string& overlay() const { return overlay_; }
const std::vector<std::string>& items() const { return items_; }
void set_title(const std::string& new_title) { title_ = new_title; }
private:
bool context_;
std::string title_, tooltip_, image_, overlay_, type_;
std::vector<std::string> items_;
};
class menu : public object
{
public:
@ -177,16 +206,16 @@ public:
const std::string& tooltip() const { return tooltip_; }
const std::string& type() const { return type_; }
const std::string& image() const { return image_; }
const std::string& overlay() const { return overlay_; }
const std::vector<std::string>& items() const { return items_; }
void set_title(const std::string& new_title) { title_ = new_title; }
private:
bool context_;
std::string title_, tooltip_, image_, type_;
std::string title_, tooltip_, image_, overlay_;
std::vector<std::string> items_;
};
@ -197,6 +226,7 @@ public:
const std::vector<panel>& panels() const { return panels_; }
const std::vector<label>& labels() const { return labels_; }
const std::vector<menu>& menus() const { return menus_; }
const std::vector<action>& actions() const { return actions_; }
const menu* context_menu() const
{ return context_.is_context() ? &context_ : NULL; }
@ -242,8 +272,10 @@ private:
std::vector<panel> panels_;
std::vector<label> labels_;
std::vector<menu> menus_;
std::vector<action> actions_;
menu context_;
action action_context_;
std::map<std::string,status_item> status_;