BsGUIElementBase.cpp 6.4 KB

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