Procházet zdrojové kódy

Refactor: unified logic for notyfing CIntObjs about left/right mouse click events;
Added support for middle-click;

Fay před 8 roky
rodič
revize
02fa478bfb

+ 0 - 2
client/VCMI_client.vcxproj

@@ -292,6 +292,4 @@
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-  <ImportGroup Label="ExtensionTargets">
-  </ImportGroup>
 </Project>

+ 2 - 8
client/VCMI_client.vcxproj.filters

@@ -109,17 +109,10 @@
       <Filter>gui</Filter>
     </ClCompile>
     <ClCompile Include="..\CCallback.cpp" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="CQuestLog.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
+    <ClCompile Include="SDLRWwrapper.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="VCMI_client.rc" />
-    <ClInclude Include="CQuestLog.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="vcmi.ico" />
@@ -254,5 +247,6 @@
       <Filter>gui</Filter>
     </ClInclude>
     <ClInclude Include="..\CCallback.h" />
+    <ClInclude Include="SDLRWwrapper.h" />
   </ItemGroup>
 </Project>

+ 48 - 58
client/gui/CGuiHandler.cpp

@@ -60,6 +60,7 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
 {
 	processList(CIntObject::LCLICK,activityFlag,&lclickable,cb);
 	processList(CIntObject::RCLICK,activityFlag,&rclickable,cb);
+	processList(CIntObject::MCLICK,activityFlag,&mclickable,cb);
 	processList(CIntObject::HOVER,activityFlag,&hoverable,cb);
 	processList(CIntObject::MOVE,activityFlag,&motioninterested,cb);
 	processList(CIntObject::KEYBOARD,activityFlag,&keyinterested,cb);
@@ -260,18 +261,18 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
 		CCS->curh->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<CIntObject*> 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<CIntObject*> 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<CIntObject*> 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,40 +322,44 @@ 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<CIntObject*> 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);
+		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;
 		}
 	}
-	else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_RIGHT))
+	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++)
 	{
-		std::list<CIntObject*> hlp = rclickable;
-		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(!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);
+			if(isPressed)
+				(*i)->updateMouseState(btn, isPressed);
+			(*i)->click(btn, isPressed, prev);
 		}
+		else if(!isPressed)
+			(*i)->click(btn, boost::logic::indeterminate, prev);
 	}
-	current = nullptr;
-} //event end
+}
 
 void CGuiHandler::handleMouseMotion(SDL_Event *sEvent)
 {

+ 3 - 0
client/gui/CGuiHandler.h

@@ -10,6 +10,7 @@ class CIntObject;
 class IUpdateable;
 class IShowActivatable;
 class IShowable;
+enum class EIntObjMouseBtnType;
 template <typename T> 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<void (std::list<CIntObject*> *)> cb);
 public:
 	void handleElementActivate(CIntObject * elem, ui16 activityFlag);

+ 22 - 12
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);
+		
 	}
 }

+ 10 - 7
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<EIntObjMouseBtnType, bool> 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);

+ 1 - 1
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();
 }
 

+ 1 - 1
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;
 	}