BsGUIElementBase.cpp 5.8 KB

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