CCControl.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Copyright (c) 2012 cocos2d-x.org
  3. * http://www.cocos2d-x.org
  4. *
  5. * Copyright 2011 Yannick Loriot.
  6. * http://yannickloriot.com
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. *
  26. *
  27. * converted to c++ / cocos2d-x by Angus C
  28. */
  29. #include "CCControl.h"
  30. #include "base/CCDirector.h"
  31. #include "2d/CCMenu.h"
  32. #include "base/CCTouch.h"
  33. #include "CCInvocation.h"
  34. #include "base/CCEventDispatcher.h"
  35. #include "base/CCEventListenerTouch.h"
  36. NS_CC_EXT_BEGIN
  37. Control::Control()
  38. : _enabled(false)
  39. , _selected(false)
  40. , _highlighted(false)
  41. , _hasVisibleParents(false)
  42. , _isOpacityModifyRGB(false)
  43. , _state(State::NORMAL)
  44. {
  45. }
  46. Control* Control::create()
  47. {
  48. Control* pRet = new (std::nothrow) Control();
  49. if (pRet && pRet->init())
  50. {
  51. pRet->autorelease();
  52. return pRet;
  53. }
  54. else
  55. {
  56. CC_SAFE_DELETE(pRet);
  57. return nullptr;
  58. }
  59. }
  60. bool Control::init()
  61. {
  62. if (Layer::init())
  63. {
  64. // Initialise instance variables
  65. _state=Control::State::NORMAL;
  66. setEnabled(true);
  67. setSelected(false);
  68. setHighlighted(false);
  69. auto dispatcher = Director::getInstance()->getEventDispatcher();
  70. auto touchListener = EventListenerTouchOneByOne::create();
  71. touchListener->setSwallowTouches(true);
  72. touchListener->onTouchBegan = CC_CALLBACK_2(Control::onTouchBegan, this);
  73. touchListener->onTouchMoved = CC_CALLBACK_2(Control::onTouchMoved, this);
  74. touchListener->onTouchEnded = CC_CALLBACK_2(Control::onTouchEnded, this);
  75. touchListener->onTouchCancelled = CC_CALLBACK_2(Control::onTouchCancelled, this);
  76. this->_touchListener = touchListener;
  77. dispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
  78. return true;
  79. }
  80. else
  81. {
  82. return false;
  83. }
  84. }
  85. void Control::setControlSwallowTouches(bool bSwall)
  86. {
  87. ((EventListenerTouchOneByOne*)this->_touchListener)->setSwallowTouches(bSwall);
  88. }
  89. Control::~Control()
  90. {
  91. for (auto iter = _dispatchTable.begin(); iter != _dispatchTable.end(); ++iter)
  92. {
  93. delete iter->second;
  94. }
  95. _dispatchTable.clear();
  96. }
  97. void Control::sendActionsForControlEvents(EventType controlEvents)
  98. {
  99. retain();
  100. // For each control events
  101. for (int i = 0; i < kControlEventTotalNumber; i++)
  102. {
  103. // If the given controlEvents bitmask contains the current event
  104. if (((int)controlEvents & (1 << i)))
  105. {
  106. // Call invocations
  107. const auto& invocationList = this->dispatchListforControlEvent((Control::EventType)(1<<i));
  108. for(const auto &invocation : invocationList) {
  109. invocation->invoke(this);
  110. }
  111. #if CC_ENABLE_SCRIPT_BINDING
  112. //Call ScriptFunc
  113. if (kScriptTypeLua == _scriptType)
  114. {
  115. cocos2d::BasicScriptData data(this,(void*)&controlEvents);
  116. cocos2d::ScriptEvent event(cocos2d::kControlEvent,(void*)&data);
  117. cocos2d::ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
  118. }
  119. #endif
  120. }
  121. }
  122. release();
  123. }
  124. void Control::addTargetWithActionForControlEvents(Ref* target, Handler action, EventType controlEvents)
  125. {
  126. // For each control events
  127. for (int i = 0; i < kControlEventTotalNumber; i++)
  128. {
  129. // If the given controlEvents bitmask contains the current event
  130. if (((int)controlEvents & (1 << i)))
  131. {
  132. this->addTargetWithActionForControlEvent(target, action, (EventType)(1<<i));
  133. }
  134. }
  135. }
  136. /**
  137. * Adds a target and action for a particular event to an internal dispatch
  138. * table.
  139. * The action message may optionally include the sender and the event as
  140. * parameters, in that order.
  141. * When you call this method, target is not retained.
  142. *
  143. * @param target The target object that is, the object to which the action
  144. * message is sent. It cannot be nil. The target is not retained.
  145. * @param action A selector identifying an action message. It cannot be nullptr.
  146. * @param controlEvent A control event for which the action message is sent.
  147. * See "CCControlEvent" for constants.
  148. */
  149. void Control::addTargetWithActionForControlEvent(Ref* target, Handler action, EventType controlEvent)
  150. {
  151. // Create the invocation object
  152. Invocation *invocation = Invocation::create(target, action, controlEvent);
  153. // Add the invocation into the dispatch list for the given control event
  154. auto& eventInvocationList = this->dispatchListforControlEvent(controlEvent);
  155. eventInvocationList.pushBack(invocation);
  156. }
  157. void Control::removeTargetWithActionForControlEvents(Ref* target, Handler action, EventType controlEvents)
  158. {
  159. // For each control events
  160. for (int i = 0; i < kControlEventTotalNumber; i++)
  161. {
  162. // If the given controlEvents bitmask contains the current event
  163. if (((int)controlEvents & (1 << i)))
  164. {
  165. this->removeTargetWithActionForControlEvent(target, action, (EventType)(1 << i));
  166. }
  167. }
  168. }
  169. void Control::removeTargetWithActionForControlEvent(Ref* target, Handler action, EventType controlEvent)
  170. {
  171. // Retrieve all invocations for the given control event
  172. auto& eventInvocationList = this->dispatchListforControlEvent(controlEvent);
  173. //remove all invocations if the target and action are null
  174. //TODO: should the invocations be deleted, or just removed from the array? Won't that cause issues if you add a single invocation for multiple events?
  175. if (!target && !action)
  176. {
  177. //remove objects
  178. eventInvocationList.clear();
  179. }
  180. else
  181. {
  182. std::vector<Invocation*> tobeRemovedInvocations;
  183. //normally we would use a predicate, but this won't work here. Have to do it manually
  184. for(const auto &invocation : eventInvocationList) {
  185. bool shouldBeRemoved=true;
  186. if (target)
  187. {
  188. shouldBeRemoved=(target==invocation->getTarget());
  189. }
  190. if (action)
  191. {
  192. shouldBeRemoved=(shouldBeRemoved && (action==invocation->getAction()));
  193. }
  194. // Remove the corresponding invocation object
  195. if (shouldBeRemoved)
  196. {
  197. tobeRemovedInvocations.push_back(invocation);
  198. }
  199. }
  200. for(const auto &invocation : tobeRemovedInvocations) {
  201. eventInvocationList.eraseObject(invocation);
  202. }
  203. }
  204. }
  205. //CRGBA protocol
  206. void Control::setOpacityModifyRGB(bool bOpacityModifyRGB)
  207. {
  208. _isOpacityModifyRGB=bOpacityModifyRGB;
  209. for(auto child : _children){
  210. child->setOpacityModifyRGB(bOpacityModifyRGB);
  211. }
  212. }
  213. bool Control::isOpacityModifyRGB() const
  214. {
  215. return _isOpacityModifyRGB;
  216. }
  217. Vec2 Control::getTouchLocation(Touch* touch)
  218. {
  219. Vec2 touchLocation = touch->getLocation(); // Get the touch position
  220. touchLocation = this->convertToNodeSpace(touchLocation); // Convert to the node space of this class
  221. return touchLocation;
  222. }
  223. bool Control::onTouchBegan(Touch* /*touch*/, Event* /*event*/) {
  224. return false;
  225. }
  226. void Control::onTouchMoved(Touch* /*touch*/, Event* /*event*/)
  227. {}
  228. void Control::onTouchEnded(Touch* /*touch*/, Event* /*event*/)
  229. {}
  230. void Control::onTouchCancelled(Touch* /*touch*/, Event* /*event*/)
  231. {}
  232. bool Control::isTouchInside(Touch* touch)
  233. {
  234. Vec2 touchLocation = touch->getLocation(); // Get the touch position
  235. touchLocation = this->getParent()->convertToNodeSpace(touchLocation);
  236. Rect bBox = getBoundingBox();
  237. return bBox.containsPoint(touchLocation);
  238. }
  239. Vector<Invocation*>& Control::dispatchListforControlEvent(EventType controlEvent)
  240. {
  241. Vector<Invocation*>* invocationList = nullptr;
  242. auto iter = _dispatchTable.find((int)controlEvent);
  243. // If the invocation list does not exist for the dispatch table, we create it
  244. if (iter == _dispatchTable.end())
  245. {
  246. invocationList = new (std::nothrow) Vector<Invocation*>();
  247. _dispatchTable[(int)controlEvent] = invocationList;
  248. }
  249. else
  250. {
  251. invocationList = iter->second;
  252. }
  253. return *invocationList;
  254. }
  255. void Control::needsLayout()
  256. {
  257. }
  258. void Control::setEnabled(bool bEnabled)
  259. {
  260. _enabled = bEnabled;
  261. if(_enabled) {
  262. _state = Control::State::NORMAL;
  263. } else {
  264. _state = Control::State::DISABLED;
  265. }
  266. this->needsLayout();
  267. }
  268. bool Control::isEnabled() const
  269. {
  270. return _enabled;
  271. }
  272. void Control::setSelected(bool bSelected)
  273. {
  274. _selected = bSelected;
  275. this->needsLayout();
  276. }
  277. bool Control::isSelected() const
  278. {
  279. return _selected;
  280. }
  281. void Control::setHighlighted(bool bHighlighted)
  282. {
  283. _highlighted = bHighlighted;
  284. this->needsLayout();
  285. }
  286. bool Control::isHighlighted() const
  287. {
  288. return _highlighted;
  289. }
  290. bool Control::hasVisibleParents() const
  291. {
  292. auto parent = this->getParent();
  293. for( auto c = parent; c != nullptr; c = c->getParent() )
  294. {
  295. if( !c->isVisible() )
  296. {
  297. return false;
  298. }
  299. }
  300. return true;
  301. }
  302. Control::EventType operator|(Control::EventType a, Control::EventType b) {
  303. return static_cast<Control::EventType>(static_cast<int>(a) | static_cast<int>(b));
  304. }
  305. NS_CC_EXT_END