controller_base.cpp

Go to the documentation of this file.
00001 /* $Id: controller_base.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2006 - 2012 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
00004    wesnoth playlevel Copyright (C) 2003 by David White <dave@whitevine.net>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY.
00013 
00014    See the COPYING file for more details.
00015 */
00016 
00017 #include "controller_base.hpp"
00018 
00019 #include "dialogs.hpp"
00020 #include "display.hpp"
00021 #include "foreach.hpp"
00022 #include "game_preferences.hpp"
00023 #include "log.hpp"
00024 #include "mouse_handler_base.hpp"
00025 
00026 static lg::log_domain log_display("display");
00027 #define ERR_DP LOG_STREAM(err, log_display)
00028 
00029 controller_base::controller_base(
00030         int ticks, const config& game_config, CVideo& /*video*/) :
00031     game_config_(game_config),
00032     ticks_(ticks),
00033     key_(),
00034     browse_(false),
00035     scrolling_(false),
00036     joystick_manager_()
00037 {
00038 }
00039 
00040 controller_base::~controller_base()
00041 {
00042 }
00043 
00044 int controller_base::get_ticks() {
00045     return ticks_;
00046 }
00047 
00048 void controller_base::handle_event(const SDL_Event& event)
00049 {
00050     if(gui::in_dialog()) {
00051         return;
00052     }
00053 
00054     switch(event.type) {
00055     case SDL_KEYDOWN:
00056         // Detect key press events, unless there something that has keyboard focus
00057         // in which case the key press events should go only to it.
00058         if(have_keyboard_focus()) {
00059             process_keydown_event(event);
00060             hotkey::key_event(get_display(), event.key,this);
00061         } else {
00062             process_focus_keydown_event(event);
00063             break;
00064         }
00065         // intentionally fall-through
00066     case SDL_KEYUP:
00067         process_keyup_event(event);
00068         break;
00069     case SDL_JOYBUTTONDOWN:
00070         process_keydown_event(event);
00071         hotkey::button_event(get_display(), event.jbutton,this);
00072         break;
00073     case SDL_JOYHATMOTION:
00074         process_keydown_event(event);
00075         hotkey::hat_event(get_display(), event.jhat, this);
00076         break;
00077     case SDL_MOUSEMOTION:
00078         // Ignore old mouse motion events in the event queue
00079         SDL_Event new_event;
00080         if(SDL_PeepEvents(&new_event,1,SDL_GETEVENT,
00081                     SDL_EVENTMASK(SDL_MOUSEMOTION)) > 0) {
00082             while(SDL_PeepEvents(&new_event,1,SDL_GETEVENT,
00083                         SDL_EVENTMASK(SDL_MOUSEMOTION)) > 0) {};
00084             get_mouse_handler_base().mouse_motion_event(new_event.motion, browse_);
00085         } else {
00086             get_mouse_handler_base().mouse_motion_event(event.motion, browse_);
00087         }
00088         break;
00089     case SDL_MOUSEBUTTONDOWN:
00090     case SDL_MOUSEBUTTONUP:
00091         get_mouse_handler_base().mouse_press(event.button, browse_);
00092         post_mouse_press(event);
00093         if (get_mouse_handler_base().get_show_menu()){
00094             show_menu(get_display().get_theme().context_menu()->items(),event.button.x,event.button.y,true);
00095         }
00096         break;
00097     case SDL_ACTIVEEVENT:
00098         if (event.active.type == SDL_APPMOUSEFOCUS && event.active.gain == 0) {
00099             if (get_mouse_handler_base().is_dragging()) {
00100                 //simulate mouse button up when the app has lost mouse focus
00101                 //this should be a general fix for the issue when the mouse
00102                 //is dragged out of the game window and then the button is released
00103                 int x, y;
00104                 Uint8 mouse_flags = SDL_GetMouseState(&x, &y);
00105                 if ((mouse_flags & SDL_BUTTON_LEFT) == 0) {
00106                     get_mouse_handler_base().mouse_press(event.button, browse_);
00107                     post_mouse_press(event);
00108                 }
00109             }
00110         }
00111         break;
00112     default:
00113         break;
00114     }
00115 }
00116 
00117 bool controller_base::have_keyboard_focus()
00118 {
00119     return true;
00120 }
00121 
00122 void controller_base::process_focus_keydown_event(const SDL_Event& /*event*/) {
00123     //no action by default
00124 }
00125 
00126 void controller_base::process_keydown_event(const SDL_Event& /*event*/) {
00127     //no action by default
00128 }
00129 
00130 void controller_base::process_keyup_event(const SDL_Event& /*event*/) {
00131     //no action by default
00132 }
00133 
00134 void controller_base::post_mouse_press(const SDL_Event& /*event*/) {
00135     //no action by default
00136 }
00137 
00138 bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse_flags, double x_axis, double y_axis)
00139 {
00140     bool mouse_in_window = (SDL_GetAppState() & SDL_APPMOUSEFOCUS) != 0
00141         || preferences::get("scroll_when_mouse_outside", true);
00142     bool keyboard_focus = have_keyboard_focus();
00143     int scroll_speed = preferences::scroll_speed();
00144     int dx = 0, dy = 0;
00145     int scroll_threshold = (preferences::mouse_scroll_enabled())
00146         ? preferences::mouse_scroll_threshold() : 0;
00147     foreach (const theme::menu& m, get_display().get_theme().menus()) {
00148         if (point_in_rect(mousex, mousey, m.get_location())) {
00149             scroll_threshold = 0;
00150         }
00151     }
00152     if ((key[SDLK_UP] && keyboard_focus) ||
00153         (mousey < scroll_threshold && mouse_in_window))
00154     {
00155         dy -= scroll_speed;
00156     }
00157     if ((key[SDLK_DOWN] && keyboard_focus) ||
00158         (mousey > get_display().h() - scroll_threshold && mouse_in_window))
00159     {
00160         dy += scroll_speed;
00161     }
00162     if ((key[SDLK_LEFT] && keyboard_focus) ||
00163         (mousex < scroll_threshold && mouse_in_window))
00164     {
00165         dx -= scroll_speed;
00166     }
00167     if ((key[SDLK_RIGHT] && keyboard_focus) ||
00168         (mousex > get_display().w() - scroll_threshold && mouse_in_window))
00169     {
00170         dx += scroll_speed;
00171     }
00172     if ((mouse_flags & SDL_BUTTON_MMASK) != 0 && preferences::middle_click_scrolls()) {
00173         const SDL_Rect& rect = get_display().map_outside_area();
00174         if (point_in_rect(mousex, mousey,rect)) {
00175             // relative distance from the center to the border
00176             // NOTE: the view is a rectangle, so can be more sensible in one direction
00177             // but seems intuitive to use and it's useful since you must
00178             // more often scroll in the direction where the view is shorter
00179             const double xdisp = ((1.0*mousex / rect.w) - 0.5);
00180             const double ydisp = ((1.0*mousey / rect.h) - 0.5);
00181             // 4.0 give twice the normal speed when mouse is at border (xdisp=0.5)
00182             int speed = 4 * scroll_speed;
00183             dx += round_double(xdisp * speed);
00184             dy += round_double(ydisp * speed);
00185         }
00186     }
00187 
00188     dx += round_double( x_axis * scroll_speed);
00189     dy += round_double( y_axis * scroll_speed);
00190 
00191     return get_display().scroll(dx, dy);
00192 }
00193 
00194 void controller_base::play_slice(bool is_delay_enabled)
00195 {
00196     CKey key;
00197     events::pump();
00198     events::raise_process_event();
00199     events::raise_draw_event();
00200 
00201     slice_before_scroll();
00202     const theme::menu* const m = get_display().menu_pressed();
00203     if(m != NULL) {
00204         const SDL_Rect& menu_loc = m->location(get_display().screen_area());
00205         show_menu(m->items(),menu_loc.x+1,menu_loc.y + menu_loc.h + 1,false);
00206 
00207         return;
00208     }
00209 
00210     bool was_scrolling = scrolling_;
00211 
00212     std::pair<double, double> values = joystick_manager_.get_scroll_axis_pair();
00213     const double joystickx = values.first;
00214     const double joysticky = values.second;
00215 
00216     int mousex, mousey;
00217     Uint8 mouse_flags = SDL_GetMouseState(&mousex, &mousey);
00218 
00219     /* TODO fendrin enable after an axis choosing mechanism is implemented
00220     std::pair<double, double> values = joystick_manager_.get_mouse_axis_pair();
00221     mousex += values.first * 10;
00222     mousey += values.second * 10;
00223     SDL_WarpMouse(mousex, mousey);
00224     */
00225     scrolling_ = handle_scroll(key, mousex, mousey, mouse_flags, joystickx, joysticky);
00226 
00227     map_location highlighted_hex = get_display().mouseover_hex();
00228 
00229     /* TODO fendrin enable when the relative cursor movement is implemented well enough
00230     const map_location& selected_hex = get_display().selected_hex();
00231 
00232     if (selected_hex != map_location::null_location) {
00233         if (joystick_manager_.next_highlighted_hex(highlighted_hex, selected_hex)) {
00234             get_mouse_handler_base().mouse_motion(0,0, true, true, highlighted_hex);
00235             get_display().scroll_to_tile(highlighted_hex, display::ONSCREEN_WARP, false, true);
00236             scrolling_ = true;
00237         }
00238     } else */
00239 
00240     if (joystick_manager_.update_highlighted_hex(highlighted_hex)
00241             && get_display().get_map().on_board(highlighted_hex)) {
00242         get_mouse_handler_base().mouse_motion(0,0, true, true, highlighted_hex);
00243         get_display().scroll_to_tile(highlighted_hex, display::ONSCREEN_WARP, false, true);
00244         scrolling_ = true;
00245         }
00246 
00247     get_display().draw();
00248 
00249     // be nice when window is not visible
00250     // NOTE should be handled by display instead, to only disable drawing
00251     if (is_delay_enabled && (SDL_GetAppState() & SDL_APPACTIVE) == 0) {
00252         get_display().delay(200);
00253     }
00254 
00255     if (!scrolling_ && was_scrolling) {
00256         // scrolling ended, update the cursor and the brightened hex
00257         get_mouse_handler_base().mouse_update(browse_, highlighted_hex);
00258     }
00259     slice_end();
00260 }
00261 
00262 void controller_base::slice_before_scroll()
00263 {
00264     //no action by default
00265 }
00266 
00267 void controller_base::slice_end()
00268 {
00269     //no action by default
00270 }
00271 
00272 void controller_base::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu)
00273 {
00274     std::vector<std::string> items = items_arg;
00275     hotkey::HOTKEY_COMMAND command;
00276     std::vector<std::string>::iterator i = items.begin();
00277     while(i != items.end()) {
00278         command = hotkey::get_hotkey(*i).get_id();
00279         if(!can_execute_command(command)
00280         || (context_menu && !in_context_menu(command))) {
00281             i = items.erase(i);
00282             continue;
00283         }
00284         ++i;
00285     }
00286     if(items.empty())
00287         return;
00288     command_executor::show_menu(items, xloc, yloc, context_menu, get_display());
00289 }
00290 
00291 bool controller_base::in_context_menu(hotkey::HOTKEY_COMMAND /*command*/) const
00292 {
00293     return true;
00294 }
00295 
00296 const config& controller_base::get_theme(const config& game_config, std::string theme_name)
00297 {
00298     if (theme_name.empty()) theme_name = preferences::theme();
00299 
00300     if (const config &c = game_config.find_child("theme", "name", theme_name))
00301         return c;
00302 
00303     ERR_DP << "Theme '" << theme_name << "' not found. Trying the default theme.\n";
00304 
00305     if (const config &c = game_config.find_child("theme", "name", "Default"))
00306         return c;
00307 
00308     ERR_DP << "Default theme not found.\n";
00309 
00310     static config empty;
00311     return empty;
00312 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:33 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs