diff --git a/client/VCMI_client.vcxproj b/client/VCMI_client.vcxproj
index ec30a83ab..9d0476656 100644
--- a/client/VCMI_client.vcxproj
+++ b/client/VCMI_client.vcxproj
@@ -292,6 +292,4 @@
-
-
\ No newline at end of file
diff --git a/client/VCMI_client.vcxproj.filters b/client/VCMI_client.vcxproj.filters
index d389ba18b..b044f1d67 100644
--- a/client/VCMI_client.vcxproj.filters
+++ b/client/VCMI_client.vcxproj.filters
@@ -109,17 +109,10 @@
gui
-
-
-
- Source Files
-
+
-
- Header Files
-
@@ -254,5 +247,6 @@
gui
+
\ No newline at end of file
diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp
index c4eb536ad..57345a1e4 100644
--- a/client/gui/CGuiHandler.cpp
+++ b/client/gui/CGuiHandler.cpp
@@ -60,6 +60,7 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::functioncurh->cursorMove(sEvent->motion.x, sEvent->motion.y);
handleMouseMotion(sEvent);
}
- else if (sEvent->type==SDL_MOUSEBUTTONDOWN)
+ else if(sEvent->type == SDL_MOUSEBUTTONDOWN)
{
- if(sEvent->button.button == SDL_BUTTON_LEFT)
+ switch(sEvent->button.button)
{
-
- if(lastClick == sEvent->motion && (SDL_GetTicks() - lastClickTime) < 300)
+ case SDL_BUTTON_LEFT:
+ if(lastClick == sEvent->motion && (SDL_GetTicks() - lastClickTime) < 300)
{
std::list hlp = doubleClickInterested;
- for(auto i=hlp.begin(); i != hlp.end() && current; i++)
+ for(auto i = hlp.begin(); i != hlp.end() && current; i++)
{
- if(!vstd::contains(doubleClickInterested,*i)) continue;
- if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
+ if(!vstd::contains(doubleClickInterested, *i)) continue;
+ if(isItIn(&(*i)->pos, sEvent->motion.x, sEvent->motion.y))
{
(*i)->onDoubleClick();
}
@@ -282,31 +283,16 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
lastClick = sEvent->motion;
lastClickTime = SDL_GetTicks();
- std::list hlp = lclickable;
- for(auto i=hlp.begin(); i != hlp.end() && current; i++)
- {
- if(!vstd::contains(lclickable,*i)) continue;
- if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
- {
- prev = (*i)->pressedL;
- (*i)->pressedL = true;
- (*i)->clickLeft(true, prev);
- }
- }
- }
- else if (sEvent->button.button == SDL_BUTTON_RIGHT)
- {
- std::list hlp = rclickable;
- for(auto i=hlp.begin(); i != hlp.end() && current; i++)
- {
- if(!vstd::contains(rclickable,*i)) continue;
- if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
- {
- prev = (*i)->pressedR;
- (*i)->pressedR = true;
- (*i)->clickRight(true, prev);
- }
- }
+ handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, true);
+ break;
+ case SDL_BUTTON_RIGHT:
+ handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
+ break;
+ case SDL_BUTTON_MIDDLE:
+ handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, true);
+ break;
+ default:
+ break;
}
}
else if (sEvent->type == SDL_MOUSEWHEEL)
@@ -336,41 +322,45 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
}
}
//todo: muiltitouch
- else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_LEFT))
+ else if(sEvent->type == SDL_MOUSEBUTTONUP)
{
- std::list hlp = lclickable;
- for(auto i=hlp.begin(); i != hlp.end() && current; i++)
+ switch(sEvent->button.button)
{
- if(!vstd::contains(lclickable,*i)) continue;
- prev = (*i)->pressedL;
- (*i)->pressedL = false;
- if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
- {
- (*i)->clickLeft(false, prev);
- }
- else
- (*i)->clickLeft(boost::logic::indeterminate, prev);
- }
- }
- else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_RIGHT))
- {
- std::list hlp = rclickable;
- for(auto i=hlp.begin(); i != hlp.end() && current; i++)
- {
- if(!vstd::contains(rclickable,*i)) continue;
- prev = (*i)->pressedR;
- (*i)->pressedR = false;
- if (isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y))
- {
- (*i)->clickRight(false, prev);
- }
- else
- (*i)->clickRight(boost::logic::indeterminate, prev);
+ case SDL_BUTTON_LEFT:
+ handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false);
+ break;
+ case SDL_BUTTON_RIGHT:
+ handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
+ break;
+ case SDL_BUTTON_MIDDLE:
+ handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false);
+ break;
}
}
current = nullptr;
} //event end
+void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed)
+{
+ auto hlp = interestedObjs;
+ for(auto i = hlp.begin(); i != hlp.end() && current; i++)
+ {
+ if(!vstd::contains(interestedObjs, *i)) continue;
+
+ auto prev = (*i)->mouseState(btn);
+ if(!isPressed)
+ (*i)->updateMouseState(btn, isPressed);
+ if(isItIn(&(*i)->pos, current->motion.x, current->motion.y))
+ {
+ if(isPressed)
+ (*i)->updateMouseState(btn, isPressed);
+ (*i)->click(btn, isPressed, prev);
+ }
+ else if(!isPressed)
+ (*i)->click(btn, boost::logic::indeterminate, prev);
+ }
+}
+
void CGuiHandler::handleMouseMotion(SDL_Event *sEvent)
{
//sending active, hovered hoverable objects hover() call
diff --git a/client/gui/CGuiHandler.h b/client/gui/CGuiHandler.h
index 3449dd76c..9a10d24eb 100644
--- a/client/gui/CGuiHandler.h
+++ b/client/gui/CGuiHandler.h
@@ -10,6 +10,7 @@ class CIntObject;
class IUpdateable;
class IShowActivatable;
class IShowable;
+enum class EIntObjMouseBtnType;
template struct CondSh;
/*
@@ -53,6 +54,7 @@ private:
//active GUI elements (listening for events
CIntObjectList lclickable,
rclickable,
+ mclickable,
hoverable,
keyinterested,
motioninterested,
@@ -62,6 +64,7 @@ private:
textInterested;
+ void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed);
void processLists(const ui16 activityFlag, std::function *)> cb);
public:
void handleElementActivate(CIntObject * elem, ui16 activityFlag);
diff --git a/client/gui/CIntObject.cpp b/client/gui/CIntObject.cpp
index 8fa3b3025..40e7c281f 100644
--- a/client/gui/CIntObject.cpp
+++ b/client/gui/CIntObject.cpp
@@ -16,7 +16,7 @@ CIntObject::CIntObject(int used_, Point pos_):
parent(parent_m),
active(active_m)
{
- pressedL = pressedR = hovered = captureAllKeys = strongInterest = false;
+ hovered = captureAllKeys = strongInterest = false;
toNextTick = timerDelay = 0;
used = used_;
@@ -134,6 +134,23 @@ CIntObject::~CIntObject()
parent_m->removeChild(this);
}
+void CIntObject::click(EIntObjMouseBtnType btn, tribool down, bool previousState)
+{
+ switch(btn)
+ {
+ default:
+ case EIntObjMouseBtnType::LEFT:
+ clickLeft(down, previousState);
+ break;
+ case EIntObjMouseBtnType::MIDDLE:
+ clickMiddle(down, previousState);
+ break;
+ case EIntObjMouseBtnType::RIGHT:
+ clickRight(down, previousState);
+ break;
+ }
+}
+
void CIntObject::printAtLoc( const std::string & text, int x, int y, EFonts font, SDL_Color kolor/*=Colors::WHITE*/, SDL_Surface * dst/*=screen*/ )
{
graphics->fonts[font]->renderTextLeft(dst, text, kolor, Point(pos.x + x, pos.y + y));
@@ -340,16 +357,9 @@ void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
if(vstd::contains(assignedKeys,key.keysym.sym)
|| vstd::contains(assignedKeys, CGuiHandler::numToDigit(key.keysym.sym)))
{
- bool prev = pressedL;
- if(key.state == SDL_PRESSED)
- {
- pressedL = true;
- clickLeft(true, prev);
- }
- else
- {
- pressedL = false;
- clickLeft(false, prev);
- }
+ bool prev = mouseState(EIntObjMouseBtnType::LEFT);
+ updateMouseState(EIntObjMouseBtnType::LEFT, key.state == SDL_PRESSED);
+ clickLeft(key.state == SDL_PRESSED, prev);
+
}
}
diff --git a/client/gui/CIntObject.h b/client/gui/CIntObject.h
index 75d8c2507..31f479738 100644
--- a/client/gui/CIntObject.h
+++ b/client/gui/CIntObject.h
@@ -61,6 +61,7 @@ public:
virtual ~IShowActivatable(){}; //d-tor
};
+enum class EIntObjMouseBtnType { LEFT, MIDDLE, RIGHT };
//typedef ui16 ActivityFlag;
// Base UI element
@@ -73,6 +74,8 @@ class CIntObject : public IShowActivatable //interface object
int toNextTick;
int timerDelay;
+ std::map currentMouseState;
+
void onTimer(int timePassed);
//non-const versions of fields to allow changing them in CIntObject
@@ -104,13 +107,13 @@ public:
CIntObject(int used=0, Point offset=Point());
virtual ~CIntObject(); //d-tor
- //l-clicks handling
- /*const*/ bool pressedL; //for determining if object is L-pressed
- virtual void clickLeft(tribool down, bool previousState){}
+ void updateMouseState(EIntObjMouseBtnType btn, bool state) { currentMouseState[btn] = state; }
+ bool mouseState(EIntObjMouseBtnType btn) const { return currentMouseState.count(btn) ? currentMouseState.at(btn) : false; }
- //r-clicks handling
- /*const*/ bool pressedR; //for determining if object is R-pressed
- virtual void clickRight(tribool down, bool previousState){}
+ virtual void click(EIntObjMouseBtnType btn, tribool down, bool previousState);
+ virtual void clickLeft(tribool down, bool previousState) {}
+ virtual void clickRight(tribool down, bool previousState) {}
+ virtual void clickMiddle(tribool down, bool previousState) {}
//hover handling
/*const*/ bool hovered; //for determining if object is hovered
@@ -138,7 +141,7 @@ public:
//double click
virtual void onDoubleClick(){}
- enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, ALL=0xffff};
+ enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, MCLICK=1024, ALL=0xffff};
const ui16 & active;
void addUsedEvents(ui16 newActions);
void removeUsedEvents(ui16 newActions);
diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp
index 1cea6ad3c..12019ad92 100644
--- a/client/widgets/AdventureMapClasses.cpp
+++ b/client/widgets/AdventureMapClasses.cpp
@@ -587,7 +587,7 @@ void CMinimap::hover(bool on)
void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent)
{
- if (pressedL)
+ if(mouseState(EIntObjMouseBtnType::LEFT))
moveAdvMapSelection();
}
diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp
index 8784e0d1a..7abc4a5c5 100644
--- a/client/widgets/Buttons.cpp
+++ b/client/widgets/Buttons.cpp
@@ -623,7 +623,7 @@ void CSlider::clickLeft(tribool down, bool previousState)
return;
// if (rw>1) return;
// if (rw<0) return;
- slider->clickLeft(true, slider->pressedL);
+ slider->clickLeft(true, slider->mouseState(EIntObjMouseBtnType::LEFT));
moveTo(rw * positions + 0.5);
return;
}
diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp
index e82e34a9e..131e510e2 100644
--- a/client/windows/CAdvmapInterface.cpp
+++ b/client/windows/CAdvmapInterface.cpp
@@ -98,7 +98,7 @@ CTerrainRect::CTerrainRect()
pos.w=ADVOPT.advmapW;
pos.h=ADVOPT.advmapH;
moveX = moveY = 0;
- addUsedEvents(LCLICK | RCLICK | HOVER | MOVE);
+ addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE);
}
CTerrainRect::~CTerrainRect()
@@ -124,17 +124,10 @@ void CTerrainRect::clickLeft(tribool down, bool previousState)
#ifdef VCMI_ANDROID
if(adventureInt->swipeEnabled)
{
- if(down == true)
+ if(handleSwipeStateChange(down == true))
{
- swipeInitialRealPos = int3(GH.current->motion.x, GH.current->motion.y, 0);
- swipeInitialMapPos = int3(adventureInt->position);
return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture)
}
- else if(isSwiping) // only accept this touch if it wasn't a swipe
- {
- isSwiping = false;
- return;
- }
}
else
{
@@ -165,22 +158,32 @@ void CTerrainRect::clickRight(tribool down, bool previousState)
adventureInt->tileRClicked(mp);
}
+void CTerrainRect::clickMiddle(tribool down, bool previousState)
+{
+ handleSwipeStateChange(down == true);
+}
+
void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
{
handleHover(sEvent);
-#ifdef VCMI_ANDROID
- if(!adventureInt->swipeEnabled || sEvent.state == 0)
+ if(!adventureInt->swipeEnabled)
return;
handleSwipeMove(sEvent);
-#endif // !VCMI_ANDROID
}
-#ifdef VCMI_ANDROID
-
void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
{
+#ifdef VCMI_ANDROID
+ if(sEvent.state == 0) // any "button" is enough on android
+#else //!VCMI_ANDROID
+ if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms
+#endif //!VCMI_ANDROID
+ {
+ return;
+ }
+
if(!isSwiping)
{
// try to distinguish if this touch was meant to be a swipe or just fat-fingering press
@@ -201,7 +204,21 @@ void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
}
}
-#endif // VCMI_ANDROID
+bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
+{
+ if(btnPressed)
+ {
+ swipeInitialRealPos = int3(GH.current->motion.x, GH.current->motion.y, 0);
+ swipeInitialMapPos = int3(adventureInt->position);
+ return true;
+ }
+ else if(isSwiping) // only accept this touch if it wasn't a swipe
+ {
+ isSwiping = false;
+ return true;
+ }
+ return false;
+}
void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent)
{
@@ -534,11 +551,9 @@ CAdvMapInt::CAdvMapInt():
infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA),
spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr),
updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0),
- activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false)
-#ifdef VCMI_ANDROID
- , swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false),
+ activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false),
+ swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false),
swipeTargetPosition(int3(-1, -1, -1))
-#endif
{
adventureInt = this;
pos.x = pos.y = 0;
@@ -1007,18 +1022,16 @@ void CAdvMapInt::show(SDL_Surface * to)
}
++heroAnim;
-#ifdef VCMI_ANDROID
if(swipeEnabled)
{
handleSwipeUpdate();
}
+#ifdef VCMI_ANDROID // on android, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked)
else
+#endif // VCMI_ANDROID
{
-#endif // !VCMI_ANDROID
handleMapScrollingUpdate();
-#ifdef VCMI_ANDROID
}
-#endif
for(int i = 0; i < 4; i++)
{
@@ -1089,14 +1102,13 @@ void CAdvMapInt::handleMapScrollingUpdate()
}
}
-#ifdef VCMI_ANDROID
-
void CAdvMapInt::handleSwipeUpdate()
{
if(swipeMovementRequested)
{
- position.x = swipeTargetPosition.x;
- position.y = swipeTargetPosition.y;
+ auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition);
+ position.x = fixedPos.x;
+ position.y = fixedPos.y;
CCS->curh->changeGraphic(ECursor::DEFAULT, 0);
updateScreen = true;
minimap.redraw();
@@ -1104,8 +1116,6 @@ void CAdvMapInt::handleSwipeUpdate()
}
}
-#endif
-
void CAdvMapInt::selectionChanged()
{
const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()];
diff --git a/client/windows/CAdvmapInterface.h b/client/windows/CAdvmapInterface.h
index 8ae36b743..fca0b3da1 100644
--- a/client/windows/CAdvmapInterface.h
+++ b/client/windows/CAdvmapInterface.h
@@ -62,10 +62,10 @@ class CTerrainRect
bool isSwiping;
static constexpr float SwipeTouchSlop = 16.0f;
- void handleHover(const SDL_MouseMotionEvent &sEvent);
-#ifdef VCMI_ANDROID
- void handleSwipeMove(const SDL_MouseMotionEvent &sEvent);
-#endif // VCMI_ANDROID
+ void handleHover(const SDL_MouseMotionEvent & sEvent);
+ void handleSwipeMove(const SDL_MouseMotionEvent & sEvent);
+ /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled
+ bool handleSwipeStateChange(bool btnPressed);
public:
int tilesw, tilesh; //width and height of terrain to blit in tiles
int3 curHoveredTile;
@@ -77,6 +77,7 @@ public:
void deactivate() override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
+ void clickMiddle(tribool down, bool previousState) override;
void hover(bool on) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void show(SDL_Surface * to) override;
@@ -132,11 +133,9 @@ public:
enum{LEFT=1, RIGHT=2, UP=4, DOWN=8};
ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN
bool scrollingState;
-#ifdef VCMI_ANDROID
bool swipeEnabled;
bool swipeMovementRequested;
int3 swipeTargetPosition;
-#endif // !VCMI_ANDROID
enum{NA, INGAME, WAITING} state;
@@ -260,9 +259,7 @@ public:
void changeMode(EAdvMapMode newMode, float newScale = 0.36f);
void handleMapScrollingUpdate();
-#ifdef VCMI_ANDROID
void handleSwipeUpdate();
-#endif
};
diff --git a/config/schemas/settings.json b/config/schemas/settings.json
index 22e0f75dc..995d67eca 100644
--- a/config/schemas/settings.json
+++ b/config/schemas/settings.json
@@ -41,7 +41,7 @@
},
"swipe" : {
"type" : "boolean",
- "default" : false
+ "default" : true
},
"saveRandomMaps" : {
"type" : "boolean",