BsGUIElementBase.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. #include "BsGUIElementBase.h"
  2. #include "BsGUILayout.h"
  3. #include "BsGUILayoutX.h"
  4. #include "BsGUILayoutY.h"
  5. #include "BsGUILayoutExplicit.h"
  6. #include "BsGUIElement.h"
  7. #include "BsException.h"
  8. #include "BsGUIWidget.h"
  9. namespace BansheeEngine
  10. {
  11. GUIElementBase::GUIElementBase()
  12. :mIsDirty(true), mParentElement(nullptr), mIsDisabled(false), mParentWidget(nullptr)
  13. {
  14. }
  15. GUIElementBase::~GUIElementBase()
  16. {
  17. Vector<GUIElementBase*> childCopy = mChildren;
  18. for (auto& child : childCopy)
  19. {
  20. if (child->_getType() == GUIElementBase::Type::Element)
  21. {
  22. GUIElement* element = static_cast<GUIElement*>(child);
  23. GUIElement::destroy(element);
  24. }
  25. else
  26. {
  27. auto iterFind = std::find(mChildren.begin(), mChildren.end(), child);
  28. if (iterFind != mChildren.end())
  29. mChildren.erase(iterFind);
  30. bs_delete(child);
  31. }
  32. }
  33. }
  34. bool GUIElementBase::_isContentDirty() const
  35. {
  36. if((mIsDirty & 0x01) != 0)
  37. return true;
  38. for(auto& child : mChildren)
  39. {
  40. if(child->_isContentDirty())
  41. return true;
  42. }
  43. return false;
  44. }
  45. bool GUIElementBase::_isMeshDirty() const
  46. {
  47. return (mIsDirty & 0x02) != 0;
  48. }
  49. void GUIElementBase::markContentAsDirty()
  50. {
  51. if(_isDisabled())
  52. return;
  53. mIsDirty |= 0x01;
  54. }
  55. void GUIElementBase::markMeshAsDirty()
  56. {
  57. if(_isDisabled())
  58. return;
  59. mIsDirty |= 0x02;
  60. }
  61. void GUIElementBase::enableRecursively()
  62. {
  63. if (mParentElement != nullptr && mParentElement->mIsDisabled)
  64. return; // Cannot enable if parent is disabled
  65. // Make sure to mark everything as dirty, as we didn't track any dirty flags while the element was disabled
  66. mIsDisabled = false;
  67. markContentAsDirty();
  68. for(auto& elem : mChildren)
  69. {
  70. elem->enableRecursively();
  71. }
  72. }
  73. void GUIElementBase::disableRecursively()
  74. {
  75. markMeshAsDirty(); // Just need to hide the mesh
  76. mIsDisabled = true;
  77. for(auto& elem : mChildren)
  78. {
  79. elem->disableRecursively();
  80. }
  81. }
  82. void GUIElementBase::_updateLayout(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, UINT8 widgetDepth, UINT16 areaDepth)
  83. {
  84. _updateOptimalLayoutSizes(); // We calculate optimal sizes of all layouts as a pre-processing step, as they are requested often during update
  85. _updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, areaDepth);
  86. }
  87. void GUIElementBase::_updateOptimalLayoutSizes()
  88. {
  89. for(auto& child : mChildren)
  90. {
  91. child->_updateOptimalLayoutSizes();
  92. }
  93. }
  94. void GUIElementBase::_updateLayoutInternal(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I clipRect, UINT8 widgetDepth, UINT16 areaDepth)
  95. {
  96. for(auto& child : mChildren)
  97. {
  98. child->_updateLayoutInternal(x, y, width, height, clipRect, widgetDepth, areaDepth);
  99. }
  100. }
  101. void GUIElementBase::_getElementAreas(INT32 x, INT32 y, UINT32 width, UINT32 height, Rect2I* elementAreas, UINT32 numElements, const Vector<Vector2I>& optimalSizes) const
  102. {
  103. assert(mChildren.size() == 0);
  104. }
  105. void GUIElementBase::_setParent(GUIElementBase* parent)
  106. {
  107. if(mParentElement != parent)
  108. {
  109. mParentElement = parent;
  110. if (parent != nullptr)
  111. {
  112. if (_getParentWidget() != parent->_getParentWidget())
  113. _changeParentWidget(parent->_getParentWidget());
  114. }
  115. else
  116. _changeParentWidget(nullptr);
  117. }
  118. }
  119. GUILayout& GUIElementBase::addLayoutXInternal(GUIElementBase* parent)
  120. {
  121. GUILayoutX* entry = bs_new<GUILayoutX, PoolAlloc>();
  122. entry->_setParent(parent);
  123. mChildren.push_back(entry);
  124. if (mIsDisabled)
  125. entry->disableRecursively();
  126. markContentAsDirty();
  127. return *entry;
  128. }
  129. GUILayout& GUIElementBase::addLayoutYInternal(GUIElementBase* parent)
  130. {
  131. GUILayoutY* entry = bs_new<GUILayoutY, PoolAlloc>();
  132. entry->_setParent(parent);
  133. mChildren.push_back(entry);
  134. if (mIsDisabled)
  135. entry->disableRecursively();
  136. markContentAsDirty();
  137. return *entry;
  138. }
  139. GUILayout& GUIElementBase::addLayoutExplicitInternal(GUIElementBase* parent)
  140. {
  141. GUILayoutExplicit* entry = bs_new<GUILayoutExplicit, PoolAlloc>();
  142. entry->_setParent(parent);
  143. mChildren.push_back(entry);
  144. if (mIsDisabled)
  145. entry->disableRecursively();
  146. markContentAsDirty();
  147. return *entry;
  148. }
  149. void GUIElementBase::removeLayoutInternal(GUILayout& layout)
  150. {
  151. bool foundElem = false;
  152. for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
  153. {
  154. GUIElementBase* child = *iter;
  155. if(child->_getType() == GUIElementBase::Type::Layout && child == &layout)
  156. {
  157. bs_delete<PoolAlloc>(child);
  158. mChildren.erase(iter);
  159. foundElem = true;
  160. markContentAsDirty();
  161. break;
  162. }
  163. }
  164. if(!foundElem)
  165. BS_EXCEPT(InvalidParametersException, "Provided element is not a part of this layout.");
  166. }
  167. GUILayout& GUIElementBase::insertLayoutXInternal(GUIElementBase* parent, UINT32 idx)
  168. {
  169. if(idx < 0 || idx > (UINT32)mChildren.size())
  170. BS_EXCEPT(InvalidParametersException, "Index out of range: " + toString(idx) + ". Valid range: 0 .. " + toString((UINT32)mChildren.size()));
  171. GUILayoutX* entry = bs_new<GUILayoutX, PoolAlloc>();
  172. entry->_setParent(parent);
  173. mChildren.insert(mChildren.begin() + idx, entry);
  174. if (mIsDisabled)
  175. entry->disableRecursively();
  176. markContentAsDirty();
  177. return *entry;
  178. }
  179. GUILayout& GUIElementBase::insertLayoutYInternal(GUIElementBase* parent, UINT32 idx)
  180. {
  181. if(idx < 0 || idx > (UINT32)mChildren.size())
  182. BS_EXCEPT(InvalidParametersException, "Index out of range: " + toString(idx) + ". Valid range: 0 .. " + toString((UINT32)mChildren.size()));
  183. GUILayoutY* entry = bs_new<GUILayoutY, PoolAlloc>();
  184. entry->_setParent(parent);
  185. mChildren.insert(mChildren.begin() + idx, entry);
  186. if (mIsDisabled)
  187. entry->disableRecursively();
  188. markContentAsDirty();
  189. return *entry;
  190. }
  191. GUILayout& GUIElementBase::insertLayoutExplicitInternal(GUIElementBase* parent, UINT32 idx)
  192. {
  193. if (idx < 0 || idx >(UINT32)mChildren.size())
  194. BS_EXCEPT(InvalidParametersException, "Index out of range: " + toString(idx) + ". Valid range: 0 .. " + toString((UINT32)mChildren.size()));
  195. GUILayoutExplicit* entry = bs_new<GUILayoutExplicit, PoolAlloc>();
  196. entry->_setParent(parent);
  197. mChildren.insert(mChildren.begin() + idx, entry);
  198. if (mIsDisabled)
  199. entry->disableRecursively();
  200. markContentAsDirty();
  201. return *entry;
  202. }
  203. void GUIElementBase::_registerChildElement(GUIElement* element)
  204. {
  205. GUIElementBase* parentElement = element->_getParent();
  206. if(parentElement != nullptr)
  207. {
  208. parentElement->_unregisterChildElement(element);
  209. }
  210. element->_setParent(this);
  211. mChildren.push_back(element);
  212. if (mIsDisabled)
  213. element->disableRecursively();
  214. markContentAsDirty();
  215. }
  216. void GUIElementBase::_unregisterChildElement(GUIElement* element)
  217. {
  218. bool foundElem = false;
  219. for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
  220. {
  221. GUIElementBase* child = *iter;
  222. if(child->_getType() == GUIElementBase::Type::Element && child == element)
  223. {
  224. mChildren.erase(iter);
  225. element->_setParent(nullptr);
  226. foundElem = true;
  227. markContentAsDirty();
  228. break;
  229. }
  230. }
  231. if(!foundElem)
  232. BS_EXCEPT(InvalidParametersException, "Provided element is not a part of this element.");
  233. }
  234. void GUIElementBase::_changeParentWidget(GUIWidget* widget)
  235. {
  236. mParentWidget = widget;
  237. for(auto& child : mChildren)
  238. {
  239. child->_changeParentWidget(widget);
  240. }
  241. markContentAsDirty();
  242. }
  243. }