CCControl.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. dispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
  77. return true;
  78. }
  79. else
  80. {
  81. return false;
  82. }
  83. }
  84. Control::~Control()
  85. {
  86. for (auto iter = _dispatchTable.begin(); iter != _dispatchTable.end(); ++iter)
  87. {
  88. delete iter->second;
  89. }
  90. _dispatchTable.clear();
  91. }
  92. void Control::sendActionsForControlEvents(EventType controlEvents)
  93. {
  94. retain();
  95. // For each control events
  96. for (int i = 0; i < kControlEventTotalNumber; i++)
  97. {
  98. // If the given controlEvents bitmask contains the current event
  99. if (((int)controlEvents & (1 << i)))
  100. {
  101. // Call invocations
  102. const auto& invocationList = this->dispatchListforControlEvent((Control::EventType)(1<<i));
  103. for(const auto &invocation : invocationList) {
  104. invocation->invoke(this);
  105. }
  106. #if CC_ENABLE_SCRIPT_BINDING
  107. //Call ScriptFunc
  108. if (kScriptTypeLua == _scriptType)
  109. {
  110. cocos2d::BasicScriptData data(this,(void*)&controlEvents);
  111. cocos2d::ScriptEvent event(cocos2d::kControlEvent,(void*)&data);
  112. cocos2d::ScriptEngineManager::getInstance()->getScriptEngine()->sendEvent(&event);
  113. }
  114. #endif
  115. }
  116. }
  117. release();
  118. }
  119. void Control::addTargetWithActionForControlEvents(Ref* target, Handler action, EventType controlEvents)
  120. {
  121. // For each control events
  122. for (int i = 0; i < kControlEventTotalNumber; i++)
  123. {
  124. // If the given controlEvents bitmask contains the current event
  125. if (((int)controlEvents & (1 << i)))
  126. {
  127. this->addTargetWithActionForControlEvent(target, action, (EventType)(1<<i));
  128. }
  129. }
  130. }
  131. /**
  132. * Adds a target and action for a particular event to an internal dispatch
  133. * table.
  134. * The action message may optionally include the sender and the event as
  135. * parameters, in that order.
  136. * When you call this method, target is not retained.
  137. *
  138. * @param target The target object that is, the object to which the action
  139. * message is sent. It cannot be nil. The target is not retained.
  140. * @param action A selector identifying an action message. It cannot be nullptr.
  141. * @param controlEvent A control event for which the action message is sent.
  142. * See "CCControlEvent" for constants.
  143. */
  144. void Control::addTargetWithActionForControlEvent(Ref* target, Handler action, EventType controlEvent)
  145. {
  146. // Create the invocation object
  147. Invocation *invocation = Invocation::create(target, action, controlEvent);
  148. // Add the invocation into the dispatch list for the given control event
  149. auto& eventInvocationList = this->dispatchListforControlEvent(controlEvent);
  150. eventInvocationList.pushBack(invocation);
  151. }
  152. void Control::removeTargetWithActionForControlEvents(Ref* target, Handler action, EventType controlEvents)
  153. {
  154. // For each control events
  155. for (int i = 0; i < kControlEventTotalNumber; i++)
  156. {
  157. // If the given controlEvents bitmask contains the current event
  158. if (((int)controlEvents & (1 << i)))
  159. {
  160. this->removeTargetWithActionForControlEvent(target, action, (EventType)(1 << i));
  161. }
  162. }
  163. }
  164. void Control::removeTargetWithActionForControlEvent(Ref* target, Handler action, EventType controlEvent)
  165. {
  166. // Retrieve all invocations for the given control event
  167. auto& eventInvocationList = this->dispatchListforControlEvent(controlEvent);
  168. //remove all invocations if the target and action are null
  169. //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?
  170. if (!target && !action)
  171. {
  172. //remove objects
  173. eventInvocationList.clear();
  174. }
  175. else
  176. {
  177. std::vector<Invocation*> tobeRemovedInvocations;
  178. //normally we would use a predicate, but this won't work here. Have to do it manually
  179. for(const auto &invocation : eventInvocationList) {
  180. bool shouldBeRemoved=true;
  181. if (target)
  182. {
  183. shouldBeRemoved=(target==invocation->getTarget());
  184. }
  185. if (action)
  186. {
  187. shouldBeRemoved=(shouldBeRemoved && (action==invocation->getAction()));
  188. }
  189. // Remove the corresponding invocation object
  190. if (shouldBeRemoved)
  191. {
  192. tobeRemovedInvocations.push_back(invocation);
  193. }
  194. }
  195. for(const auto &invocation : tobeRemovedInvocations) {
  196. eventInvocationList.eraseObject(invocation);
  197. }
  198. }
  199. }
  200. //CRGBA protocol
  201. void Control::setOpacityModifyRGB(bool bOpacityModifyRGB)
  202. {
  203. _isOpacityModifyRGB=bOpacityModifyRGB;
  204. for(auto child : _children){
  205. child->setOpacityModifyRGB(bOpacityModifyRGB);
  206. }
  207. }
  208. bool Control::isOpacityModifyRGB() const
  209. {
  210. return _isOpacityModifyRGB;
  211. }
  212. Vec2 Control::getTouchLocation(Touch* touch)
  213. {
  214. Vec2 touchLocation = touch->getLocation(); // Get the touch position
  215. touchLocation = this->convertToNodeSpace(touchLocation); // Convert to the node space of this class
  216. return touchLocation;
  217. }
  218. bool Control::onTouchBegan(Touch* /*touch*/, Event* /*event*/) {
  219. return false;
  220. }
  221. void Control::onTouchMoved(Touch* /*touch*/, Event* /*event*/)
  222. {}
  223. void Control::onTouchEnded(Touch* /*touch*/, Event* /*event*/)
  224. {}
  225. void Control::onTouchCancelled(Touch* /*touch*/, Event* /*event*/)
  226. {}
  227. bool Control::isTouchInside(Touch* touch)
  228. {
  229. Vec2 touchLocation = touch->getLocation(); // Get the touch position
  230. touchLocation = this->getParent()->convertToNodeSpace(touchLocation);
  231. Rect bBox = getBoundingBox();
  232. return bBox.containsPoint(touchLocation);
  233. }
  234. Vector<Invocation*>& Control::dispatchListforControlEvent(EventType controlEvent)
  235. {
  236. Vector<Invocation*>* invocationList = nullptr;
  237. auto iter = _dispatchTable.find((int)controlEvent);
  238. // If the invocation list does not exist for the dispatch table, we create it
  239. if (iter == _dispatchTable.end())
  240. {
  241. invocationList = new (std::nothrow) Vector<Invocation*>();
  242. _dispatchTable[(int)controlEvent] = invocationList;
  243. }
  244. else
  245. {
  246. invocationList = iter->second;
  247. }
  248. return *invocationList;
  249. }
  250. void Control::needsLayout()
  251. {
  252. }
  253. void Control::setEnabled(bool bEnabled)
  254. {
  255. _enabled = bEnabled;
  256. if(_enabled) {
  257. _state = Control::State::NORMAL;
  258. } else {
  259. _state = Control::State::DISABLED;
  260. }
  261. this->needsLayout();
  262. }
  263. bool Control::isEnabled() const
  264. {
  265. return _enabled;
  266. }
  267. void Control::setSelected(bool bSelected)
  268. {
  269. _selected = bSelected;
  270. this->needsLayout();
  271. }
  272. bool Control::isSelected() const
  273. {
  274. return _selected;
  275. }
  276. void Control::setHighlighted(bool bHighlighted)
  277. {
  278. _highlighted = bHighlighted;
  279. this->needsLayout();
  280. }
  281. bool Control::isHighlighted() const
  282. {
  283. return _highlighted;
  284. }
  285. bool Control::hasVisibleParents() const
  286. {
  287. auto parent = this->getParent();
  288. for( auto c = parent; c != nullptr; c = c->getParent() )
  289. {
  290. if( !c->isVisible() )
  291. {
  292. return false;
  293. }
  294. }
  295. return true;
  296. }
  297. Control::EventType operator|(Control::EventType a, Control::EventType b) {
  298. return static_cast<Control::EventType>(static_cast<int>(a) | static_cast<int>(b));
  299. }
  300. NS_CC_EXT_END