iOS: Touch interface implemented, and a RMB emulation of such on PC.
This commit is contained in:
parent
ea2e16d251
commit
aedc081b2e
14 changed files with 533 additions and 39 deletions
|
@ -40,6 +40,12 @@
|
|||
command="deselecthex"
|
||||
mouse=0
|
||||
[/hotkey]
|
||||
[hotkey]
|
||||
button=1
|
||||
command="selectmoveaction"
|
||||
# Which means "touch"
|
||||
mouse=255
|
||||
[/hotkey]
|
||||
|
||||
[hotkey]
|
||||
command=aiformula
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
#include <SDL_platform.h>
|
||||
|
||||
static lg::log_domain log_cache("cache");
|
||||
#define ERR_CACHE LOG_STREAM(err, log_cache)
|
||||
|
@ -45,6 +46,10 @@ void add_builtin_defines(preproc_map& target)
|
|||
target["APPLE"] = preproc_define();
|
||||
#endif
|
||||
|
||||
#if defined(MOUSE_TOUCH_EMULATION) || defined(__IPHONEOS__)
|
||||
target["IPHONEOS"] = preproc_define();
|
||||
#endif
|
||||
|
||||
target["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ void controller_base::handle_event(const SDL_Event& event)
|
|||
|
||||
events::mouse_handler_base& mh_base = get_mouse_handler_base();
|
||||
|
||||
SDL_Event new_event = {};
|
||||
|
||||
switch(event.type) {
|
||||
case SDL_TEXTINPUT:
|
||||
if(have_keyboard_focus()) {
|
||||
|
@ -96,33 +98,47 @@ void controller_base::handle_event(const SDL_Event& event)
|
|||
break;
|
||||
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
process_keydown_event(event);
|
||||
hotkey::jbutton_event(event, get_hotkey_command_executor());
|
||||
break;
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
process_keydown_event(event);
|
||||
hotkey::jhat_event(event, get_hotkey_command_executor());
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
// Ignore old mouse motion events in the event queue
|
||||
SDL_Event new_event;
|
||||
if(SDL_PeepEvents(&new_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) {
|
||||
while(SDL_PeepEvents(&new_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) {
|
||||
};
|
||||
mh_base.mouse_motion_event(new_event.motion, is_browsing());
|
||||
if(new_event.motion.which != SDL_TOUCH_MOUSEID) {
|
||||
mh_base.mouse_motion_event(new_event.motion, is_browsing());
|
||||
}
|
||||
} else {
|
||||
mh_base.mouse_motion_event(event.motion, is_browsing());
|
||||
if(new_event.motion.which != SDL_TOUCH_MOUSEID) {
|
||||
mh_base.mouse_motion_event(event.motion, is_browsing());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_FINGERMOTION:
|
||||
if(SDL_PeepEvents(&new_event, 1, SDL_GETEVENT, SDL_FINGERMOTION, SDL_FINGERMOTION) > 0) {
|
||||
while(SDL_PeepEvents(&new_event, 1, SDL_GETEVENT, SDL_FINGERMOTION, SDL_FINGERMOTION) > 0) {
|
||||
};
|
||||
mh_base.touch_motion_event(new_event.tfinger, is_browsing());
|
||||
} else {
|
||||
mh_base.touch_motion_event(event.tfinger, is_browsing());
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
process_keydown_event(event);
|
||||
mh_base.mouse_press(event.button, is_browsing());
|
||||
hotkey::mbutton_event(event, get_hotkey_command_executor());
|
||||
break;
|
||||
|
||||
case SDL_FINGERDOWN:
|
||||
// handled by mouse case
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
mh_base.mouse_press(event.button, is_browsing());
|
||||
if(mh_base.get_show_menu()) {
|
||||
|
@ -131,6 +147,10 @@ void controller_base::handle_event(const SDL_Event& event)
|
|||
}
|
||||
break;
|
||||
|
||||
case SDL_FINGERUP:
|
||||
// handled by mouse case
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
mh_base.mouse_wheel(-event.wheel.x, event.wheel.y, is_browsing());
|
||||
|
@ -139,6 +159,8 @@ void controller_base::handle_event(const SDL_Event& event)
|
|||
#endif
|
||||
break;
|
||||
|
||||
// TODO: Support finger specifically, like pan the map. For now, SDL's "shadow mouse" events will do.
|
||||
case SDL_MULTIGESTURE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1290,6 +1290,11 @@ void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
|
|||
gui().highlight_hex(hex_clicked);
|
||||
}
|
||||
|
||||
void editor_controller::touch_motion(int /* x */, int /* y */, const bool /* browse */, bool /* update */, map_location /* new_loc */)
|
||||
{
|
||||
// Not implemented at all. Sorry, it's a very low priority for iOS port.
|
||||
}
|
||||
|
||||
bool editor_controller::allow_mouse_wheel_scroll(int x, int y)
|
||||
{
|
||||
return get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(x,y));
|
||||
|
|
|
@ -154,6 +154,7 @@ class editor_controller : public controller_base,
|
|||
|
||||
/* mouse_handler_base overrides */
|
||||
void mouse_motion(int x, int y, const bool browse, bool update, map_location new_loc = map_location::null_location()) override;
|
||||
void touch_motion(int x, int y, const bool browse, bool update=false, map_location new_loc = map_location::null_location()) override;
|
||||
editor_display& gui() override { return *gui_; }
|
||||
const editor_display& gui() const override { return *gui_; }
|
||||
bool allow_mouse_wheel_scroll(int x, int y) override;
|
||||
|
|
|
@ -504,11 +504,69 @@ void pump()
|
|||
events.erase(first_draw_event + 1, events.end());
|
||||
}
|
||||
|
||||
for(const SDL_Event& event : events) {
|
||||
for(SDL_Event& event : events) {
|
||||
for(context& c : event_contexts) {
|
||||
c.add_staging_handlers();
|
||||
}
|
||||
|
||||
#ifdef MOUSE_TOUCH_EMULATION
|
||||
switch (event.type) {
|
||||
// TODO: Implement SDL_MULTIGESTURE. Some day.
|
||||
case SDL_MOUSEMOTION:
|
||||
if(event.motion.which != SDL_TOUCH_MOUSEID && event.motion.state == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(event.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT))
|
||||
{
|
||||
SDL_Rect r = CVideo::get_singleton().screen_area();
|
||||
|
||||
// TODO: Check if SDL_FINGERMOTION is actually signaled for COMPLETE motions (I doubt, but tbs)
|
||||
SDL_Event touch_event;
|
||||
touch_event.type = SDL_FINGERMOTION;
|
||||
touch_event.tfinger.type = SDL_FINGERMOTION;
|
||||
touch_event.tfinger.timestamp = event.motion.timestamp;
|
||||
touch_event.tfinger.touchId = 1;
|
||||
touch_event.tfinger.fingerId = 1;
|
||||
touch_event.tfinger.dx = static_cast<float>(event.motion.xrel) / r.w;
|
||||
touch_event.tfinger.dy = static_cast<float>(event.motion.yrel) / r.h;
|
||||
touch_event.tfinger.x = static_cast<float>(event.motion.x) / r.w;
|
||||
touch_event.tfinger.y = static_cast<float>(event.motion.y) / r.h;
|
||||
touch_event.tfinger.pressure = 1;
|
||||
::SDL_PushEvent(&touch_event);
|
||||
|
||||
event.motion.state = SDL_BUTTON(SDL_BUTTON_LEFT);
|
||||
event.motion.which = SDL_TOUCH_MOUSEID;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if(event.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
event.button.button = SDL_BUTTON_LEFT;
|
||||
event.button.which = SDL_TOUCH_MOUSEID;
|
||||
|
||||
SDL_Rect r = CVideo::get_singleton().screen_area();
|
||||
SDL_Event touch_event;
|
||||
touch_event.type = (event.type == SDL_MOUSEBUTTONDOWN) ? SDL_FINGERDOWN : SDL_FINGERUP;
|
||||
touch_event.tfinger.type = touch_event.type;
|
||||
touch_event.tfinger.timestamp = event.button.timestamp;
|
||||
touch_event.tfinger.touchId = 1;
|
||||
touch_event.tfinger.fingerId = 1;
|
||||
touch_event.tfinger.dx = 0;
|
||||
touch_event.tfinger.dy = 0;
|
||||
touch_event.tfinger.x = static_cast<float>(event.button.x) / r.w;
|
||||
touch_event.tfinger.y = static_cast<float>(event.button.y) / r.h;
|
||||
touch_event.tfinger.pressure = 1;
|
||||
::SDL_PushEvent(&touch_event);
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(event.type) {
|
||||
case SDL_WINDOWEVENT:
|
||||
switch(event.window.event) {
|
||||
|
|
|
@ -379,17 +379,30 @@ void sdl_event_handler::handle_event(const SDL_Event& event)
|
|||
return;
|
||||
}
|
||||
|
||||
Uint8 button = event.button.button;
|
||||
CVideo& video = dynamic_cast<window&>(*dispatchers_.back()).video();
|
||||
|
||||
switch(event.type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse(SDL_MOUSE_MOTION, {event.motion.x, event.motion.y});
|
||||
#ifdef MOUSE_TOUCH_EMULATION
|
||||
// There's no finger motion when it's not down.
|
||||
if (event.motion.state != 0)
|
||||
#endif
|
||||
{
|
||||
mouse(SDL_MOUSE_MOTION, {event.motion.x, event.motion.y});
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
mouse_button_down({event.button.x, event.button.y}, event.button.button);
|
||||
{
|
||||
mouse_button_down({event.button.x, event.button.y}, button);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
mouse_button_up({event.button.x, event.button.y}, event.button.button);
|
||||
{
|
||||
mouse_button_up({event.button.x, event.button.y}, button);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
|
@ -465,20 +478,33 @@ void sdl_event_handler::handle_event(const SDL_Event& event)
|
|||
break;
|
||||
|
||||
case SDL_FINGERMOTION:
|
||||
touch_motion(point(event.tfinger.x, event.tfinger.y), point(event.tfinger.dx, event.tfinger.dy));
|
||||
{
|
||||
SDL_Rect r = video.screen_area();
|
||||
touch_motion(point(event.tfinger.x * r.w, event.tfinger.y * r.h),
|
||||
point(event.tfinger.dx * r.w, event.tfinger.dy * r.h));
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_FINGERUP:
|
||||
touch_up(point(event.tfinger.x, event.tfinger.y));
|
||||
{
|
||||
SDL_Rect r = video.screen_area();
|
||||
touch_up(point(event.tfinger.x * r.w, event.tfinger.y * r.h));
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_FINGERDOWN:
|
||||
touch_down(point(event.tfinger.x, event.tfinger.y));
|
||||
{
|
||||
SDL_Rect r = video.screen_area();
|
||||
touch_down(point(event.tfinger.x * r.w, event.tfinger.y * r.h));
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MULTIGESTURE:
|
||||
touch_multi_gesture(point(event.mgesture.x, event.mgesture.y),
|
||||
event.mgesture.dTheta, event.mgesture.dDist, event.mgesture.numFingers);
|
||||
{
|
||||
SDL_Rect r = video.screen_area();
|
||||
touch_multi_gesture(point(event.mgesture.x * r.w, event.mgesture.y * r.h),
|
||||
event.mgesture.dTheta, event.mgesture.dDist, event.mgesture.numFingers);
|
||||
}
|
||||
break;
|
||||
|
||||
#if(defined(_X11) && !defined(__APPLE__)) || defined(_WIN32)
|
||||
|
|
|
@ -39,7 +39,6 @@ void hotkey_bind::pre_show(window& window)
|
|||
window.connect_signal<event::SDL_RAW_EVENT>(
|
||||
std::bind(&hotkey_bind::sdl_event_callback, this, std::ref(window), _5),
|
||||
event::dispatcher::front_child);
|
||||
|
||||
}
|
||||
|
||||
void hotkey_bind::sdl_event_callback(window& win, const SDL_Event &event)
|
||||
|
|
|
@ -593,7 +593,7 @@ void command_executor::queue_command(const SDL_Event& event, int index)
|
|||
bool keypress = (event.type == SDL_KEYDOWN || event.type == SDL_TEXTINPUT) &&
|
||||
!press_event_sent_;
|
||||
bool press = keypress ||
|
||||
(event.type == SDL_JOYBUTTONDOWN || event.type == SDL_MOUSEBUTTONDOWN);
|
||||
(event.type == SDL_JOYBUTTONDOWN || event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_FINGERDOWN);
|
||||
bool release = event.type == SDL_KEYUP;
|
||||
if(press) {
|
||||
LOG_HK << "sending press event (keypress = " <<
|
||||
|
|
|
@ -40,6 +40,11 @@ namespace hotkey {
|
|||
hotkey_list hotkeys_;
|
||||
config default_hotkey_cfg_;
|
||||
|
||||
namespace {
|
||||
const int TOUCH_MOUSE_INDEX = 255;
|
||||
const char TOUCH_MOUSE_STRING[] = "255";
|
||||
};
|
||||
|
||||
static unsigned int sdl_get_mods()
|
||||
{
|
||||
unsigned int mods;
|
||||
|
@ -196,7 +201,11 @@ hotkey_ptr load_from_config(const config& cfg)
|
|||
if (!mouse_cfg.empty()) {
|
||||
auto mouse = std::make_shared<hotkey_mouse>();
|
||||
base = std::dynamic_pointer_cast<hotkey_base>(mouse);
|
||||
mouse->set_button(cfg["button"].to_int());
|
||||
if (mouse_cfg == TOUCH_MOUSE_STRING) {
|
||||
mouse->set_button(TOUCH_MOUSE_INDEX);
|
||||
} else {
|
||||
mouse->set_button(cfg["button"].to_int());
|
||||
}
|
||||
}
|
||||
// TODO: add joystick support back
|
||||
#if 0
|
||||
|
@ -254,7 +263,10 @@ hotkey_ptr load_from_config(const config& cfg)
|
|||
|
||||
bool hotkey_mouse::matches_helper(const SDL_Event &event) const
|
||||
{
|
||||
if (event.type != SDL_MOUSEBUTTONUP && event.type != SDL_MOUSEBUTTONDOWN) {
|
||||
if (event.type != SDL_MOUSEBUTTONUP
|
||||
&& event.type != SDL_MOUSEBUTTONDOWN
|
||||
&& event.type != SDL_FINGERDOWN
|
||||
&& event.type != SDL_FINGERUP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -263,11 +275,11 @@ bool hotkey_mouse::matches_helper(const SDL_Event &event) const
|
|||
return false;
|
||||
}
|
||||
|
||||
if (event.button.button != button_) {
|
||||
return false;
|
||||
if (event.button.which == SDL_TOUCH_MOUSEID) {
|
||||
return button_ == TOUCH_MOUSE_INDEX;
|
||||
}
|
||||
|
||||
return true;
|
||||
return event.button.button == button_;
|
||||
}
|
||||
|
||||
const std::string hotkey_mouse::get_name_helper() const
|
||||
|
|
|
@ -89,9 +89,288 @@ void mouse_handler::set_side(int side_number)
|
|||
|
||||
int mouse_handler::drag_threshold() const
|
||||
{
|
||||
// TODO: Use physical screen size.
|
||||
return 14;
|
||||
}
|
||||
|
||||
void mouse_handler::touch_motion(int x, int y, const bool browse, bool update, map_location new_hex)
|
||||
{
|
||||
// Frankensteining from mouse_motion(), as it has a lot in common, but a lot of differences too.
|
||||
// Copy-pasted from everywhere. TODO: generalize the two.
|
||||
SDL_GetMouseState(&x,&y);
|
||||
|
||||
// This is from mouse_handler_base::mouse_motion_default()
|
||||
tooltips::process(x, y);
|
||||
|
||||
if(simple_warp_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(minimap_scrolling_) {
|
||||
const map_location& mini_loc = gui().minimap_location_on(x,y);
|
||||
if(mini_loc.valid()) {
|
||||
if(mini_loc != last_hex_) {
|
||||
last_hex_ = mini_loc;
|
||||
gui().scroll_to_tile(mini_loc,display::WARP,false);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
// clicking outside of the minimap will end minimap scrolling
|
||||
minimap_scrolling_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fire the drag & drop only after minimal drag distance
|
||||
// While we check the mouse buttons state, we also grab fresh position data.
|
||||
int mx = drag_from_x_; // some default value to prevent unlikely SDL bug
|
||||
int my = drag_from_y_;
|
||||
if(is_dragging() && !dragging_started_) {
|
||||
if(dragging_touch_) {
|
||||
SDL_GetMouseState(&mx, &my);
|
||||
const double drag_distance = std::pow(static_cast<double>(drag_from_x_- mx), 2)
|
||||
+ std::pow(static_cast<double>(drag_from_y_- my), 2);
|
||||
if(drag_distance > drag_threshold()*drag_threshold()) {
|
||||
dragging_started_ = true;
|
||||
// cursor::set_dragging(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// my own panning...
|
||||
bool selected_hex_has_unit = find_unit(selected_hex_).valid();
|
||||
if(!selected_hex_has_unit && is_dragging() && dragging_started_) {
|
||||
// Here, naive pan. In general, is it a problem that panning is synchronous?
|
||||
// Looks like it can do frameskips.
|
||||
// but does it use CPU? I think on iOS GPU is much more appropriate for panning.
|
||||
// What does SDL2 have to offer?
|
||||
|
||||
SDL_GetMouseState(&mx, &my);
|
||||
|
||||
int dx = drag_from_x_ - mx;
|
||||
int dy = drag_from_y_ - my;
|
||||
|
||||
gui().scroll(dx, dy);
|
||||
drag_from_x_ = mx;
|
||||
drag_from_y_ = my;
|
||||
return;
|
||||
}
|
||||
|
||||
// now copy-pasting mouse_handler::mouse_motion()
|
||||
|
||||
game_board & board = pc_.gamestate().board_;
|
||||
|
||||
if(new_hex == map_location::null_location())
|
||||
new_hex = gui().hex_clicked_on(x,y);
|
||||
|
||||
if(new_hex != last_hex_) {
|
||||
update = true;
|
||||
if( pc_.get_map_const().on_board(last_hex_) ) {
|
||||
// we store the previous hexes used to propose attack direction
|
||||
previous_hex_ = last_hex_;
|
||||
// the hex of the selected unit is also "free"
|
||||
{ // start planned unit map scope
|
||||
wb::future_map_if_active raii;
|
||||
if(last_hex_ == selected_hex_ || !find_unit(last_hex_)) {
|
||||
previous_free_hex_ = last_hex_;
|
||||
}
|
||||
} // end planned unit map scope
|
||||
}
|
||||
last_hex_ = new_hex;
|
||||
}
|
||||
|
||||
if(reachmap_invalid_) update = true;
|
||||
|
||||
if(!update) return;
|
||||
|
||||
if(reachmap_invalid_) {
|
||||
reachmap_invalid_ = false;
|
||||
if(!current_paths_.destinations.empty() && !show_partial_move_) {
|
||||
{ // start planned unit map scope
|
||||
wb::future_map_if_active planned_unit_map;
|
||||
selected_hex_has_unit = find_unit(selected_hex_).valid();
|
||||
} // end planned unit map scope
|
||||
if(selected_hex_.valid() && selected_hex_has_unit ) {
|
||||
// FIXME: vic: why doesn't this trigger when touch-dragging an unselected unit?
|
||||
// reselect the unit without firing events (updates current_paths_)
|
||||
select_hex(selected_hex_, true);
|
||||
}
|
||||
// we do never deselect here, mainly because of canceled attack-move
|
||||
}
|
||||
}
|
||||
|
||||
// reset current_route_ and current_paths if not valid anymore
|
||||
// we do it before cursor selection, because it uses current_paths_
|
||||
if( !pc_.get_map_const().on_board(new_hex) ) {
|
||||
current_route_.steps.clear();
|
||||
gui().set_route(nullptr);
|
||||
pc_.get_whiteboard()->erase_temp_move();
|
||||
}
|
||||
|
||||
if(unselected_paths_) {
|
||||
unselected_paths_ = false;
|
||||
current_paths_ = pathfind::paths();
|
||||
gui().unhighlight_reach();
|
||||
} else if(over_route_) {
|
||||
over_route_ = false;
|
||||
current_route_.steps.clear();
|
||||
gui().set_route(nullptr);
|
||||
pc_.get_whiteboard()->erase_temp_move();
|
||||
}
|
||||
|
||||
gui().highlight_hex(new_hex);
|
||||
pc_.get_whiteboard()->on_mouseover_change(new_hex);
|
||||
|
||||
unit_map::iterator selected_unit;
|
||||
unit_map::iterator mouseover_unit;
|
||||
map_location attack_from;
|
||||
|
||||
{ // start planned unit map scope
|
||||
wb::future_map_if_active planned_unit_map;
|
||||
selected_unit = find_unit(selected_hex_);
|
||||
mouseover_unit = find_unit(new_hex);
|
||||
|
||||
// we search if there is an attack possibility and where
|
||||
attack_from = current_unit_attacks_from(new_hex);
|
||||
|
||||
//see if we should show the normal cursor, the movement cursor, or
|
||||
//the attack cursor
|
||||
//If the cursor is on WAIT, we don't change it and let the setter
|
||||
//of this state end it
|
||||
if (cursor::get() != cursor::WAIT) {
|
||||
if (selected_unit &&
|
||||
selected_unit->side() == side_num_ &&
|
||||
!selected_unit->incapacitated() && !browse)
|
||||
{
|
||||
if (attack_from.valid()) {
|
||||
cursor::set(dragging_started_ ? cursor::ATTACK_DRAG : cursor::ATTACK);
|
||||
}
|
||||
else if (!mouseover_unit &&
|
||||
current_paths_.destinations.contains(new_hex))
|
||||
{
|
||||
// Is this where left-drag cursor changes? Test.
|
||||
cursor::set(dragging_started_ ? cursor::MOVE_DRAG : cursor::MOVE);
|
||||
} else {
|
||||
// selected unit can't attack or move there
|
||||
cursor::set(cursor::NORMAL);
|
||||
}
|
||||
} else {
|
||||
// no selected unit or we can't move it
|
||||
|
||||
if ( selected_hex_.valid() && mouseover_unit
|
||||
&& mouseover_unit->side() == side_num_ ) {
|
||||
// empty hex field selected and unit on our site under the cursor
|
||||
cursor::set(dragging_started_ ? cursor::MOVE_DRAG : cursor::MOVE);
|
||||
} else {
|
||||
cursor::set(cursor::NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end planned unit map scope
|
||||
|
||||
// show (or cancel) the attack direction indicator
|
||||
if(attack_from.valid() && (!browse || pc_.get_whiteboard()->is_active())) {
|
||||
gui().set_attack_indicator(attack_from, new_hex);
|
||||
} else {
|
||||
gui().clear_attack_indicator();
|
||||
}
|
||||
|
||||
unit_ptr un; //will later point to unit at mouseover_hex_
|
||||
|
||||
// the destination is the pointed hex or the adjacent hex
|
||||
// used to attack it
|
||||
map_location dest;
|
||||
unit_map::const_iterator dest_un;
|
||||
{ // start planned unit map scope
|
||||
wb::future_map_if_active raii;
|
||||
if (attack_from.valid()) {
|
||||
dest = attack_from;
|
||||
dest_un = find_unit(dest);
|
||||
} else {
|
||||
dest = new_hex;
|
||||
dest_un = find_unit(new_hex);
|
||||
}
|
||||
|
||||
if(dest == selected_hex_ || dest_un) {
|
||||
current_route_.steps.clear();
|
||||
gui().set_route(nullptr);
|
||||
pc_.get_whiteboard()->erase_temp_move();
|
||||
}
|
||||
else if (!current_paths_.destinations.empty() &&
|
||||
board.map().on_board(selected_hex_) && board.map().on_board(new_hex))
|
||||
{
|
||||
if (selected_unit && !selected_unit->incapacitated()) {
|
||||
// Show the route from selected unit to mouseover hex
|
||||
current_route_ = get_route(&*selected_unit, dest, viewing_team());
|
||||
|
||||
pc_.get_whiteboard()->create_temp_move();
|
||||
|
||||
if(!browse) {
|
||||
gui().set_route(¤t_route_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(board.map().on_board(selected_hex_)
|
||||
&& !selected_unit
|
||||
&& mouseover_unit.valid()
|
||||
&& mouseover_unit) {
|
||||
// Show the route from selected hex to mouseover unit
|
||||
current_route_ = get_route(&*mouseover_unit, selected_hex_, viewing_team());
|
||||
|
||||
pc_.get_whiteboard()->create_temp_move();
|
||||
|
||||
if(!browse) {
|
||||
gui().set_route(¤t_route_);
|
||||
}
|
||||
} else if (!selected_unit) {
|
||||
current_route_.steps.clear();
|
||||
gui().set_route(nullptr);
|
||||
pc_.get_whiteboard()->erase_temp_move();
|
||||
}
|
||||
|
||||
unit_map::iterator iter = mouseover_unit;
|
||||
if (iter)
|
||||
un = iter.get_shared_ptr();
|
||||
else
|
||||
un.reset();
|
||||
} //end planned unit map scope
|
||||
|
||||
if( (!selected_hex_.valid()) && un && current_paths_.destinations.empty() &&
|
||||
!gui().fogged(un->get_location()))
|
||||
{
|
||||
if (un->side() == side_num_) {
|
||||
//unit is on our team, show path if the unit has one
|
||||
const map_location go_to = un->get_goto();
|
||||
if(board.map().on_board(go_to)) {
|
||||
pathfind::marked_route route;
|
||||
{ // start planned unit map scope
|
||||
wb::future_map_if_active raii;
|
||||
route = get_route(un.get(), go_to, current_team());
|
||||
} // end planned unit map scope
|
||||
gui().set_route(&route);
|
||||
}
|
||||
over_route_ = true;
|
||||
|
||||
wb::future_map_if_active raii;
|
||||
current_paths_ = pathfind::paths(*un, false, true,
|
||||
viewing_team(), path_turns_);
|
||||
} else {
|
||||
//unit under cursor is not on our team
|
||||
//Note: planned unit map must be activated after this is done,
|
||||
//since the future state includes changes to units' movement.
|
||||
unit_movement_resetter move_reset(*un);
|
||||
|
||||
wb::future_map_if_active raii;
|
||||
current_paths_ = pathfind::paths(*un, false, true,
|
||||
viewing_team(), path_turns_);
|
||||
}
|
||||
|
||||
unselected_paths_ = true;
|
||||
gui().highlight_reach(current_paths_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mouse_handler::mouse_motion(int x, int y, const bool browse, bool update, map_location new_hex)
|
||||
{
|
||||
// we ignore the position coming from event handler
|
||||
|
@ -235,8 +514,8 @@ void mouse_handler::mouse_motion(int x, int y, const bool browse, bool update, m
|
|||
// used to attack it
|
||||
map_location dest;
|
||||
unit_map::const_iterator dest_un;
|
||||
|
||||
{ // start planned unit map scope
|
||||
/* start planned unit map scope*/
|
||||
{
|
||||
wb::future_map_if_active raii;
|
||||
if(attack_from.valid()) {
|
||||
dest = attack_from;
|
||||
|
@ -279,13 +558,12 @@ void mouse_handler::mouse_motion(int x, int y, const bool browse, bool update, m
|
|||
pc_.get_whiteboard()->erase_temp_move();
|
||||
}
|
||||
|
||||
unit_map::iterator iter = mouseover_unit;
|
||||
if(iter) {
|
||||
un = iter.get_shared_ptr();
|
||||
if(mouseover_unit) {
|
||||
un = mouseover_unit.get_shared_ptr();
|
||||
} else {
|
||||
un.reset();
|
||||
}
|
||||
} // end planned unit map scope
|
||||
} /*end planned unit map scope*/
|
||||
|
||||
if((!selected_hex_.valid()) && un && current_paths_.destinations.empty() && !gui().fogged(un->get_location())) {
|
||||
/*
|
||||
|
|
|
@ -130,6 +130,8 @@ protected:
|
|||
// bool left_click(int x, int y, const bool browse);
|
||||
bool move_unit_along_current_route();
|
||||
|
||||
void touch_motion(int x, int y, const bool browse, bool update=false, map_location loc = map_location::null_location());
|
||||
|
||||
void save_whiteboard_attack(const map_location& attacker_loc, const map_location& defender_loc, int weapon_choice);
|
||||
|
||||
// fill weapon choices into bc_vector
|
||||
|
|
|
@ -54,6 +54,7 @@ mouse_handler_base::mouse_handler_base()
|
|||
, dragging_left_(false)
|
||||
, dragging_started_(false)
|
||||
, dragging_right_(false)
|
||||
, dragging_touch_(false)
|
||||
, drag_from_x_(0)
|
||||
, drag_from_y_(0)
|
||||
, drag_from_hex_()
|
||||
|
@ -67,7 +68,7 @@ mouse_handler_base::mouse_handler_base()
|
|||
|
||||
bool mouse_handler_base::is_dragging() const
|
||||
{
|
||||
return dragging_left_ || dragging_right_;
|
||||
return dragging_left_ || dragging_right_ || dragging_touch_;
|
||||
}
|
||||
|
||||
void mouse_handler_base::mouse_motion_event(const SDL_MouseMotionEvent& event, const bool browse)
|
||||
|
@ -75,6 +76,11 @@ void mouse_handler_base::mouse_motion_event(const SDL_MouseMotionEvent& event, c
|
|||
mouse_motion(event.x, event.y, browse);
|
||||
}
|
||||
|
||||
void mouse_handler_base::touch_motion_event(const SDL_TouchFingerEvent& event, const bool browse)
|
||||
{
|
||||
touch_motion(event.x, event.y, browse);
|
||||
}
|
||||
|
||||
void mouse_handler_base::mouse_update(const bool browse, map_location loc)
|
||||
{
|
||||
int x, y;
|
||||
|
@ -94,8 +100,7 @@ bool mouse_handler_base::mouse_motion_default(int x, int y, bool /*update*/)
|
|||
// if the game is run in a window, we could miss a LMB/MMB up event
|
||||
// if it occurs outside our window.
|
||||
// thus, we need to check if the LMB/MMB is still down
|
||||
minimap_scrolling_ = ((SDL_GetMouseState(nullptr, nullptr) & (SDL_BUTTON(1) | SDL_BUTTON(2))) != 0);
|
||||
|
||||
minimap_scrolling_ = ((SDL_GetMouseState(nullptr, nullptr) & (SDL_BUTTON(SDL_BUTTON_LEFT) | SDL_BUTTON(SDL_BUTTON_MIDDLE))) != 0);
|
||||
if(minimap_scrolling_) {
|
||||
const map_location& loc = gui().minimap_location_on(x, y);
|
||||
if(loc.valid()) {
|
||||
|
@ -120,12 +125,19 @@ bool mouse_handler_base::mouse_motion_default(int x, int y, bool /*update*/)
|
|||
int my = drag_from_y_;
|
||||
|
||||
if(is_dragging() && !dragging_started_) {
|
||||
if((dragging_left_ && (SDL_GetMouseState(&mx, &my) & SDL_BUTTON_LEFT) != 0) ||
|
||||
(dragging_right_ && (SDL_GetMouseState(&mx, &my) & SDL_BUTTON_RIGHT) != 0))
|
||||
Uint32 mouse_state = dragging_left_ || dragging_right_ ? SDL_GetMouseState(&mx, &my) : 0;
|
||||
#ifdef MOUSE_TOUCH_EMULATION
|
||||
if(dragging_left_ && (mouse_state & SDL_BUTTON(SDL_BUTTON_RIGHT))) {
|
||||
// Monkey-patch touch controls again to make them look like left button.
|
||||
mouse_state = SDL_BUTTON(SDL_BUTTON_LEFT);
|
||||
}
|
||||
#endif
|
||||
if((dragging_left_ && (mouse_state & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0) ||
|
||||
(dragging_right_ && (mouse_state & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0))
|
||||
{
|
||||
const double drag_distance =
|
||||
std::pow(static_cast<double>(drag_from_x_ - mx), 2) +
|
||||
std::pow(static_cast<double>(drag_from_y_ - my), 2);
|
||||
std::pow(static_cast<double>(drag_from_x_- mx), 2) +
|
||||
std::pow(static_cast<double>(drag_from_y_- my), 2);
|
||||
|
||||
if(drag_distance > drag_threshold() * drag_threshold()) {
|
||||
dragging_started_ = true;
|
||||
|
@ -147,7 +159,35 @@ void mouse_handler_base::mouse_press(const SDL_MouseButtonEvent& event, const bo
|
|||
map_location loc = gui().hex_clicked_on(event.x, event.y);
|
||||
mouse_update(browse, loc);
|
||||
|
||||
if(is_left_click(event)) {
|
||||
static time_t touch_timestamp = 0;
|
||||
|
||||
if(is_touch_click(event)) {
|
||||
if (event.state == SDL_PRESSED) {
|
||||
cancel_dragging();
|
||||
touch_timestamp = time(NULL);
|
||||
init_dragging(dragging_touch_);
|
||||
left_click(event.x, event.y, browse);
|
||||
} else if (event.state == SDL_RELEASED) {
|
||||
minimap_scrolling_ = false;
|
||||
|
||||
if (!dragging_started_ && touch_timestamp > 0) {
|
||||
time_t dt = clock() - touch_timestamp;
|
||||
// I couldn't make this work. Sorry for some C.
|
||||
// auto dt_cpp = high_resolution_clock::now() - touch_timestamp_cpp;
|
||||
// auto dt2 = duration_cast<milliseconds>(dt_cpp);
|
||||
// auto menu_hold = milliseconds(300);
|
||||
// if (dt2 > menu_hold) {
|
||||
if (dt > CLOCKS_PER_SEC * 3 / 10) {
|
||||
right_click(event.x, event.y, browse); // show_menu_ = true;
|
||||
}
|
||||
} else {
|
||||
touch_timestamp = 0;
|
||||
}
|
||||
|
||||
clear_dragging(event, browse);
|
||||
left_mouse_up(event.x, event.y, browse);
|
||||
}
|
||||
} else if(is_left_click(event)) {
|
||||
if(event.state == SDL_PRESSED) {
|
||||
cancel_dragging();
|
||||
init_dragging(dragging_left_);
|
||||
|
@ -192,8 +232,7 @@ void mouse_handler_base::mouse_press(const SDL_MouseButtonEvent& event, const bo
|
|||
scroll_started_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!dragging_left_ && !dragging_right_ && dragging_started_) {
|
||||
if(!dragging_left_ && !dragging_right_ && !dragging_touch_ && dragging_started_) {
|
||||
dragging_started_ = false;
|
||||
cursor::set_dragging(false);
|
||||
}
|
||||
|
@ -203,6 +242,14 @@ void mouse_handler_base::mouse_press(const SDL_MouseButtonEvent& event, const bo
|
|||
|
||||
bool mouse_handler_base::is_left_click(const SDL_MouseButtonEvent& event) const
|
||||
{
|
||||
#ifdef MOUSE_TOUCH_EMULATION
|
||||
if(event.button == SDL_BUTTON_RIGHT) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if(event.which == SDL_TOUCH_MOUSEID) {
|
||||
return false;
|
||||
}
|
||||
return event.button == SDL_BUTTON_LEFT && !command_active();
|
||||
}
|
||||
|
||||
|
@ -213,7 +260,21 @@ bool mouse_handler_base::is_middle_click(const SDL_MouseButtonEvent& event) cons
|
|||
|
||||
bool mouse_handler_base::is_right_click(const SDL_MouseButtonEvent& event) const
|
||||
{
|
||||
return event.button == SDL_BUTTON_RIGHT || (event.button == SDL_BUTTON_LEFT && command_active());
|
||||
#ifdef MOUSE_TOUCH_EMULATION
|
||||
(void) event;
|
||||
return false;
|
||||
#else
|
||||
if(event.which == SDL_TOUCH_MOUSEID) {
|
||||
return false;
|
||||
}
|
||||
return event.button == SDL_BUTTON_RIGHT
|
||||
|| (event.button == SDL_BUTTON_LEFT && command_active());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool mouse_handler_base::is_touch_click(const SDL_MouseButtonEvent& event) const
|
||||
{
|
||||
return event.which == SDL_TOUCH_MOUSEID;
|
||||
}
|
||||
|
||||
bool mouse_handler_base::left_click(int x, int y, const bool /*browse*/)
|
||||
|
@ -301,6 +362,7 @@ void mouse_handler_base::cancel_dragging()
|
|||
{
|
||||
dragging_started_ = false;
|
||||
dragging_left_ = false;
|
||||
dragging_touch_ = false;
|
||||
dragging_right_ = false;
|
||||
cursor::set_dragging(false);
|
||||
}
|
||||
|
@ -314,6 +376,13 @@ void mouse_handler_base::clear_dragging(const SDL_MouseButtonEvent& event, bool
|
|||
|
||||
if(dragging_started_) {
|
||||
dragging_started_ = false;
|
||||
|
||||
if(dragging_touch_) {
|
||||
dragging_touch_ = false;
|
||||
// Maybe to do: create touch_drag_end(). Do panning and what else there. OTOH, it's fine now.
|
||||
left_drag_end(event.x, event.y, browse);
|
||||
}
|
||||
|
||||
if(dragging_left_) {
|
||||
dragging_left_ = false;
|
||||
left_drag_end(event.x, event.y, browse);
|
||||
|
@ -326,6 +395,7 @@ void mouse_handler_base::clear_dragging(const SDL_MouseButtonEvent& event, bool
|
|||
} else {
|
||||
dragging_left_ = false;
|
||||
dragging_right_ = false;
|
||||
dragging_touch_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,8 @@ public:
|
|||
|
||||
void mouse_motion_event(const SDL_MouseMotionEvent& event, const bool browse);
|
||||
|
||||
void touch_motion_event(const SDL_TouchFingerEvent& event, const bool browse);
|
||||
|
||||
/** Update the mouse with a fake mouse motion */
|
||||
void mouse_update(const bool browse, map_location loc);
|
||||
|
||||
|
@ -85,10 +87,15 @@ public:
|
|||
int x, int y, const bool browse, bool update = false, map_location new_loc = map_location::null_location())
|
||||
= 0;
|
||||
|
||||
virtual void touch_motion(
|
||||
int x, int y, const bool browse, bool update = false, map_location new_loc = map_location::null_location())
|
||||
= 0;
|
||||
|
||||
virtual void mouse_press(const SDL_MouseButtonEvent& event, const bool browse);
|
||||
bool is_left_click(const SDL_MouseButtonEvent& event) const;
|
||||
bool is_middle_click(const SDL_MouseButtonEvent& event) const;
|
||||
bool is_right_click(const SDL_MouseButtonEvent& event) const;
|
||||
bool is_touch_click(const SDL_MouseButtonEvent& event) const;
|
||||
|
||||
/** Called when scrolling with the mouse wheel. */
|
||||
virtual void mouse_wheel(int xscroll, int yscroll, bool browse);
|
||||
|
@ -214,6 +221,9 @@ protected:
|
|||
/** LMB drag init flag */
|
||||
bool dragging_left_;
|
||||
|
||||
/** Finger drag init flag */
|
||||
bool dragging_touch_;
|
||||
|
||||
/** Actual drag flag */
|
||||
bool dragging_started_;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue