UIRect.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  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. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "DebugRenderer.h"
  25. #include "Log.h"
  26. #include "Node.h"
  27. #include "Scene.h"
  28. #include "UIRect.h"
  29. #include "UIRoot.h"
  30. #include "UIXEvents.h"
  31. #include "DebugNew.h"
  32. namespace Urho3D
  33. {
  34. extern const char* UIX_CATEGORY;
  35. static const char* uiLayoutModes[] =
  36. {
  37. "Free",
  38. "Anchor",
  39. 0
  40. };
  41. static const char* uiXAnchorPivots[] =
  42. {
  43. "Center",
  44. "Left",
  45. "Right",
  46. 0
  47. };
  48. static const char* uiYAnchorPivots[] =
  49. {
  50. "Center",
  51. "Top",
  52. "Bottom",
  53. 0
  54. };
  55. UIRect::UIRect(Context* context) :
  56. Component(context),
  57. layoutMode_(UILM_FREE),
  58. position_(0.0f, 0.0f),
  59. size_(2.0f, 2.0f),
  60. leftAnchorPivot_(AP_XCENTER),
  61. rightAnchorPivot_(AP_XCENTER),
  62. topAnchorPivot_(AP_YCENTER),
  63. bottomAnchorPivot_(AP_YCENTER),
  64. leftOffset_(1.0f),
  65. rightOffset_(1.0f),
  66. topOffset_(1.0f),
  67. bottomOffset_(1.0f),
  68. handleNodeDirty_(true),
  69. rectangleDirty_(true)
  70. {
  71. }
  72. UIRect::~UIRect()
  73. {
  74. }
  75. void UIRect::RegisterObject(Context* context)
  76. {
  77. context->RegisterFactory<UIRect>(UIX_CATEGORY);
  78. ENUM_ACCESSOR_ATTRIBUTE("Layout Mode", GetLayoutMode, SetLayoutMode, UILayoutMode, uiLayoutModes, UILM_FREE, AM_FILE);
  79. ACCESSOR_ATTRIBUTE("Center", GetPosition, SetPosition, Vector2, Vector2::ZERO, AM_FILE);
  80. ACCESSOR_ATTRIBUTE("Size", GetSize, SetSize, Vector2, Vector2(2.0f, 2.0f), AM_FILE);
  81. ENUM_ACCESSOR_ATTRIBUTE("Left Anchor Pivot", GetLeftAnchorPivot, SetLeftAnchorPivot, UIXAnchorPivot, uiXAnchorPivots, AP_XCENTER, AM_FILE);
  82. ENUM_ACCESSOR_ATTRIBUTE("Right Anchor Pivot", GetRightAnchorPivot, SetRightAnchorPivot, UIXAnchorPivot, uiXAnchorPivots, AP_XCENTER, AM_FILE);
  83. ENUM_ACCESSOR_ATTRIBUTE("Top Anchor Pivot", GetTopAnchorPivot, SetTopAnchorPivot, UIYAnchorPivot, uiYAnchorPivots, AP_YCENTER, AM_FILE);
  84. ENUM_ACCESSOR_ATTRIBUTE("Bottom Anchor Pivot", GetBottomAnchorPivot, SetBottomAnchorPivot, UIYAnchorPivot, uiYAnchorPivots, AP_YCENTER, AM_FILE);
  85. ACCESSOR_ATTRIBUTE("Left Offset", GetLeftOffset, SetLeftOffset, float, 1.0f, AM_FILE);
  86. ACCESSOR_ATTRIBUTE("Right Offset", GetRightOffset, SetRightOffset, float, 1.0f, AM_FILE);
  87. ACCESSOR_ATTRIBUTE("Right Offset", GetTopOffset, SetTopOffset, float, 1.0f, AM_FILE);
  88. ACCESSOR_ATTRIBUTE("Bottom Offset", GetBottomOffset, SetBottomOffset, float, 1.0f, AM_FILE);
  89. }
  90. void UIRect::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  91. {
  92. // Draw parent rectangle
  93. if (parent_)
  94. parent_->DrawRect(debug, depthTest);
  95. DrawRect(debug, depthTest);
  96. }
  97. void UIRect::SetPosition(const Vector2& position)
  98. {
  99. if (layoutMode_ == UILM_ANCHOR)
  100. return;
  101. if (position == position_)
  102. return;
  103. position_ = position;
  104. // Update node's position for editor
  105. if (node_)
  106. {
  107. handleNodeDirty_ = false;
  108. node_->SetWorldPosition2D(GetRect().Center());
  109. handleNodeDirty_ = true;
  110. }
  111. MarkRectDirty();
  112. }
  113. void UIRect::SetSize(const Vector2& size)
  114. {
  115. if (layoutMode_ == UILM_ANCHOR)
  116. return;
  117. if (size.x_ < 0.0f || size.y_ < 0.0f || size == size_)
  118. return;
  119. size_ = size;
  120. MarkRectDirty();
  121. }
  122. void UIRect::SetLayoutMode(UILayoutMode layoutMode)
  123. {
  124. if (layoutMode == layoutMode_)
  125. return;
  126. Rect rect = GetRect();
  127. layoutMode_ = layoutMode;
  128. if (layoutMode_ == UILM_FREE)
  129. CalculateFreeModeParameters(rect);
  130. else
  131. CalculateAnchorModeParameters(rect);
  132. }
  133. void UIRect::SetLeftAnchorPivot(UIXAnchorPivot anchorPivot)
  134. {
  135. if (layoutMode_ == UILM_FREE)
  136. return;
  137. if (anchorPivot == leftAnchorPivot_)
  138. return;
  139. Rect rect = GetRect();
  140. leftAnchorPivot_ = anchorPivot;
  141. CalculateAnchorModeParameters(rect);
  142. }
  143. void UIRect::SetRightAnchorPivot(UIXAnchorPivot anchorPivot)
  144. {
  145. if (layoutMode_ == UILM_FREE)
  146. return;
  147. if (anchorPivot == rightAnchorPivot_)
  148. return;
  149. Rect rect = GetRect();
  150. rightAnchorPivot_ = anchorPivot;
  151. CalculateAnchorModeParameters(rect);
  152. }
  153. void UIRect::SetTopAnchorPivot(UIYAnchorPivot anchorPivot)
  154. {
  155. if (anchorPivot == topAnchorPivot_)
  156. return;
  157. Rect rect = GetRect();
  158. topAnchorPivot_ = anchorPivot;
  159. CalculateAnchorModeParameters(rect);
  160. }
  161. void UIRect::SetBottomAnchorPivot(UIYAnchorPivot anchorPivot)
  162. {
  163. if (layoutMode_ == UILM_FREE)
  164. return;
  165. if (anchorPivot == bottomAnchorPivot_)
  166. return;
  167. Rect rect = GetRect();
  168. bottomAnchorPivot_ = anchorPivot;
  169. CalculateAnchorModeParameters(rect);
  170. }
  171. void UIRect::SetLeftOffset(float offset)
  172. {
  173. if (layoutMode_ == UILM_FREE)
  174. return;
  175. if (offset == leftOffset_)
  176. return;
  177. leftOffset_ = offset;
  178. MarkRectDirty();
  179. }
  180. void UIRect::SetRightOffset(float offset)
  181. {
  182. if (layoutMode_ == UILM_FREE)
  183. return;
  184. if (offset == rightOffset_)
  185. return;
  186. rightOffset_ = offset;
  187. MarkRectDirty();
  188. }
  189. void UIRect::SetBottomOffset(float offset)
  190. {
  191. if (layoutMode_ == UILM_FREE)
  192. return;
  193. if (offset == bottomOffset_)
  194. return;
  195. bottomOffset_ = offset;
  196. MarkRectDirty();
  197. }
  198. void UIRect::SetTopOffset(float offset)
  199. {
  200. if (layoutMode_ == UILM_FREE)
  201. return;
  202. if (offset == topOffset_)
  203. return;
  204. topOffset_ = offset;
  205. MarkRectDirty();
  206. }
  207. const Rect& UIRect::GetRect() const
  208. {
  209. if (!rectangleDirty_)
  210. return rectangle_;
  211. if (layoutMode_ == UILM_FREE)
  212. rectangle_ = CalculateRectFreeMode();
  213. else
  214. rectangle_ = CalculateRectAnchorMode();
  215. rectangleDirty_ = false;
  216. return rectangle_;
  217. }
  218. void UIRect::OnNodeSet(Node* node)
  219. {
  220. Component::OnNodeSet(node);
  221. if (node)
  222. {
  223. root_ = GetScene()->GetOrCreateComponent<UIRoot>();
  224. UIRect* rect = node->GetComponent<UIRect>();
  225. if (rect && rect != this)
  226. {
  227. LOGERROR("Can not add more than one UIRect in node");
  228. return;
  229. }
  230. node->AddListener(this);
  231. Node* parent = node->GetParent();
  232. if (parent)
  233. {
  234. parent_ = parent->GetComponent<UIRect>();
  235. MarkRectDirty();
  236. }
  237. }
  238. else
  239. {
  240. parent_ = 0;
  241. MarkRectDirty();
  242. }
  243. }
  244. void UIRect::OnMarkedDirty(Node* node)
  245. {
  246. if (layoutMode_ == UILM_FREE && handleNodeDirty_)
  247. {
  248. position_ -= node_->GetPosition2D();
  249. MarkRectDirty();
  250. }
  251. }
  252. void UIRect::MarkRectDirty()
  253. {
  254. rectangleDirty_ = true;
  255. using namespace UIRectDirtied;
  256. VariantMap& eventData = GetEventDataMap();
  257. eventData[P_UIRECT] = this;
  258. SendEvent(E_UIRECTDIRTIED, eventData);
  259. MarkChildrenRectDirty();
  260. }
  261. void UIRect::MarkChildrenRectDirty()
  262. {
  263. if (!node_)
  264. return;
  265. const Vector<SharedPtr<Node> >& children = node_->GetChildren();
  266. for (unsigned i = 0; i < children.Size(); ++i)
  267. {
  268. UIRect* uiRect = children[i]->GetComponent<UIRect>();
  269. if (uiRect)
  270. uiRect->MarkRectDirty();
  271. }
  272. }
  273. Rect UIRect::CalculateRectFreeMode() const
  274. {
  275. if (!node_)
  276. return Rect::ZERO;
  277. Vector2 center = node_->GetPosition2D();
  278. if (parent_)
  279. center += parent_->GetRect().Center();
  280. Vector2 halfSize = size_ * 0.5f;
  281. return Rect(center - halfSize, center + halfSize);
  282. }
  283. void UIRect::CalculateFreeModeParameters(const Rect& rect)
  284. {
  285. position_ = rect.Center();
  286. if (parent_)
  287. position_ -= parent_->GetRect().Center();
  288. size_ = rect.Size();
  289. }
  290. Rect UIRect::CalculateRectAnchorMode() const
  291. {
  292. UIRect* parent = parent_;
  293. if (!parent)
  294. parent = root_;
  295. float parentXs[] = { parent->GetX(), parent->GetLeft(), parent->GetRight() };
  296. float parentYs[] = { parent->GetY(), parent->GetTop(), parent->GetBottom() };
  297. float left = parentXs[leftAnchorPivot_] + leftOffset_;
  298. float right = parentXs[rightAnchorPivot_] + rightOffset_;
  299. float top = parentYs[topAnchorPivot_] + topOffset_;
  300. float bottom = parentYs[bottomAnchorPivot_] + bottomOffset_;
  301. return Rect(left, bottom, right, top);
  302. }
  303. void UIRect::CalculateAnchorModeParameters(const Rect& rect)
  304. {
  305. UIRect* parent = parent_;
  306. if (!parent)
  307. parent = root_;
  308. float parentXs[] = { parent->GetX(), parent->GetLeft(), parent->GetRight() };
  309. float parentYs[] = { parent->GetY(), parent->GetTop(), parent->GetBottom() };
  310. leftOffset_ = rect.min_.x_ - parentXs[leftAnchorPivot_];
  311. rightOffset_ = rect.max_.x_ - parentXs[rightAnchorPivot_];
  312. topOffset_ = rect.max_.y_ - parentYs[topAnchorPivot_];
  313. bottomOffset_ = rect.min_.y_ - parentYs[bottomAnchorPivot_];
  314. }
  315. void UIRect::DrawRect(DebugRenderer* debug, bool depthTest)
  316. {
  317. if (!debug)
  318. return;
  319. const Rect& drawRect = GetRect();
  320. if (drawRect.Size().x_ < M_EPSILON || drawRect.Size().y_ < M_EPSILON)
  321. return;
  322. const Vector3 leftTop(drawRect.min_.x_, drawRect.max_.y_);
  323. const Vector3 leftBottom(drawRect.min_);
  324. const Vector3 rightTop(drawRect.max_);
  325. const Vector3 rightBottom(drawRect.max_.x_, drawRect.min_.y_);
  326. const Color& color = Color::GREEN;
  327. debug->AddLine(leftTop, rightTop, color, depthTest);
  328. debug->AddLine(rightTop, rightBottom, color, depthTest);
  329. debug->AddLine(rightBottom, leftBottom, color, depthTest);
  330. debug->AddLine(leftBottom, leftTop, color, depthTest);
  331. }
  332. }