UILayout.cpp 51 KB

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