extensive changes to the way event handling works

This commit is contained in:
Dave White 2003-11-01 04:38:26 +00:00
parent a2b3c84ea0
commit e41c8bd858
13 changed files with 1203 additions and 1076 deletions

View file

@ -13,6 +13,7 @@
#include "actions.hpp"
#include "display.hpp"
#include "events.hpp"
#include "font.hpp"
#include "game.hpp"
#include "game_config.hpp"
@ -319,7 +320,7 @@ void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type)
double xdiff = 0.0, ydiff = 0.0;
for(int i = 0; i != num_moves; ++i) {
check_keys(*this);
events::pump();
xdiff += xmove/divisor;
ydiff += ymove/divisor;
@ -1808,7 +1809,7 @@ bool display::unit_attack_ranged(const gamemap::location& a,
int ticks = SDL_GetTicks();
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
check_keys(*this);
events::pump();
//this is a while instead of an if, because there might be multiple
//sounds playing simultaneously or close together
@ -2041,7 +2042,7 @@ bool display::unit_attack(const gamemap::location& a,
hiddenUnit_ = a;
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
check_keys(*this);
events::pump();
//this is a while instead of an if, because there might be multiple
//sounds playing simultaneously or close together
@ -2151,7 +2152,7 @@ void display::move_unit_between(const gamemap::location& a,
int skips = 0;
for(double i = 0.0; i < nsteps; i += 1.0) {
check_keys(*this);
events::pump();
//checking keys may have invalidated all images (if they have
//zoomed in or out), so reget the image here

View file

@ -55,9 +55,11 @@ void pump()
SDL_Event event;
while(SDL_PollEvent(&event)) {
for(std::vector<handler*>::iterator i = event_handlers.begin();
i != event_handlers.end(); ++i) {
(*i)->handle_event(event);
//events may cause more event handlers to be added and/or removed,
//so we must use indexes instead of iterators here.
for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2; ++i1) {
assert(i1 < event_handlers.size());
event_handlers[i1]->handle_event(event);
}
switch(event.type) {

View file

@ -12,10 +12,12 @@ struct resize_lock {
//any classes that derive from this class will automatically
//receive sdl events through the handle function for their lifetime
//note that handlers should *always* be allocated as automatic variables
//(never on the free store or in static memory)
class handler
{
public:
virtual void handle_event(const SDL_Event& event) {};
virtual void handle_event(const SDL_Event& event) = 0;
protected:
handler();
virtual ~handler();

View file

@ -20,12 +20,24 @@
#include "show_dialog.hpp"
#include "video.hpp"
#include "SDL.h"
#include <algorithm>
#include <cstdlib>
#include <map>
namespace {
enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_UNDO, HOTKEY_REDO,
HOTKEY_ZOOM_IN, HOTKEY_ZOOM_OUT, HOTKEY_ZOOM_DEFAULT,
HOTKEY_FULLSCREEN, HOTKEY_ACCELERATED,
HOTKEY_TERRAIN_TABLE, HOTKEY_ATTACK_RESISTANCE,
HOTKEY_UNIT_DESCRIPTION, HOTKEY_SAVE_GAME,
HOTKEY_RECRUIT, HOTKEY_RECALL, HOTKEY_ENDTURN,
HOTKEY_TOGGLE_GRID, HOTKEY_STATUS_TABLE,
HOTKEY_NULL };
HOTKEY_COMMAND string_to_command(const std::string& str)
{
static std::map<std::string,HOTKEY_COMMAND> m;
@ -59,8 +71,8 @@ HOTKEY_COMMAND string_to_command(const std::string& str)
return i->second;
}
struct hotkey {
explicit hotkey(config& cfg);
struct hotkey_item {
explicit hotkey_item(config& cfg);
HOTKEY_COMMAND action;
int keycode;
@ -68,7 +80,7 @@ struct hotkey {
mutable bool lastres;
};
hotkey::hotkey(config& cfg) : lastres(false)
hotkey_item::hotkey_item(config& cfg) : lastres(false)
{
std::map<std::string,std::string>& m = cfg.values;
action = string_to_command(m["command"]);
@ -79,61 +91,48 @@ hotkey::hotkey(config& cfg) : lastres(false)
shift = (m["shift"] == "yes");
}
bool operator==(const hotkey& a, const hotkey& b)
bool operator==(const hotkey_item& a, const hotkey_item& b)
{
return a.keycode == b.keycode && a.alt == b.alt &&
a.ctrl == b.ctrl && a.shift == b.shift;
}
bool operator!=(const hotkey& a, const hotkey& b)
bool operator!=(const hotkey_item& a, const hotkey_item& b)
{
return !(a == b);
}
std::vector<hotkey> hotkeys;
std::vector<hotkey_item> hotkeys;
}
struct hotkey_pressed {
hotkey_pressed(CKey& key);
hotkey_pressed(const SDL_KeyboardEvent& event);
bool operator()(const hotkey& hk) const;
bool operator()(const hotkey_item& hk) const;
private:
const bool shift_, ctrl_, alt_;
CKey& key_;
int keycode_;
bool shift_, ctrl_, alt_;
};
hotkey_pressed::hotkey_pressed(CKey& key) :
shift_(key[SDLK_LSHIFT] || key[SDLK_RSHIFT]),
ctrl_(key[SDLK_LCTRL] || key[SDLK_RCTRL]),
alt_(key[SDLK_LALT] || key[SDLK_RALT]), key_(key) {}
hotkey_pressed::hotkey_pressed(const SDL_KeyboardEvent& event)
: keycode_(event.keysym.sym), shift_(event.keysym.mod&KMOD_SHIFT),
ctrl_(event.keysym.mod&KMOD_CTRL), alt_(event.keysym.mod&KMOD_ALT)
{}
bool hotkey_pressed::operator()(const hotkey& hk) const
bool hotkey_pressed::operator()(const hotkey_item& hk) const
{
const bool res = shift_ == hk.shift && ctrl_ == hk.ctrl &&
alt_ == hk.alt && key_[hk.keycode];
//for zoom in and zoom out, allow it to happen multiple consecutive times
if(hk.action == HOTKEY_ZOOM_IN || hk.action == HOTKEY_ZOOM_OUT) {
hk.lastres = false;
return res;
}
//don't let it return true on multiple consecutive occurrences
if(hk.lastres) {
hk.lastres = res;
return false;
} else {
hk.lastres = res;
return res;
}
return hk.keycode == keycode_ && shift_ == hk.shift &&
ctrl_ == hk.ctrl && alt_ == hk.alt;
}
namespace {
void add_hotkey(config& cfg)
{
const hotkey new_hotkey(cfg);
const std::vector<hotkey>::iterator i =
const hotkey_item new_hotkey(cfg);
const std::vector<hotkey_item>::iterator i =
std::find(hotkeys.begin(),hotkeys.end(),new_hotkey);
if(i != hotkeys.end()) {
*i = new_hotkey;
@ -142,6 +141,19 @@ void add_hotkey(config& cfg)
}
}
}
namespace hotkey {
basic_handler::basic_handler(display& disp) : disp_(disp) {}
void basic_handler::handle_event(const SDL_Event& event)
{
if(event.type == SDL_KEYDOWN && !gui::in_dialog()) {
key_event(disp_,event.key,NULL);
}
}
void add_hotkeys(config& cfg)
{
std::vector<config*>& children = cfg.children["hotkey"];
@ -151,25 +163,26 @@ void add_hotkeys(config& cfg)
}
}
HOTKEY_COMMAND check_keys(display& disp)
void key_event(display& disp, const SDL_KeyboardEvent& event,
command_executor* executor)
{
const double zoom_amount = 5.0;
events::pump();
CKey key;
if(key[KEY_ESCAPE]) {
if(event.keysym.sym == SDLK_ESCAPE) {
const int res = gui::show_dialog(disp,NULL,"",
string_table["quit_message"],gui::YES_NO);
if(res == 0) {
throw end_level_exception(QUIT);
} else {
return;
}
}
const std::vector<hotkey>::iterator i =
std::find_if(hotkeys.begin(),hotkeys.end(),hotkey_pressed(key));
const std::vector<hotkey_item>::iterator i =
std::find_if(hotkeys.begin(),hotkeys.end(),hotkey_pressed(event));
if(i == hotkeys.end())
return HOTKEY_NULL;
return;
switch(i->action) {
case HOTKEY_ZOOM_IN:
@ -187,9 +200,65 @@ HOTKEY_COMMAND check_keys(display& disp)
case HOTKEY_ACCELERATED:
preferences::set_turbo(!preferences::turbo());
break;
case HOTKEY_CYCLE_UNITS:
if(executor)
executor->cycle_units();
break;
case HOTKEY_ENDTURN:
if(executor)
executor->end_turn();
break;
case HOTKEY_END_UNIT_TURN:
if(executor)
executor->end_unit_turn();
break;
case HOTKEY_LEADER:
if(executor)
executor->goto_leader();
break;
case HOTKEY_UNDO:
if(executor)
executor->undo();
break;
case HOTKEY_REDO:
if(executor)
executor->redo();
break;
case HOTKEY_TERRAIN_TABLE:
if(executor)
executor->terrain_table();
break;
case HOTKEY_ATTACK_RESISTANCE:
if(executor)
executor->attack_resistance();
break;
case HOTKEY_UNIT_DESCRIPTION:
if(executor)
executor->unit_description();
break;
case HOTKEY_SAVE_GAME:
if(executor)
executor->save_game();
break;
case HOTKEY_TOGGLE_GRID:
if(executor)
executor->toggle_grid();
break;
case HOTKEY_STATUS_TABLE:
if(executor)
executor->status_table();
break;
case HOTKEY_RECALL:
if(executor)
executor->recall();
break;
case HOTKEY_RECRUIT:
if(executor)
executor->recruit();
break;
default:
return i->action;
break;
}
return HOTKEY_NULL;
}
}

View file

@ -15,20 +15,45 @@
#include "config.hpp"
#include "display.hpp"
#include "events.hpp"
#include "key.hpp"
enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_UNDO, HOTKEY_REDO,
HOTKEY_ZOOM_IN, HOTKEY_ZOOM_OUT, HOTKEY_ZOOM_DEFAULT,
HOTKEY_FULLSCREEN, HOTKEY_ACCELERATED,
HOTKEY_TERRAIN_TABLE, HOTKEY_ATTACK_RESISTANCE,
HOTKEY_UNIT_DESCRIPTION, HOTKEY_SAVE_GAME,
HOTKEY_RECRUIT, HOTKEY_RECALL, HOTKEY_ENDTURN,
HOTKEY_TOGGLE_GRID, HOTKEY_STATUS_TABLE,
HOTKEY_NULL };
namespace hotkey {
class command_executor
{
public:
virtual void cycle_units() = 0;
virtual void end_turn() = 0;
virtual void goto_leader() = 0;
virtual void end_unit_turn() = 0;
virtual void undo() = 0;
virtual void redo() = 0;
virtual void terrain_table() = 0;
virtual void attack_resistance() = 0;
virtual void unit_description() = 0;
virtual void save_game() = 0;
virtual void toggle_grid() = 0;
virtual void status_table() = 0;
virtual void recall() = 0;
virtual void recruit() = 0;
};
//object which will ensure that basic keyboard events like escape
//are handled properly for the duration of its lifetime
struct basic_handler : public events::handler {
basic_handler(display& disp);
void handle_event(const SDL_Event& event);
private:
display& disp_;
};
void add_hotkeys(config& cfg);
HOTKEY_COMMAND check_keys(display& disp);
void key_event(display& disp, const SDL_KeyboardEvent& event,
command_executor* executor);
}
#endif

View file

@ -48,7 +48,7 @@ bool internal_set_language(const std::string& locale, config& cfg)
string_table[j->first] = j->second;
}
add_hotkeys(**i);
hotkey::add_hotkeys(**i);
return true;
}
}

View file

@ -13,6 +13,7 @@
#include "events.hpp"
#include "game_events.hpp"
#include "hotkeys.hpp"
#include "intro.hpp"
#include "language.hpp"
#include "network.hpp"
@ -168,10 +169,12 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
find_leader(units,player_number);
if(leader != units.end() && !recorder.skipping()) {
const hotkey::basic_handler key_events_handler(gui);
gui.scroll_to_tile(leader->first.x,leader->first.y);
}
if(replaying) {
const hotkey::basic_handler key_events_handler(gui);
std::cerr << "doing replay " << player_number << "\n";
replaying = do_replay(gui,map,gameinfo,units,teams,
player_number,status,state_of_game);
@ -198,6 +201,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
display::clear_debug_highlights();
} else if(!replaying && team_it->is_ai()) {
const hotkey::basic_handler key_events_handler(gui);
const int start_command = recorder.ncommands();
ai::do_move(gui,map,gameinfo,units,teams,
@ -225,8 +230,9 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
config cfg;
turn_info turn_data;
const paths_wiper wiper(gui);
turn_info turn_data(gameinfo,state_of_game,status,
terrain_config,level,key,gui,
map,teams,player_number,units,true);
for(;;) {
network::connection res =
@ -239,9 +245,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
break;
}
turn_slice(gameinfo,state_of_game,status,
terrain_config,level,video,key,gui,map,
teams,player_number,units,turn_data,true);
turn_data.turn_slice();
gui.draw();
}
std::cerr << "replay: '" << cfg.children["turn"].front()->write() << "'\n";

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,11 @@
#include "config.hpp"
#include "dialogs.hpp"
#include "display.hpp"
#include "events.hpp"
#include "game_config.hpp"
#include "game_events.hpp"
#include "gamestatus.hpp"
#include "hotkeys.hpp"
#include "key.hpp"
#include "pathfind.hpp"
#include "show_dialog.hpp"
@ -43,21 +45,75 @@ private:
display& gui_;
};
struct turn_info {
turn_info() : left_button(false), right_button(false), middle_button(false),
enemy_paths(false), path_turns(0)
{}
class turn_info : public hotkey::command_executor, public events::handler,
private paths_wiper
{
public:
turn_info(game_data& gameinfo, game_state& state_of_game,
gamestatus& status, config& terrain_config, config* level,
CKey& key, display& gui, gamemap& map,
std::vector<team>& teams, int team_num,
unit_map& units, bool browse_only);
bool left_button, right_button, middle_button;
gamemap::location next_unit;
paths current_paths;
paths::route current_route;
bool enemy_paths;
gamemap::location last_hex;
gamemap::location selected_hex;
undo_list undo_stack;
undo_list redo_stack;
int path_turns;
void turn_slice();
bool turn_over() const;
int send_data(int first_command);
undo_list& undos() { return undo_stack_; }
private:
void cycle_units();
void end_turn();
void goto_leader();
void end_unit_turn();
void undo();
void redo();
void terrain_table();
void attack_resistance();
void unit_description();
void save_game();
void toggle_grid();
void status_table();
void recruit();
void recall();
void handle_event(const SDL_Event& event);
void mouse_motion(const SDL_MouseMotionEvent& event);
void mouse_press(const SDL_MouseButtonEvent& event);
void left_click(const SDL_MouseButtonEvent& event);
void show_menu();
unit_map::const_iterator current_unit();
game_data& gameinfo_;
game_state& state_of_game_;
gamestatus& status_;
config& terrain_config_;
config* level_;
CKey key_;
display& gui_;
gamemap& map_;
std::vector<team>& teams_;
int team_num_;
unit_map& units_;
bool browse_;
bool left_button_, right_button_, middle_button_;
gamemap::location next_unit_;
paths current_paths_;
paths::route current_route_;
bool enemy_paths_;
gamemap::location last_hex_;
gamemap::location selected_hex_;
undo_list undo_stack_;
undo_list redo_stack_;
int path_turns_;
bool end_turn_;
};
void play_turn(game_data& gameinfo, game_state& state_of_game,

View file

@ -55,7 +55,7 @@ display_manager::display_manager(display* d)
{
disp = d;
add_hotkeys(prefs);
hotkey::add_hotkeys(prefs);
set_grid(grid());
set_turbo(turbo());

View file

@ -28,8 +28,17 @@
#include <iostream>
#include <numeric>
namespace {
bool is_in_dialog = false;
}
namespace gui {
bool in_dialog() { return is_in_dialog; }
dialog_manager::dialog_manager() : reset_to(is_in_dialog) {is_in_dialog = true;}
dialog_manager::~dialog_manager() { is_in_dialog = reset_to; }
void draw_dialog_frame(int x, int y, int w, int h, display& disp)
{
draw_dialog_background(x,y,w,h,disp);
@ -190,6 +199,8 @@ int show_dialog(display& disp, SDL_Surface* image,
if(disp.update_locked())
return -1;
const dialog_manager manager;
const events::resize_lock prevent_resizing;
const std::vector<std::string>& menu_items =

View file

@ -25,6 +25,16 @@
namespace gui
{
bool in_dialog();
struct dialog_manager {
dialog_manager();
~dialog_manager();
private:
bool reset_to;
};
void draw_dialog_frame(int x, int y, int w, int h, display& disp);
void draw_dialog_background(int x, int y, int w, int h, display& disp);

View file

@ -213,7 +213,7 @@ void CVideo::flip()
{
if(update_all) {
::SDL_Flip(frameBuffer);
} else {
} else if(update_rects.empty() == false) {
SDL_UpdateRects(frameBuffer,update_rects.size(),&update_rects[0]);
}