UILayout.cpp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919
  1. /****************************************************************************
  2. Copyright (c) 2013-2017 Chukong Technologies Inc.
  3. http://www.cocos2d-x.org
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. THE SOFTWARE.
  19. ****************************************************************************/
  20. #include "ui/UILayout.h"
  21. #include "ui/UIHelper.h"
  22. #include "ui/UIScale9Sprite.h"
  23. #include "renderer/CCGLProgram.h"
  24. #include "renderer/CCGLProgramCache.h"
  25. #include "renderer/ccGLStateCache.h"
  26. #include "renderer/CCRenderState.h"
  27. #include "base/CCDirector.h"
  28. #include "2d/CCDrawingPrimitives.h"
  29. #include "renderer/CCRenderer.h"
  30. #include "ui/UILayoutManager.h"
  31. #include "2d/CCDrawNode.h"
  32. #include "2d/CCLayer.h"
  33. #include "2d/CCSprite.h"
  34. #include "base/CCEventFocus.h"
  35. #include "base/CCStencilStateManager.h"
  36. #include "editor-support/cocostudio/CocosStudioExtension.h"
  37. NS_CC_BEGIN
  38. namespace ui {
  39. static const int BACKGROUNDIMAGE_Z = (-1);
  40. static const int BCAKGROUNDCOLORRENDERER_Z = (-2);
  41. IMPLEMENT_CLASS_GUI_INFO(Layout)
  42. Layout::Layout():
  43. _backGroundScale9Enabled(false),
  44. _backGroundImage(nullptr),
  45. _backGroundImageFileName(""),
  46. _backGroundImageCapInsets(Rect::ZERO),
  47. _colorType(BackGroundColorType::NONE),
  48. _bgImageTexType(TextureResType::LOCAL),
  49. _backGroundImageTextureSize(Size::ZERO),
  50. _backGroundImageColor(Color3B::WHITE),
  51. _backGroundImageOpacity(255),
  52. _colorRender(nullptr),
  53. _gradientRender(nullptr),
  54. _cColor(Color3B::WHITE),
  55. _gStartColor(Color3B::WHITE),
  56. _gEndColor(Color3B::WHITE),
  57. _alongVector(Vec2(0.0f, -1.0f)),
  58. _cOpacity(255),
  59. _clippingEnabled(false),
  60. _layoutType(Type::ABSOLUTE),
  61. _clippingType(ClippingType::STENCIL),
  62. _clippingStencil(nullptr),
  63. _clippingRect(Rect::ZERO),
  64. _clippingParent(nullptr),
  65. _clippingRectDirty(true),
  66. _stencilStateManager(new StencilStateManager()),
  67. _doLayoutDirty(true),
  68. _isInterceptTouch(false),
  69. _loopFocus(false),
  70. _passFocusToChild(true),
  71. _isFocusPassing(false)
  72. {
  73. //no-op
  74. }
  75. Layout::~Layout()
  76. {
  77. CC_SAFE_RELEASE(_clippingStencil);
  78. CC_SAFE_DELETE(_stencilStateManager);
  79. }
  80. void Layout::onEnter()
  81. {
  82. #if CC_ENABLE_SCRIPT_BINDING
  83. if (_scriptType == kScriptTypeJavascript)
  84. {
  85. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter))
  86. return;
  87. }
  88. #endif
  89. Widget::onEnter();
  90. if (_clippingStencil)
  91. {
  92. _clippingStencil->onEnter();
  93. }
  94. _doLayoutDirty = true;
  95. _clippingRectDirty = true;
  96. }
  97. void Layout::onExit()
  98. {
  99. #if CC_ENABLE_SCRIPT_BINDING
  100. if (_scriptType == kScriptTypeJavascript)
  101. {
  102. if (ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit))
  103. return;
  104. }
  105. #endif
  106. Widget::onExit();
  107. if (_clippingStencil)
  108. {
  109. _clippingStencil->onExit();
  110. }
  111. }
  112. void Layout::setGlobalZOrder(float globalZOrder)
  113. {
  114. // _protectedChildren's global z order is set in ProtectedNode::setGlobalZOrder()
  115. Widget::setGlobalZOrder(globalZOrder);
  116. if (_clippingStencil)
  117. _clippingStencil->setGlobalZOrder(globalZOrder);
  118. for (auto &child : _children)
  119. child->setGlobalZOrder(globalZOrder);
  120. }
  121. Layout* Layout::create()
  122. {
  123. Layout* layout = new (std::nothrow) Layout();
  124. if (layout && layout->init())
  125. {
  126. layout->autorelease();
  127. return layout;
  128. }
  129. CC_SAFE_DELETE(layout);
  130. return nullptr;
  131. }
  132. bool Layout::init()
  133. {
  134. if (Widget::init())
  135. {
  136. ignoreContentAdaptWithSize(false);
  137. setContentSize(Size::ZERO);
  138. setAnchorPoint(Vec2::ZERO);
  139. onPassFocusToChild = CC_CALLBACK_2(Layout::findNearestChildWidgetIndex, this);
  140. return true;
  141. }
  142. return false;
  143. }
  144. void Layout::addChild(Node* child)
  145. {
  146. Layout::addChild(child, child->getLocalZOrder(), child->getTag());
  147. }
  148. void Layout::addChild(Node * child, int localZOrder)
  149. {
  150. Layout::addChild(child, localZOrder, child->getTag());
  151. }
  152. void Layout::addChild(Node *child, int zOrder, int tag)
  153. {
  154. if (dynamic_cast<Widget*>(child)) {
  155. supplyTheLayoutParameterLackToChild(static_cast<Widget*>(child));
  156. }
  157. child->setGlobalZOrder(_globalZOrder);
  158. Widget::addChild(child, zOrder, tag);
  159. _doLayoutDirty = true;
  160. }
  161. void Layout::addChild(Node* child, int zOrder, const std::string &name)
  162. {
  163. if (dynamic_cast<Widget*>(child)) {
  164. supplyTheLayoutParameterLackToChild(static_cast<Widget*>(child));
  165. }
  166. child->setGlobalZOrder(_globalZOrder);
  167. Widget::addChild(child, zOrder, name);
  168. _doLayoutDirty = true;
  169. }
  170. void Layout::removeChild(Node *child, bool cleanup)
  171. {
  172. Widget::removeChild(child, cleanup);
  173. _doLayoutDirty = true;
  174. }
  175. void Layout::removeAllChildren()
  176. {
  177. Widget::removeAllChildren();
  178. _doLayoutDirty = true;
  179. }
  180. void Layout::removeAllChildrenWithCleanup(bool cleanup)
  181. {
  182. Widget::removeAllChildrenWithCleanup(cleanup);
  183. _doLayoutDirty = true;
  184. }
  185. bool Layout::isClippingEnabled()const
  186. {
  187. return _clippingEnabled;
  188. }
  189. void Layout::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
  190. {
  191. if (!_visible)
  192. {
  193. return;
  194. }
  195. adaptRenderers();
  196. doLayout();
  197. if (_clippingEnabled)
  198. {
  199. switch (_clippingType)
  200. {
  201. case ClippingType::STENCIL:
  202. stencilClippingVisit(renderer, parentTransform, parentFlags);
  203. break;
  204. case ClippingType::SCISSOR:
  205. scissorClippingVisit(renderer, parentTransform, parentFlags);
  206. break;
  207. default:
  208. break;
  209. }
  210. }
  211. else
  212. {
  213. Widget::visit(renderer, parentTransform, parentFlags);
  214. }
  215. }
  216. void Layout::stencilClippingVisit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags)
  217. {
  218. if(!_visible)
  219. return;
  220. uint32_t flags = processParentFlags(parentTransform, parentFlags);
  221. // IMPORTANT:
  222. // To ease the migration to v3.0, we still support the Mat4 stack,
  223. // but it is deprecated and your code should not rely on it
  224. Director* director = Director::getInstance();
  225. CCASSERT(nullptr != director, "Director is null when setting matrix stack");
  226. director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  227. director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
  228. //Add group command
  229. _groupCommand.init(_globalZOrder);
  230. renderer->addCommand(&_groupCommand);
  231. renderer->pushGroup(_groupCommand.getRenderQueueID());
  232. _beforeVisitCmdStencil.init(_globalZOrder);
  233. _beforeVisitCmdStencil.func = CC_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
  234. renderer->addCommand(&_beforeVisitCmdStencil);
  235. _clippingStencil->visit(renderer, _modelViewTransform, flags);
  236. _afterDrawStencilCmd.init(_globalZOrder);
  237. _afterDrawStencilCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterDrawStencil, _stencilStateManager);
  238. renderer->addCommand(&_afterDrawStencilCmd);
  239. int i = 0; // used by _children
  240. int j = 0; // used by _protectedChildren
  241. sortAllChildren();
  242. sortAllProtectedChildren();
  243. //
  244. // draw children and protectedChildren zOrder < 0
  245. //
  246. for(auto size = _children.size(); i < size; i++)
  247. {
  248. auto node = _children.at(i);
  249. if (node && node->getLocalZOrder() < 0)
  250. node->visit(renderer, _modelViewTransform, flags);
  251. else
  252. break;
  253. }
  254. for(auto size = _protectedChildren.size(); j < size; j++)
  255. {
  256. auto node = _protectedChildren.at(j);
  257. if (node && node->getLocalZOrder() < 0)
  258. node->visit(renderer, _modelViewTransform, flags);
  259. else
  260. break;
  261. }
  262. //
  263. // draw self
  264. //
  265. this->draw(renderer, _modelViewTransform, flags);
  266. //
  267. // draw children and protectedChildren zOrder >= 0
  268. //
  269. for(auto it=_protectedChildren.cbegin()+j, itCend = _protectedChildren.cend(); it != itCend; ++it)
  270. (*it)->visit(renderer, _modelViewTransform, flags);
  271. for(auto it=_children.cbegin()+i, itCend = _children.cend(); it != itCend; ++it)
  272. (*it)->visit(renderer, _modelViewTransform, flags);
  273. _afterVisitCmdStencil.init(_globalZOrder);
  274. _afterVisitCmdStencil.func = CC_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
  275. renderer->addCommand(&_afterVisitCmdStencil);
  276. renderer->popGroup();
  277. director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  278. }
  279. void Layout::onBeforeVisitScissor()
  280. {
  281. auto glview = Director::getInstance()->getOpenGLView();
  282. // apply scissor test
  283. _scissorOldState = glview->isScissorEnabled();
  284. if (false == _scissorOldState)
  285. {
  286. glEnable(GL_SCISSOR_TEST);
  287. }
  288. // apply scissor box
  289. Rect clippingRect = getClippingRect();
  290. _clippingOldRect = glview->getScissorRect();
  291. if (false == _clippingOldRect.equals(clippingRect))
  292. {
  293. glview->setScissorInPoints(clippingRect.origin.x,
  294. clippingRect.origin.y,
  295. clippingRect.size.width,
  296. clippingRect.size.height);
  297. }
  298. }
  299. void Layout::onAfterVisitScissor()
  300. {
  301. if (_scissorOldState)
  302. {
  303. // revert scissor box
  304. if (false == _clippingOldRect.equals(_clippingRect))
  305. {
  306. auto glview = Director::getInstance()->getOpenGLView();
  307. glview->setScissorInPoints(_clippingOldRect.origin.x,
  308. _clippingOldRect.origin.y,
  309. _clippingOldRect.size.width,
  310. _clippingOldRect.size.height);
  311. }
  312. }
  313. else
  314. {
  315. // revert scissor test
  316. glDisable(GL_SCISSOR_TEST);
  317. }
  318. }
  319. void Layout::scissorClippingVisit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags)
  320. {
  321. if (parentFlags & FLAGS_DIRTY_MASK)
  322. {
  323. _clippingRectDirty = true;
  324. }
  325. _beforeVisitCmdScissor.init(_globalZOrder);
  326. _beforeVisitCmdScissor.func = CC_CALLBACK_0(Layout::onBeforeVisitScissor, this);
  327. renderer->addCommand(&_beforeVisitCmdScissor);
  328. ProtectedNode::visit(renderer, parentTransform, parentFlags);
  329. _afterVisitCmdScissor.init(_globalZOrder);
  330. _afterVisitCmdScissor.func = CC_CALLBACK_0(Layout::onAfterVisitScissor, this);
  331. renderer->addCommand(&_afterVisitCmdScissor);
  332. }
  333. void Layout::setClippingEnabled(bool able)
  334. {
  335. if (able == _clippingEnabled)
  336. {
  337. return;
  338. }
  339. _clippingEnabled = able;
  340. switch (_clippingType)
  341. {
  342. case ClippingType::STENCIL:
  343. if (able)
  344. {
  345. _clippingStencil = DrawNode::create();
  346. _clippingStencil->setGlobalZOrder(_globalZOrder);
  347. if (_running)
  348. {
  349. _clippingStencil->onEnter();
  350. }
  351. _clippingStencil->retain();
  352. setStencilClippingSize(_contentSize);
  353. }
  354. else
  355. {
  356. if (_running)
  357. {
  358. _clippingStencil->onExit();
  359. }
  360. _clippingStencil->release();
  361. _clippingStencil = nullptr;
  362. }
  363. break;
  364. default:
  365. break;
  366. }
  367. }
  368. void Layout::setClippingType(ClippingType type)
  369. {
  370. if (type == _clippingType)
  371. {
  372. return;
  373. }
  374. bool clippingEnabled = isClippingEnabled();
  375. setClippingEnabled(false);
  376. _clippingType = type;
  377. setClippingEnabled(clippingEnabled);
  378. }
  379. Layout::ClippingType Layout::getClippingType()const
  380. {
  381. return _clippingType;
  382. }
  383. void Layout::setStencilClippingSize(const Size& /*size*/)
  384. {
  385. if (_clippingEnabled && _clippingType == ClippingType::STENCIL)
  386. {
  387. Vec2 rect[4];
  388. // rect[0].setZero(); Zero default
  389. rect[1].set(_contentSize.width, 0.0f);
  390. rect[2].set(_contentSize.width, _contentSize.height);
  391. rect[3].set(0.0f, _contentSize.height);
  392. Color4F green(0.0f, 1.0f, 0.0f, 1.0f);
  393. _clippingStencil->clear();
  394. _clippingStencil->drawPolygon(rect, 4, green, 0, green);
  395. }
  396. }
  397. const Rect& Layout::getClippingRect()
  398. {
  399. if (_clippingRectDirty)
  400. {
  401. Vec2 worldPos = convertToWorldSpace(Vec2::ZERO);
  402. AffineTransform t = getNodeToWorldAffineTransform();
  403. float scissorWidth = _contentSize.width*t.a;
  404. float scissorHeight = _contentSize.height*t.d;
  405. Rect parentClippingRect;
  406. Layout* parent = this;
  407. while (parent)
  408. {
  409. parent = dynamic_cast<Layout*>(parent->getParent());
  410. if(parent)
  411. {
  412. if (parent->isClippingEnabled())
  413. {
  414. _clippingParent = parent;
  415. break;
  416. }
  417. }
  418. }
  419. if (_clippingParent)
  420. {
  421. parentClippingRect = _clippingParent->getClippingRect();
  422. float finalX = worldPos.x - (scissorWidth * _anchorPoint.x);
  423. float finalY = worldPos.y - (scissorHeight * _anchorPoint.y);
  424. float finalWidth = scissorWidth;
  425. float finalHeight = scissorHeight;
  426. float leftOffset = worldPos.x - parentClippingRect.origin.x;
  427. if (leftOffset < 0.0f)
  428. {
  429. finalX = parentClippingRect.origin.x;
  430. finalWidth += leftOffset;
  431. }
  432. float rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.origin.x + parentClippingRect.size.width);
  433. if (rightOffset > 0.0f)
  434. {
  435. finalWidth -= rightOffset;
  436. }
  437. float topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.origin.y + parentClippingRect.size.height);
  438. if (topOffset > 0.0f)
  439. {
  440. finalHeight -= topOffset;
  441. }
  442. float bottomOffset = worldPos.y - parentClippingRect.origin.y;
  443. if (bottomOffset < 0.0f)
  444. {
  445. finalY = parentClippingRect.origin.y;
  446. finalHeight += bottomOffset;
  447. }
  448. if (finalWidth < 0.0f)
  449. {
  450. finalWidth = 0.0f;
  451. }
  452. if (finalHeight < 0.0f)
  453. {
  454. finalHeight = 0.0f;
  455. }
  456. _clippingRect.origin.x = finalX;
  457. _clippingRect.origin.y = finalY;
  458. _clippingRect.size.width = finalWidth;
  459. _clippingRect.size.height = finalHeight;
  460. }
  461. else
  462. {
  463. _clippingRect.origin.x = worldPos.x - (scissorWidth * _anchorPoint.x);
  464. _clippingRect.origin.y = worldPos.y - (scissorHeight * _anchorPoint.y);
  465. _clippingRect.size.width = scissorWidth;
  466. _clippingRect.size.height = scissorHeight;
  467. }
  468. _clippingRectDirty = false;
  469. }
  470. return _clippingRect;
  471. }
  472. void Layout::onSizeChanged()
  473. {
  474. Widget::onSizeChanged();
  475. setStencilClippingSize(_contentSize);
  476. _doLayoutDirty = true;
  477. _clippingRectDirty = true;
  478. if (_backGroundImage)
  479. {
  480. _backGroundImage->setPosition(_contentSize.width/2.0f, _contentSize.height/2.0f);
  481. if (_backGroundScale9Enabled){
  482. _backGroundImage->setPreferredSize(_contentSize);
  483. }
  484. else{
  485. _backGroundImage->setPreferredSize(_backGroundImageTextureSize);
  486. }
  487. }
  488. if (_colorRender)
  489. {
  490. _colorRender->setContentSize(_contentSize);
  491. }
  492. if (_gradientRender)
  493. {
  494. _gradientRender->setContentSize(_contentSize);
  495. }
  496. }
  497. void Layout::setBackGroundImageScale9Enabled(bool able)
  498. {
  499. if (_backGroundScale9Enabled == able)
  500. {
  501. return;
  502. }
  503. _backGroundScale9Enabled = able;
  504. if (nullptr == _backGroundImage)
  505. {
  506. addBackGroundImage();
  507. setBackGroundImage(_backGroundImageFileName,_bgImageTexType);
  508. }
  509. if(_backGroundScale9Enabled){
  510. _backGroundImage->setRenderingType(Scale9Sprite::RenderingType::SLICE);
  511. _backGroundImage->setPreferredSize(_contentSize);
  512. }else{
  513. _backGroundImage->setRenderingType(Scale9Sprite::RenderingType::SIMPLE);
  514. _backGroundImage->setPreferredSize(_backGroundImageTextureSize);
  515. }
  516. setBackGroundImageCapInsets(_backGroundImageCapInsets);
  517. }
  518. bool Layout::isBackGroundImageScale9Enabled()const
  519. {
  520. return _backGroundScale9Enabled;
  521. }
  522. void Layout::setBackGroundImage(const std::string& fileName,TextureResType texType)
  523. {
  524. if (fileName.empty())
  525. {
  526. return;
  527. }
  528. if (_backGroundImage == nullptr)
  529. {
  530. addBackGroundImage();
  531. if(_backGroundScale9Enabled){
  532. _backGroundImage->setRenderingType(Scale9Sprite::RenderingType::SLICE);
  533. }else{
  534. _backGroundImage->setRenderingType(Scale9Sprite::RenderingType::SIMPLE);
  535. }
  536. }
  537. _backGroundImageFileName = fileName;
  538. _bgImageTexType = texType;
  539. switch (_bgImageTexType)
  540. {
  541. case TextureResType::LOCAL:
  542. _backGroundImage->initWithFile(fileName);
  543. break;
  544. case TextureResType::PLIST:
  545. _backGroundImage->initWithSpriteFrameName(fileName);
  546. break;
  547. default:
  548. break;
  549. }
  550. _backGroundImageTextureSize = _backGroundImage->getContentSize();
  551. _backGroundImage->setPosition(_contentSize.width/2.0f, _contentSize.height/2.0f);
  552. if (_backGroundScale9Enabled) {
  553. _backGroundImage->setPreferredSize(_contentSize);
  554. }
  555. else{
  556. _backGroundImage->setPreferredSize(_backGroundImageTextureSize);
  557. }
  558. updateBackGroundImageRGBA();
  559. }
  560. void Layout::setBackGroundImageCapInsets(const Rect &capInsets)
  561. {
  562. _backGroundImageCapInsets = capInsets;
  563. if (_backGroundScale9Enabled && _backGroundImage)
  564. {
  565. _backGroundImage->setCapInsets(capInsets);
  566. }
  567. }
  568. const Rect& Layout::getBackGroundImageCapInsets()const
  569. {
  570. return _backGroundImageCapInsets;
  571. }
  572. void Layout::supplyTheLayoutParameterLackToChild(Widget *child)
  573. {
  574. if (!child)
  575. {
  576. return;
  577. }
  578. switch (_layoutType)
  579. {
  580. case Type::ABSOLUTE:
  581. break;
  582. case Type::HORIZONTAL:
  583. case Type::VERTICAL:
  584. {
  585. LinearLayoutParameter* layoutParameter = dynamic_cast<LinearLayoutParameter*>(child->getLayoutParameter());
  586. if (!layoutParameter)
  587. {
  588. child->setLayoutParameter(LinearLayoutParameter::create());
  589. }
  590. break;
  591. }
  592. case Type::RELATIVE:
  593. {
  594. RelativeLayoutParameter* layoutParameter = dynamic_cast<RelativeLayoutParameter*>(child->getLayoutParameter());
  595. if (!layoutParameter)
  596. {
  597. child->setLayoutParameter(RelativeLayoutParameter::create());
  598. }
  599. break;
  600. }
  601. default:
  602. break;
  603. }
  604. }
  605. void Layout::addBackGroundImage()
  606. {
  607. _backGroundImage = Scale9Sprite::create();
  608. _backGroundImage->setRenderingType(Scale9Sprite::RenderingType::SIMPLE);
  609. addProtectedChild(_backGroundImage, BACKGROUNDIMAGE_Z, -1);
  610. _backGroundImage->setPosition(_contentSize.width/2.0f, _contentSize.height/2.0f);
  611. }
  612. void Layout::removeBackGroundImage()
  613. {
  614. if (!_backGroundImage)
  615. {
  616. return;
  617. }
  618. removeProtectedChild(_backGroundImage);
  619. _backGroundImage = nullptr;
  620. _backGroundImageFileName = "";
  621. _backGroundImageTextureSize = Size::ZERO;
  622. }
  623. void Layout::setBackGroundColorType(BackGroundColorType type)
  624. {
  625. if (_colorType == type)
  626. {
  627. return;
  628. }
  629. switch (_colorType)
  630. {
  631. case BackGroundColorType::NONE:
  632. if (_colorRender)
  633. {
  634. removeProtectedChild(_colorRender);
  635. _colorRender = nullptr;
  636. }
  637. if (_gradientRender)
  638. {
  639. removeProtectedChild(_gradientRender);
  640. _gradientRender = nullptr;
  641. }
  642. break;
  643. case BackGroundColorType::SOLID:
  644. if (_colorRender)
  645. {
  646. removeProtectedChild(_colorRender);
  647. _colorRender = nullptr;
  648. }
  649. break;
  650. case BackGroundColorType::GRADIENT:
  651. if (_gradientRender)
  652. {
  653. removeProtectedChild(_gradientRender);
  654. _gradientRender = nullptr;
  655. }
  656. break;
  657. default:
  658. break;
  659. }
  660. _colorType = type;
  661. switch (_colorType)
  662. {
  663. case BackGroundColorType::NONE:
  664. break;
  665. case BackGroundColorType::SOLID:
  666. _colorRender = LayerColor::create();
  667. _colorRender->setContentSize(_contentSize);
  668. _colorRender->setOpacity(_cOpacity);
  669. _colorRender->setColor(_cColor);
  670. addProtectedChild(_colorRender, BCAKGROUNDCOLORRENDERER_Z, -1);
  671. break;
  672. case BackGroundColorType::GRADIENT:
  673. _gradientRender = LayerGradient::create();
  674. _gradientRender->setContentSize(_contentSize);
  675. _gradientRender->setOpacity(_cOpacity);
  676. _gradientRender->setStartColor(_gStartColor);
  677. _gradientRender->setEndColor(_gEndColor);
  678. _gradientRender->setVector(_alongVector);
  679. addProtectedChild(_gradientRender, BCAKGROUNDCOLORRENDERER_Z, -1);
  680. break;
  681. default:
  682. break;
  683. }
  684. }
  685. Layout::BackGroundColorType Layout::getBackGroundColorType()const
  686. {
  687. return _colorType;
  688. }
  689. void Layout::setBackGroundColor(const Color3B &color)
  690. {
  691. _cColor = color;
  692. if (_colorRender)
  693. {
  694. _colorRender->setColor(color);
  695. }
  696. }
  697. const Color3B& Layout::getBackGroundColor()const
  698. {
  699. return _cColor;
  700. }
  701. void Layout::setBackGroundColor(const Color3B &startColor, const Color3B &endColor)
  702. {
  703. _gStartColor = startColor;
  704. if (_gradientRender)
  705. {
  706. _gradientRender->setStartColor(startColor);
  707. }
  708. _gEndColor = endColor;
  709. if (_gradientRender)
  710. {
  711. _gradientRender->setEndColor(endColor);
  712. }
  713. }
  714. const Color3B& Layout::getBackGroundStartColor()const
  715. {
  716. return _gStartColor;
  717. }
  718. const Color3B& Layout::getBackGroundEndColor()const
  719. {
  720. return _gEndColor;
  721. }
  722. void Layout::setBackGroundColorOpacity(GLubyte opacity)
  723. {
  724. _cOpacity = opacity;
  725. switch (_colorType)
  726. {
  727. case BackGroundColorType::NONE:
  728. break;
  729. case BackGroundColorType::SOLID:
  730. _colorRender->setOpacity(opacity);
  731. break;
  732. case BackGroundColorType::GRADIENT:
  733. _gradientRender->setOpacity(opacity);
  734. break;
  735. default:
  736. break;
  737. }
  738. }
  739. GLubyte Layout::getBackGroundColorOpacity()const
  740. {
  741. return _cOpacity;
  742. }
  743. void Layout::setBackGroundColorVector(const Vec2 &vector)
  744. {
  745. _alongVector = vector;
  746. if (_gradientRender)
  747. {
  748. _gradientRender->setVector(vector);
  749. }
  750. }
  751. const Vec2& Layout::getBackGroundColorVector()const
  752. {
  753. return _alongVector;
  754. }
  755. void Layout::setBackGroundImageColor(const Color3B &color)
  756. {
  757. _backGroundImageColor = color;
  758. updateBackGroundImageColor();
  759. }
  760. void Layout::setBackGroundImageOpacity(GLubyte opacity)
  761. {
  762. _backGroundImageOpacity = opacity;
  763. updateBackGroundImageOpacity();
  764. }
  765. const Color3B& Layout::getBackGroundImageColor()const
  766. {
  767. return _backGroundImageColor;
  768. }
  769. GLubyte Layout::getBackGroundImageOpacity()const
  770. {
  771. return _backGroundImageOpacity;
  772. }
  773. void Layout::updateBackGroundImageColor()
  774. {
  775. if (_backGroundImage)
  776. {
  777. _backGroundImage->setColor(_backGroundImageColor);
  778. }
  779. }
  780. void Layout::updateBackGroundImageOpacity()
  781. {
  782. if (_backGroundImage)
  783. {
  784. _backGroundImage->setOpacity(_backGroundImageOpacity);
  785. }
  786. }
  787. void Layout::updateBackGroundImageRGBA()
  788. {
  789. if (_backGroundImage)
  790. {
  791. _backGroundImage->setColor(_backGroundImageColor);
  792. _backGroundImage->setOpacity(_backGroundImageOpacity);
  793. }
  794. }
  795. const Size& Layout::getBackGroundImageTextureSize() const
  796. {
  797. return _backGroundImageTextureSize;
  798. }
  799. void Layout::setLayoutType(Type type)
  800. {
  801. _layoutType = type;
  802. for (auto& child : _children)
  803. {
  804. Widget* widgetChild = dynamic_cast<Widget*>(child);
  805. if (widgetChild)
  806. {
  807. supplyTheLayoutParameterLackToChild(static_cast<Widget*>(child));
  808. }
  809. }
  810. _doLayoutDirty = true;
  811. }
  812. Layout::Type Layout::getLayoutType() const
  813. {
  814. return _layoutType;
  815. }
  816. void Layout::forceDoLayout()
  817. {
  818. this->requestDoLayout();
  819. this->doLayout();
  820. }
  821. void Layout::requestDoLayout()
  822. {
  823. _doLayoutDirty = true;
  824. }
  825. Size Layout::getLayoutContentSize()const
  826. {
  827. return this->getContentSize();
  828. }
  829. const Vector<Node*>& Layout::getLayoutElements()const
  830. {
  831. return this->getChildren();
  832. }
  833. LayoutManager* Layout::createLayoutManager()
  834. {
  835. LayoutManager* exe = nullptr;
  836. switch (_layoutType)
  837. {
  838. case Type::VERTICAL:
  839. exe = LinearVerticalLayoutManager::create();
  840. break;
  841. case Type::HORIZONTAL:
  842. exe = LinearHorizontalLayoutManager::create();
  843. break;
  844. case Type::RELATIVE:
  845. exe = RelativeLayoutManager::create();
  846. break;
  847. default:
  848. break;
  849. }
  850. return exe;
  851. }
  852. void Layout::doLayout()
  853. {
  854. if (!_doLayoutDirty)
  855. {
  856. return;
  857. }
  858. sortAllChildren();
  859. LayoutManager* executant = this->createLayoutManager();
  860. if (executant)
  861. {
  862. executant->doLayout(this);
  863. }
  864. _doLayoutDirty = false;
  865. }
  866. std::string Layout::getDescription() const
  867. {
  868. return "Layout";
  869. }
  870. Widget* Layout::createCloneInstance()
  871. {
  872. return Layout::create();
  873. }
  874. void Layout::copyClonedWidgetChildren(Widget* model)
  875. {
  876. Widget::copyClonedWidgetChildren(model);
  877. }
  878. void Layout::copySpecialProperties(Widget *widget)
  879. {
  880. Layout* layout = dynamic_cast<Layout*>(widget);
  881. if (layout)
  882. {
  883. setBackGroundImageScale9Enabled(layout->_backGroundScale9Enabled);
  884. setBackGroundImage(layout->_backGroundImageFileName,layout->_bgImageTexType);
  885. setBackGroundImageCapInsets(layout->_backGroundImageCapInsets);
  886. setBackGroundColorType(layout->_colorType);
  887. setBackGroundColor(layout->_cColor);
  888. setBackGroundColor(layout->_gStartColor, layout->_gEndColor);
  889. setBackGroundColorOpacity(layout->_cOpacity);
  890. setBackGroundColorVector(layout->_alongVector);
  891. setLayoutType(layout->_layoutType);
  892. setClippingEnabled(layout->_clippingEnabled);
  893. setClippingType(layout->_clippingType);
  894. _loopFocus = layout->_loopFocus;
  895. _passFocusToChild = layout->_passFocusToChild;
  896. _isInterceptTouch = layout->_isInterceptTouch;
  897. }
  898. }
  899. void Layout::setLoopFocus(bool loop)
  900. {
  901. _loopFocus = loop;
  902. }
  903. bool Layout::isLoopFocus()const
  904. {
  905. return _loopFocus;
  906. }
  907. void Layout::setPassFocusToChild(bool pass)
  908. {
  909. _passFocusToChild = pass;
  910. }
  911. bool Layout::isPassFocusToChild()const
  912. {
  913. return _passFocusToChild;
  914. }
  915. Size Layout::getLayoutAccumulatedSize()const
  916. {
  917. const auto& children = this->getChildren();
  918. Size layoutSize = Size::ZERO;
  919. int widgetCount =0;
  920. for(const auto& widget : children)
  921. {
  922. Layout *layout = dynamic_cast<Layout*>(widget);
  923. if (nullptr != layout)
  924. {
  925. layoutSize = layoutSize + layout->getLayoutAccumulatedSize();
  926. }
  927. else
  928. {
  929. Widget *w = dynamic_cast<Widget*>(widget);
  930. if (w)
  931. {
  932. widgetCount++;
  933. Margin m = w->getLayoutParameter()->getMargin();
  934. layoutSize = layoutSize + w->getContentSize() + Size(m.right + m.left, m.top + m.bottom) * 0.5;
  935. }
  936. }
  937. }
  938. //subtract extra size
  939. Type type = this->getLayoutType();
  940. if (type == Type::HORIZONTAL)
  941. {
  942. layoutSize = layoutSize - Size(0, layoutSize.height/widgetCount * (widgetCount-1));
  943. }
  944. if (type == Type::VERTICAL)
  945. {
  946. layoutSize = layoutSize - Size(layoutSize.width/widgetCount * (widgetCount-1), 0);
  947. }
  948. return layoutSize;
  949. }
  950. Vec2 Layout::getWorldCenterPoint(Widget* widget)const
  951. {
  952. Layout *layout = dynamic_cast<Layout*>(widget);
  953. //FIXEDME: we don't need to calculate the content size of layout anymore
  954. Size widgetSize = layout ? layout->getLayoutAccumulatedSize() : widget->getContentSize();
  955. // CCLOG("content size : width = %f, height = %f", widgetSize.width, widgetSize.height);
  956. return widget->convertToWorldSpace(Vec2(widgetSize.width/2, widgetSize.height/2));
  957. }
  958. float Layout::calculateNearestDistance(Widget* baseWidget)
  959. {
  960. float distance = FLT_MAX;
  961. Vec2 widgetPosition = this->getWorldCenterPoint(baseWidget);
  962. for (Node* node : _children)
  963. {
  964. Layout *layout = dynamic_cast<Layout*>(node);
  965. int length;
  966. if (layout)
  967. {
  968. length = layout->calculateNearestDistance(baseWidget);
  969. }
  970. else
  971. {
  972. Widget* w = dynamic_cast<Widget*>(node);
  973. if (w && w->isFocusEnabled())
  974. {
  975. Vec2 wPosition = this->getWorldCenterPoint(w);
  976. length = (wPosition - widgetPosition).length();
  977. }
  978. else
  979. {
  980. continue;
  981. }
  982. }
  983. if (length < distance)
  984. {
  985. distance = length;
  986. }
  987. }
  988. return distance;
  989. }
  990. float Layout::calculateFarthestDistance(cocos2d::ui::Widget *baseWidget)
  991. {
  992. float distance = -FLT_MAX;
  993. Vec2 widgetPosition = this->getWorldCenterPoint(baseWidget);
  994. for (Node* node : _children)
  995. {
  996. Layout *layout = dynamic_cast<Layout*>(node);
  997. int length;
  998. if (layout)
  999. {
  1000. length = layout->calculateFarthestDistance(baseWidget);
  1001. }
  1002. else
  1003. {
  1004. Widget* w = dynamic_cast<Widget*>(node);
  1005. if (w && w->isFocusEnabled()) {
  1006. Vec2 wPosition = this->getWorldCenterPoint(w);
  1007. length = (wPosition - widgetPosition).length();
  1008. }
  1009. else
  1010. {
  1011. continue;
  1012. }
  1013. }
  1014. if (length > distance)
  1015. {
  1016. distance = length;
  1017. }
  1018. }
  1019. return distance;
  1020. }
  1021. int Layout::findFirstFocusEnabledWidgetIndex()
  1022. {
  1023. ssize_t index = 0;
  1024. ssize_t count = this->getChildren().size();
  1025. while (index < count)
  1026. {
  1027. Widget* w = dynamic_cast<Widget*>(_children.at(index));
  1028. if (w && w->isFocusEnabled())
  1029. {
  1030. return (int)index;
  1031. }
  1032. index++;
  1033. }
  1034. CCASSERT(0, "invalid operation");
  1035. return 0;
  1036. }
  1037. int Layout::findNearestChildWidgetIndex(FocusDirection direction, Widget* baseWidget)
  1038. {
  1039. if (baseWidget == nullptr || baseWidget == this)
  1040. {
  1041. return this->findFirstFocusEnabledWidgetIndex();
  1042. }
  1043. int index = 0;
  1044. ssize_t count = this->getChildren().size();
  1045. float distance = FLT_MAX;
  1046. int found = 0;
  1047. if (direction == FocusDirection::LEFT || direction == FocusDirection::RIGHT ||
  1048. direction == FocusDirection::DOWN || direction == FocusDirection::UP)
  1049. {
  1050. Vec2 widgetPosition = this->getWorldCenterPoint(baseWidget);
  1051. while (index < count)
  1052. {
  1053. Widget *w = dynamic_cast<Widget*>(this->getChildren().at(index));
  1054. if (w && w->isFocusEnabled())
  1055. {
  1056. Vec2 wPosition = this->getWorldCenterPoint(w);
  1057. float length;
  1058. Layout *layout = dynamic_cast<Layout*>(w);
  1059. if (layout)
  1060. {
  1061. length = layout->calculateNearestDistance(baseWidget);
  1062. }
  1063. else
  1064. {
  1065. length = (wPosition - widgetPosition).getLength();
  1066. }
  1067. if (length < distance)
  1068. {
  1069. found = index;
  1070. distance = length;
  1071. }
  1072. }
  1073. index++;
  1074. }
  1075. return found;
  1076. }
  1077. CCASSERT(0, "invalid focus direction!!!");
  1078. return 0;
  1079. }
  1080. int Layout::findFarthestChildWidgetIndex(FocusDirection direction, cocos2d::ui::Widget *baseWidget)
  1081. {
  1082. if (baseWidget == nullptr || baseWidget == this)
  1083. {
  1084. return this->findFirstFocusEnabledWidgetIndex();
  1085. }
  1086. int index = 0;
  1087. ssize_t count = this->getChildren().size();
  1088. float distance = -FLT_MAX;
  1089. int found = 0;
  1090. if (direction == FocusDirection::LEFT || direction == FocusDirection::RIGHT
  1091. || direction == FocusDirection::DOWN || direction == FocusDirection::UP)
  1092. {
  1093. Vec2 widgetPosition = this->getWorldCenterPoint(baseWidget);
  1094. while (index < count)
  1095. {
  1096. Widget *w = dynamic_cast<Widget*>(this->getChildren().at(index));
  1097. if (w && w->isFocusEnabled())
  1098. {
  1099. Vec2 wPosition = this->getWorldCenterPoint(w);
  1100. float length;
  1101. Layout *layout = dynamic_cast<Layout*>(w);
  1102. if (layout)
  1103. {
  1104. length = layout->calculateFarthestDistance(baseWidget);
  1105. }
  1106. else
  1107. {
  1108. length = (wPosition - widgetPosition).getLength();
  1109. }
  1110. if (length > distance)
  1111. {
  1112. found = index;
  1113. distance = length;
  1114. }
  1115. }
  1116. index++;
  1117. }
  1118. return found;
  1119. }
  1120. CCASSERT(0, "invalid focus direction!!!");
  1121. return 0;
  1122. }
  1123. Widget* Layout::findFocusEnabledChildWidgetByIndex(ssize_t index)
  1124. {
  1125. Widget *widget = this->getChildWidgetByIndex(index);
  1126. if (widget)
  1127. {
  1128. if (widget->isFocusEnabled())
  1129. {
  1130. return widget;
  1131. }
  1132. index = index + 1;
  1133. return this->findFocusEnabledChildWidgetByIndex(index);
  1134. }
  1135. return nullptr;
  1136. }
  1137. Widget *Layout::findFirstNonLayoutWidget()
  1138. {
  1139. Widget* widget = nullptr;
  1140. for(Node *node : _children)
  1141. {
  1142. Layout* layout = dynamic_cast<Layout*>(node);
  1143. if (layout)
  1144. {
  1145. widget = layout->findFirstNonLayoutWidget();
  1146. if (widget != nullptr)
  1147. {
  1148. return widget;
  1149. }
  1150. }
  1151. else
  1152. {
  1153. Widget *w = dynamic_cast<Widget*>(node);
  1154. if (w)
  1155. {
  1156. widget = w;
  1157. break;
  1158. }
  1159. }
  1160. }
  1161. return widget;
  1162. }
  1163. void Layout::findProperSearchingFunctor(FocusDirection dir, Widget* baseWidget)
  1164. {
  1165. if (baseWidget == nullptr)
  1166. {
  1167. return;
  1168. }
  1169. Vec2 previousWidgetPosition = this->getWorldCenterPoint(baseWidget);
  1170. Vec2 widgetPosition = this->getWorldCenterPoint(this->findFirstNonLayoutWidget());
  1171. if (dir == FocusDirection::LEFT)
  1172. {
  1173. if (previousWidgetPosition.x > widgetPosition.x)
  1174. {
  1175. onPassFocusToChild = CC_CALLBACK_2(Layout::findNearestChildWidgetIndex, this);
  1176. }
  1177. else
  1178. {
  1179. onPassFocusToChild = CC_CALLBACK_2(Layout::findFarthestChildWidgetIndex, this);
  1180. }
  1181. }
  1182. else if(dir == FocusDirection::RIGHT)
  1183. {
  1184. if (previousWidgetPosition.x > widgetPosition.x)
  1185. {
  1186. onPassFocusToChild = CC_CALLBACK_2(Layout::findFarthestChildWidgetIndex, this);
  1187. }
  1188. else
  1189. {
  1190. onPassFocusToChild = CC_CALLBACK_2(Layout::findNearestChildWidgetIndex, this);
  1191. }
  1192. }
  1193. else if(dir == FocusDirection::DOWN)
  1194. {
  1195. if (previousWidgetPosition.y > widgetPosition.y)
  1196. {
  1197. onPassFocusToChild = CC_CALLBACK_2(Layout::findNearestChildWidgetIndex, this);
  1198. }
  1199. else
  1200. {
  1201. onPassFocusToChild = CC_CALLBACK_2(Layout::findFarthestChildWidgetIndex, this);
  1202. }
  1203. }
  1204. else if(dir == FocusDirection::UP)
  1205. {
  1206. if (previousWidgetPosition.y < widgetPosition.y)
  1207. {
  1208. onPassFocusToChild = CC_CALLBACK_2(Layout::findNearestChildWidgetIndex, this);
  1209. }
  1210. else
  1211. {
  1212. onPassFocusToChild = CC_CALLBACK_2(Layout::findFarthestChildWidgetIndex, this);
  1213. }
  1214. }
  1215. else
  1216. {
  1217. CCASSERT(0, "invalid direction!");
  1218. }
  1219. }
  1220. Widget* Layout::passFocusToChild(FocusDirection dir, cocos2d::ui::Widget *current)
  1221. {
  1222. if (checkFocusEnabledChild())
  1223. {
  1224. Widget* previousWidget = this->getCurrentFocusedWidget();
  1225. this->findProperSearchingFunctor(dir, previousWidget);
  1226. int index = onPassFocusToChild(dir, previousWidget);
  1227. Widget *widget = this->getChildWidgetByIndex(index);
  1228. Layout *layout = dynamic_cast<Layout*>(widget);
  1229. if (layout)
  1230. {
  1231. layout->_isFocusPassing = true;
  1232. return layout->findNextFocusedWidget(dir, layout);
  1233. }
  1234. else
  1235. {
  1236. this->dispatchFocusEvent(current, widget);
  1237. return widget;
  1238. }
  1239. }
  1240. else
  1241. {
  1242. return this;
  1243. }
  1244. }
  1245. bool Layout::checkFocusEnabledChild()const
  1246. {
  1247. bool ret = false;
  1248. for(Node* node : _children)
  1249. {
  1250. Widget* widget = dynamic_cast<Widget*>(node);
  1251. if (widget && widget->isFocusEnabled())
  1252. {
  1253. ret = true;
  1254. break;
  1255. }
  1256. }
  1257. return ret;
  1258. }
  1259. Widget* Layout::getChildWidgetByIndex(ssize_t index)const
  1260. {
  1261. ssize_t size = _children.size();
  1262. int count = 0;
  1263. ssize_t oldIndex = index;
  1264. Widget *widget = nullptr;
  1265. while (index < size)
  1266. {
  1267. Widget* firstChild = dynamic_cast<Widget*>(_children.at(index));
  1268. if (firstChild)
  1269. {
  1270. widget = firstChild;
  1271. break;
  1272. }
  1273. count++;
  1274. index++;
  1275. }
  1276. if (nullptr == widget)
  1277. {
  1278. int begin = 0;
  1279. while (begin < oldIndex)
  1280. {
  1281. Widget* firstChild = dynamic_cast<Widget*>(_children.at(begin));
  1282. if (firstChild)
  1283. {
  1284. widget = firstChild;
  1285. break;
  1286. }
  1287. count++;
  1288. begin++;
  1289. }
  1290. }
  1291. return widget;
  1292. }
  1293. Widget* Layout::getPreviousFocusedWidget(FocusDirection direction, Widget *current)
  1294. {
  1295. Widget *nextWidget = nullptr;
  1296. ssize_t previousWidgetPos = _children.getIndex(current);
  1297. previousWidgetPos = previousWidgetPos - 1;
  1298. if (previousWidgetPos >= 0)
  1299. {
  1300. nextWidget = this->getChildWidgetByIndex(previousWidgetPos);
  1301. if (nextWidget->isFocusEnabled())
  1302. {
  1303. Layout* layout = dynamic_cast<Layout*>(nextWidget);
  1304. if (layout)
  1305. {
  1306. layout->_isFocusPassing = true;
  1307. return layout->findNextFocusedWidget(direction, layout);
  1308. }
  1309. this->dispatchFocusEvent(current, nextWidget);
  1310. return nextWidget;
  1311. }
  1312. else
  1313. {
  1314. //handling the disabled widget, there is no actual focus lose or get, so we don't need any event
  1315. return this->getPreviousFocusedWidget(direction, nextWidget);
  1316. }
  1317. }
  1318. else
  1319. {
  1320. if (_loopFocus)
  1321. {
  1322. if (checkFocusEnabledChild())
  1323. {
  1324. previousWidgetPos = _children.size()-1;
  1325. nextWidget = this->getChildWidgetByIndex(previousWidgetPos);
  1326. if (nextWidget->isFocusEnabled())
  1327. {
  1328. Layout* layout = dynamic_cast<Layout*>(nextWidget);
  1329. if (layout)
  1330. {
  1331. layout->_isFocusPassing = true;
  1332. return layout->findNextFocusedWidget(direction, layout);
  1333. }
  1334. else
  1335. {
  1336. this->dispatchFocusEvent(current, nextWidget);
  1337. return nextWidget;
  1338. }
  1339. }
  1340. else
  1341. {
  1342. return this->getPreviousFocusedWidget(direction, nextWidget);
  1343. }
  1344. }
  1345. else
  1346. {
  1347. if (dynamic_cast<Layout*>(current))
  1348. {
  1349. return current;
  1350. }
  1351. else
  1352. {
  1353. return _focusedWidget;
  1354. }
  1355. }
  1356. }
  1357. else
  1358. {
  1359. if (isLastWidgetInContainer(current, direction))
  1360. {
  1361. if (isWidgetAncestorSupportLoopFocus(this, direction))
  1362. {
  1363. return Widget::findNextFocusedWidget(direction, this);
  1364. }
  1365. if (dynamic_cast<Layout*>(current))
  1366. {
  1367. return current;
  1368. }
  1369. else
  1370. {
  1371. return _focusedWidget;
  1372. }
  1373. }
  1374. else
  1375. {
  1376. return Widget::findNextFocusedWidget(direction, this);
  1377. }
  1378. }
  1379. }
  1380. }
  1381. Widget* Layout::getNextFocusedWidget(FocusDirection direction, Widget *current)
  1382. {
  1383. Widget *nextWidget = nullptr;
  1384. ssize_t previousWidgetPos = _children.getIndex(current);
  1385. previousWidgetPos = previousWidgetPos + 1;
  1386. if (previousWidgetPos < _children.size())
  1387. {
  1388. nextWidget = this->getChildWidgetByIndex(previousWidgetPos);
  1389. //handle widget
  1390. if (nextWidget)
  1391. {
  1392. if (nextWidget->isFocusEnabled())
  1393. {
  1394. Layout* layout = dynamic_cast<Layout*>(nextWidget);
  1395. if (layout)
  1396. {
  1397. layout->_isFocusPassing = true;
  1398. return layout->findNextFocusedWidget(direction, layout);
  1399. }
  1400. else
  1401. {
  1402. this->dispatchFocusEvent(current, nextWidget);
  1403. return nextWidget;
  1404. }
  1405. }
  1406. else
  1407. {
  1408. return this->getNextFocusedWidget(direction, nextWidget);
  1409. }
  1410. }
  1411. else
  1412. {
  1413. return current;
  1414. }
  1415. }
  1416. else
  1417. {
  1418. if (_loopFocus)
  1419. {
  1420. if (checkFocusEnabledChild())
  1421. {
  1422. previousWidgetPos = 0;
  1423. nextWidget = this->getChildWidgetByIndex(previousWidgetPos);
  1424. if (nextWidget->isFocusEnabled())
  1425. {
  1426. Layout* layout = dynamic_cast<Layout*>(nextWidget);
  1427. if (layout)
  1428. {
  1429. layout->_isFocusPassing = true;
  1430. return layout->findNextFocusedWidget(direction, layout);
  1431. }
  1432. else
  1433. {
  1434. this->dispatchFocusEvent(current, nextWidget);
  1435. return nextWidget;
  1436. }
  1437. }
  1438. else
  1439. {
  1440. return this->getNextFocusedWidget(direction, nextWidget);
  1441. }
  1442. }
  1443. else
  1444. {
  1445. if (dynamic_cast<Layout*>(current)) {
  1446. return current;
  1447. }
  1448. else
  1449. {
  1450. return _focusedWidget;
  1451. }
  1452. }
  1453. }
  1454. else
  1455. {
  1456. if (isLastWidgetInContainer(current, direction))
  1457. {
  1458. if (isWidgetAncestorSupportLoopFocus(this, direction))
  1459. {
  1460. return Widget::findNextFocusedWidget(direction, this);
  1461. }
  1462. if (dynamic_cast<Layout*>(current)) {
  1463. return current;
  1464. }
  1465. else
  1466. {
  1467. return _focusedWidget;
  1468. }
  1469. }
  1470. else
  1471. {
  1472. return Widget::findNextFocusedWidget(direction, this);
  1473. }
  1474. }
  1475. }
  1476. }
  1477. bool Layout::isLastWidgetInContainer(Widget* widget, FocusDirection direction)const
  1478. {
  1479. Layout* parent = dynamic_cast<Layout*>(widget->getParent());
  1480. if (parent == nullptr)
  1481. {
  1482. return true;
  1483. }
  1484. auto& container = parent->getChildren();
  1485. ssize_t index = container.getIndex(widget);
  1486. if (parent->getLayoutType() == Type::HORIZONTAL)
  1487. {
  1488. if (direction == FocusDirection::LEFT)
  1489. {
  1490. if (index == 0)
  1491. {
  1492. return isLastWidgetInContainer(parent, direction);
  1493. }
  1494. else
  1495. {
  1496. return false;
  1497. }
  1498. }
  1499. if (direction == FocusDirection::RIGHT)
  1500. {
  1501. if (index == container.size()-1)
  1502. {
  1503. return isLastWidgetInContainer(parent, direction);
  1504. }
  1505. else
  1506. {
  1507. return false;
  1508. }
  1509. }
  1510. if (direction == FocusDirection::DOWN)
  1511. {
  1512. return isLastWidgetInContainer(parent, direction);
  1513. }
  1514. if (direction == FocusDirection::UP)
  1515. {
  1516. return isLastWidgetInContainer(parent, direction);
  1517. }
  1518. }
  1519. else if(parent->getLayoutType() == Type::VERTICAL)
  1520. {
  1521. if (direction == FocusDirection::UP)
  1522. {
  1523. if (index == 0)
  1524. {
  1525. return isLastWidgetInContainer(parent, direction);
  1526. }
  1527. else
  1528. {
  1529. return false;
  1530. }
  1531. }
  1532. if (direction == FocusDirection::DOWN)
  1533. {
  1534. if (index == container.size() - 1)
  1535. {
  1536. return isLastWidgetInContainer(parent, direction);
  1537. }
  1538. else
  1539. {
  1540. return false;
  1541. }
  1542. }
  1543. if (direction == FocusDirection::LEFT)
  1544. {
  1545. return isLastWidgetInContainer(parent, direction);
  1546. }
  1547. if (direction == FocusDirection::RIGHT)
  1548. {
  1549. return isLastWidgetInContainer(parent, direction);
  1550. }
  1551. }
  1552. else
  1553. {
  1554. CCASSERT(0, "invalid layout Type");
  1555. return false;
  1556. }
  1557. return false;
  1558. }
  1559. bool Layout::isWidgetAncestorSupportLoopFocus(Widget* widget, FocusDirection direction)const
  1560. {
  1561. Layout* parent = dynamic_cast<Layout*>(widget->getParent());
  1562. if (parent == nullptr)
  1563. {
  1564. return false;
  1565. }
  1566. if (parent->isLoopFocus())
  1567. {
  1568. auto layoutType = parent->getLayoutType();
  1569. if (layoutType == Type::HORIZONTAL)
  1570. {
  1571. if (direction == FocusDirection::LEFT || direction == FocusDirection::RIGHT)
  1572. {
  1573. return true;
  1574. }
  1575. else
  1576. {
  1577. return isWidgetAncestorSupportLoopFocus(parent, direction);
  1578. }
  1579. }
  1580. if (layoutType == Type::VERTICAL)
  1581. {
  1582. if (direction == FocusDirection::DOWN || direction == FocusDirection::UP)
  1583. {
  1584. return true;
  1585. }
  1586. else
  1587. {
  1588. return isWidgetAncestorSupportLoopFocus(parent, direction);
  1589. }
  1590. }
  1591. else
  1592. {
  1593. CCASSERT(0, "invalid layout type");
  1594. return false;
  1595. }
  1596. }
  1597. else
  1598. {
  1599. return isWidgetAncestorSupportLoopFocus(parent, direction);
  1600. }
  1601. }
  1602. Widget* Layout::findNextFocusedWidget(FocusDirection direction, Widget* current)
  1603. {
  1604. if (_isFocusPassing || this->isFocused())
  1605. {
  1606. Layout* parent = dynamic_cast<Layout*>(this->getParent());
  1607. _isFocusPassing = false;
  1608. if (_passFocusToChild)
  1609. {
  1610. Widget * w = this->passFocusToChild(direction, current);
  1611. if (dynamic_cast<Layout*>(w))
  1612. {
  1613. if (parent)
  1614. {
  1615. parent->_isFocusPassing = true;
  1616. return parent->findNextFocusedWidget(direction, this);
  1617. }
  1618. }
  1619. return w;
  1620. }
  1621. if (nullptr == parent)
  1622. {
  1623. return this;
  1624. }
  1625. parent->_isFocusPassing = true;
  1626. return parent->findNextFocusedWidget(direction, this);
  1627. }
  1628. else if(current->isFocused() || dynamic_cast<Layout*>(current))
  1629. {
  1630. if (_layoutType == Type::HORIZONTAL)
  1631. {
  1632. switch (direction)
  1633. {
  1634. case FocusDirection::LEFT:
  1635. {
  1636. return this->getPreviousFocusedWidget(direction, current);
  1637. }break;
  1638. case FocusDirection::RIGHT:
  1639. {
  1640. return this->getNextFocusedWidget(direction, current);
  1641. }break;
  1642. case FocusDirection::DOWN:
  1643. case FocusDirection::UP:
  1644. {
  1645. if (isLastWidgetInContainer(this, direction))
  1646. {
  1647. if (isWidgetAncestorSupportLoopFocus(current, direction))
  1648. {
  1649. return Widget::findNextFocusedWidget(direction, this);
  1650. }
  1651. return current;
  1652. }
  1653. else
  1654. {
  1655. return Widget::findNextFocusedWidget(direction, this);
  1656. }
  1657. }break;
  1658. default:
  1659. {
  1660. CCASSERT(0, "Invalid Focus Direction");
  1661. return current;
  1662. }
  1663. break;
  1664. }
  1665. }
  1666. else if (_layoutType == Type::VERTICAL)
  1667. {
  1668. switch (direction)
  1669. {
  1670. case FocusDirection::LEFT:
  1671. case FocusDirection::RIGHT:
  1672. {
  1673. if (isLastWidgetInContainer(this, direction))
  1674. {
  1675. if (isWidgetAncestorSupportLoopFocus(current, direction))
  1676. {
  1677. return Widget::findNextFocusedWidget(direction, this);
  1678. }
  1679. return current;
  1680. }
  1681. else
  1682. {
  1683. return Widget::findNextFocusedWidget(direction, this);
  1684. }
  1685. } break;
  1686. case FocusDirection::DOWN:
  1687. {
  1688. return getNextFocusedWidget(direction, current);
  1689. }
  1690. break;
  1691. case FocusDirection::UP:
  1692. {
  1693. return getPreviousFocusedWidget(direction, current);
  1694. }
  1695. break;
  1696. default:
  1697. {
  1698. CCASSERT(0, "Invalid Focus Direction");
  1699. return current;
  1700. }
  1701. break;
  1702. }
  1703. }
  1704. else
  1705. {
  1706. CCASSERT(0, "Un Supported Layout type, please use VBox and HBox instead!!!");
  1707. return current;
  1708. }
  1709. }
  1710. else
  1711. {
  1712. return current;
  1713. }
  1714. }
  1715. void Layout::setCameraMask(unsigned short mask, bool applyChildren)
  1716. {
  1717. Widget::setCameraMask(mask, applyChildren);
  1718. if (_clippingStencil){
  1719. _clippingStencil->setCameraMask(mask, applyChildren);
  1720. }
  1721. }
  1722. ResourceData Layout::getRenderFile()
  1723. {
  1724. ResourceData rData;
  1725. rData.type = (int)_bgImageTexType;
  1726. rData.file = _backGroundImageFileName;
  1727. return rData;
  1728. }
  1729. }
  1730. NS_CC_END