BsGUIFloatDistributionField.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2018 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "GUI/BsGUIFloatDistributionField.h"
  4. #include "GUI/BsGUILayout.h"
  5. #include "GUI/BsGUILayoutY.h"
  6. #include "GUI/BsGUILabel.h"
  7. #include "GUI/BsGUIColor.h"
  8. #include "GUI/BsGUIFloatField.h"
  9. #include "GUI/BsGUIVector2Field.h"
  10. #include "GUI/BsGUIVector3Field.h"
  11. #include "GUI/BsGUICurves.h"
  12. #include "GUI/BsGUIButton.h"
  13. #include "GUI/BsGUIContextMenu.h"
  14. #include "GUI/BsGUISpace.h"
  15. using namespace std::placeholders;
  16. namespace bs
  17. {
  18. namespace impl
  19. {
  20. template<class T>
  21. bool isVertical() { return true; }
  22. template<>
  23. bool isVertical<float>() { return false; }
  24. }
  25. template<class T, class SELF>
  26. TGUIDistributionField<T, SELF>::TGUIDistributionField(const PrivatelyConstruct& dummy, const GUIContent& labelContent,
  27. UINT32 labelWidth, const String& style, const GUIDimensions& dimensions, bool withLabel)
  28. : TGUIField(dummy, labelContent, labelWidth, style, dimensions, withLabel)
  29. {
  30. mContextMenu = bs_shared_ptr_new<GUIContextMenu>();
  31. mContextMenu->addMenuItem("Constant", [this]()
  32. {
  33. mValue = TDistribution<T>(mMinConstant);
  34. mPropertyType = PDT_Constant;
  35. rebuild();
  36. }, 50);
  37. mContextMenu->addMenuItem("Range", [this]()
  38. {
  39. mValue = TDistribution<T>(mMinConstant, mMaxConstant);
  40. mPropertyType = PDT_RandomRange;
  41. rebuild();
  42. }, 40);
  43. mContextMenu->addMenuItem("Curve", [this]()
  44. {
  45. TAnimationCurve<T> combinedCurve;
  46. AnimationUtility::combineCurve<T>(mMinCurve, combinedCurve);
  47. mValue = TDistribution<T>(combinedCurve);
  48. mPropertyType = PDT_Curve;
  49. rebuild();
  50. }, 30);
  51. mContextMenu->addMenuItem("Curve range", [this]()
  52. {
  53. TAnimationCurve<T> combinedCurveMin;
  54. AnimationUtility::combineCurve<T>(mMinCurve, combinedCurveMin);
  55. TAnimationCurve<T> combinedCurveMax;
  56. AnimationUtility::combineCurve<T>(mMaxCurve, combinedCurveMax);
  57. mValue = TDistribution<T>(combinedCurveMin, combinedCurveMax);
  58. mPropertyType = PDT_RandomCurveRange;
  59. rebuild();
  60. }, 20);
  61. rebuild();
  62. }
  63. template<class T, class SELF>
  64. void TGUIDistributionField<T, SELF>::setValue(const TDistribution<T>& value)
  65. {
  66. mValue = value;
  67. switch (mPropertyType)
  68. {
  69. default:
  70. case PDT_Constant:
  71. mMinConstant = mValue.getMinConstant();
  72. mMaxConstant = mMinConstant;
  73. for(UINT32 i = 0; i < NumComponents; i++)
  74. {
  75. mMinCurve[i] = TAnimationCurve<float>({
  76. { TCurveProperties<T>::getComponent(mMinConstant, i), 0.0f, 0.0f, 0.0f},
  77. { TCurveProperties<T>::getComponent(mMinConstant, i), 0.0f, 0.0f, 1.0f} });
  78. mMaxCurve[i] = TAnimationCurve<float>({
  79. { TCurveProperties<T>::getComponent(mMinConstant, i), 0.0f, 0.0f, 0.0f},
  80. { TCurveProperties<T>::getComponent(mMinConstant, i), 0.0f, 0.0f, 1.0f} });
  81. }
  82. mMinInput->setValue(mMinConstant);
  83. break;
  84. case PDT_RandomRange:
  85. mMinConstant = mValue.getMinConstant();
  86. mMaxConstant = mValue.getMaxConstant();
  87. for(UINT32 i = 0; i < NumComponents; i++)
  88. {
  89. mMinCurve[i] = TAnimationCurve<float>({
  90. { TCurveProperties<T>::getComponent(mMinConstant, i), 0.0f, 0.0f, 0.0f},
  91. { TCurveProperties<T>::getComponent(mMinConstant, i), 0.0f, 0.0f, 1.0f} });
  92. mMaxCurve[i] = TAnimationCurve<float>({
  93. { TCurveProperties<T>::getComponent(mMaxConstant, i), 0.0f, 0.0f, 0.0f},
  94. { TCurveProperties<T>::getComponent(mMaxConstant, i), 0.0f, 0.0f, 1.0f} });
  95. }
  96. mMinInput->setValue(mMinConstant);
  97. mMaxInput->setValue(mMaxConstant);
  98. break;
  99. case PDT_Curve:
  100. AnimationUtility::splitCurve(mValue.getMinCurve(), mMinCurve);
  101. AnimationUtility::splitCurve(mValue.getMinCurve(), mMaxCurve);
  102. for(UINT32 i = 0; i < NumComponents; i++)
  103. {
  104. TCurveProperties<T>::setComponent(mMinConstant, i, mMinCurve[i].evaluate(0.0f));
  105. TCurveProperties<T>::setComponent(mMaxConstant, i, mMaxCurve[i].evaluate(0.0f));
  106. mCurveDisplay[i]->setCurves({ CurveDrawInfo(mMinCurve[i], Color::BansheeOrange) });
  107. }
  108. break;
  109. case PDT_RandomCurveRange:
  110. AnimationUtility::splitCurve(mValue.getMinCurve(), mMinCurve);
  111. AnimationUtility::splitCurve(mValue.getMaxCurve(), mMaxCurve);
  112. for(UINT32 i = 0; i < NumComponents; i++)
  113. {
  114. TCurveProperties<T>::setComponent(mMinConstant, i, mMinCurve[i].evaluate(0.0f));
  115. TCurveProperties<T>::setComponent(mMaxConstant, i, mMaxCurve[i].evaluate(0.0f));
  116. mCurveDisplay[i]->setCurves(
  117. {
  118. CurveDrawInfo(mMinCurve[i], Color::BansheeOrange),
  119. CurveDrawInfo(mMaxCurve[i], Color::Red)
  120. });
  121. }
  122. break;
  123. }
  124. }
  125. template<class T, class SELF>
  126. bool TGUIDistributionField<T, SELF>::hasInputFocus() const
  127. {
  128. if(mMinInput && mMinInput->hasInputFocus())
  129. return true;
  130. if(mMaxInput && mMaxInput->hasInputFocus())
  131. return true;
  132. return false;
  133. }
  134. template<class T, class SELF>
  135. void TGUIDistributionField<T, SELF>::setTint(const Color& color)
  136. {
  137. mDropDownButton->setTint(color);
  138. if (mLabel)
  139. mLabel->setTint(color);
  140. if(mMinInput)
  141. mMinInput->setTint(color);
  142. if(mMaxInput)
  143. mMaxInput->setTint(color);
  144. for(int i = 0; i < NumComponents; i++)
  145. {
  146. if(mCurveDisplay[i])
  147. mCurveDisplay[i]->setTint(color);
  148. }
  149. }
  150. template<class T, class SELF>
  151. Vector2I TGUIDistributionField<T, SELF>::_getOptimalSize() const
  152. {
  153. Vector2I optimalsize = Vector2I::ZERO;
  154. if(impl::isVertical<T>())
  155. {
  156. if (mMinInput)
  157. {
  158. Vector2I elemOptimal = mMinInput->_calculateLayoutSizeRange().optimal;
  159. optimalsize.x = std::max(optimalsize.x, elemOptimal.x);
  160. optimalsize.y += elemOptimal.y;
  161. }
  162. if (mMaxInput)
  163. {
  164. Vector2I elemOptimal = mMaxInput->_calculateLayoutSizeRange().optimal;
  165. optimalsize.x = std::max(optimalsize.x, elemOptimal.x);
  166. optimalsize.y += elemOptimal.y;
  167. }
  168. for(UINT32 i = 0; i < NumComponents; i++)
  169. {
  170. if (mCurveDisplay[i])
  171. {
  172. Vector2I elemOptimal = mCurveDisplay[i]->_calculateLayoutSizeRange().optimal;
  173. optimalsize.x = std::max(optimalsize.x, elemOptimal.x);
  174. optimalsize.y += elemOptimal.y;
  175. }
  176. }
  177. }
  178. else
  179. {
  180. if (mMinInput)
  181. {
  182. Vector2I elemOptimal = mMinInput->_calculateLayoutSizeRange().optimal;
  183. optimalsize.x += elemOptimal.x;
  184. optimalsize.y = std::max(optimalsize.y, elemOptimal.y);
  185. }
  186. if (mMaxInput)
  187. {
  188. Vector2I elemOptimal = mMaxInput->_calculateLayoutSizeRange().optimal;
  189. optimalsize.x += elemOptimal.x;
  190. optimalsize.y = std::max(optimalsize.y, elemOptimal.y);
  191. }
  192. for(UINT32 i = 0; i < NumComponents; i++)
  193. {
  194. if (mCurveDisplay[i])
  195. {
  196. Vector2I elemOptimal = mCurveDisplay[i]->_calculateLayoutSizeRange().optimal;
  197. optimalsize.x += elemOptimal.x;
  198. optimalsize.y = std::max(optimalsize.y, elemOptimal.y);
  199. }
  200. }
  201. }
  202. Vector2I dropDownSize = mDropDownButton->_calculateLayoutSizeRange().optimal;
  203. optimalsize.x += dropDownSize.x;
  204. optimalsize.y = std::max(optimalsize.y, dropDownSize.y);
  205. if (mLabel)
  206. {
  207. Vector2I elemOptimal = mLabel->_calculateLayoutSizeRange().optimal;
  208. optimalsize.x += elemOptimal.x;
  209. optimalsize.y = std::max(optimalsize.y, elemOptimal.y);
  210. }
  211. return optimalsize;
  212. }
  213. template<class T, class SELF>
  214. void TGUIDistributionField<T, SELF>::styleUpdated()
  215. {
  216. mDropDownButton->setStyle(getSubStyleName(DROP_DOWN_FIELD_STYLE_TYPE));
  217. if (mLabel)
  218. mLabel->setStyle(getSubStyleName(getLabelStyleType()));
  219. if (mMinInput)
  220. mMinInput->setStyle(getSubStyleName(FLOAT_FIELD_STYLE_TYPE));
  221. if (mMaxInput)
  222. mMaxInput->setStyle(getSubStyleName(FLOAT_FIELD_STYLE_TYPE));
  223. for(int i = 0; i < NumComponents; i++)
  224. {
  225. if (mCurveDisplay[i])
  226. mCurveDisplay[i]->setStyle(getSubStyleName(CURVES_FIELD_STYLE_TYPE));
  227. }
  228. }
  229. template<class T, class SELF>
  230. void TGUIDistributionField<T, SELF>::rebuild()
  231. {
  232. if(mLabel)
  233. mLayout->removeElement(mLabel);
  234. mLayout->clear();
  235. mLayout->addElement(mLabel);
  236. GUILayout* valueLayout;
  237. if(impl::isVertical<T>())
  238. valueLayout = mLayout->addNewElement<GUILayoutY>();
  239. else
  240. valueLayout = mLayout;
  241. switch (mValue.getType())
  242. {
  243. default:
  244. case PDT_Constant:
  245. mMinInput = GUIConstantType::create(GUIOptions(), getSubStyleName(FLOAT_FIELD_STYLE_TYPE));
  246. mMaxInput = nullptr;
  247. for(int i = 0; i < NumComponents; i++)
  248. mCurveDisplay[i] = nullptr;
  249. mMinInput->setValue(mMinConstant);
  250. mMinInput->onValueChanged.connect([this](T value)
  251. {
  252. mMinConstant = value;
  253. mValue = TDistribution<T>(value);
  254. onConstantModified();
  255. });
  256. mMinInput->onConfirm.connect([this]() { onConstantConfirmed(); });
  257. valueLayout->addElement(mMinInput);
  258. break;
  259. case PDT_RandomRange:
  260. mMinInput = GUIConstantType::create(HString("Min."), 40, GUIOptions(), getSubStyleName(FLOAT_FIELD_STYLE_TYPE));
  261. mMaxInput = GUIConstantType::create(HString("Max."), 40, GUIOptions(), getSubStyleName(FLOAT_FIELD_STYLE_TYPE));
  262. for(int i = 0; i < NumComponents; i++)
  263. mCurveDisplay[i] = nullptr;
  264. mMinInput->setValue(mMinConstant);
  265. mMinInput->onValueChanged.connect([this](T value)
  266. {
  267. mMinConstant = value;
  268. mValue = TDistribution<T>(value, mMaxConstant);
  269. onConstantModified();
  270. });
  271. mMinInput->onConfirm.connect([this]() { onConstantConfirmed(); });
  272. mMaxInput->setValue(mMaxConstant);
  273. mMaxInput->onValueChanged.connect([this](T value)
  274. {
  275. mMaxConstant = value;
  276. mValue = TDistribution<T>(mMinConstant, value);
  277. onConstantModified();
  278. });
  279. mMaxInput->onConfirm.connect([this]() { onConstantConfirmed(); });
  280. valueLayout->addElement(mMinInput);
  281. valueLayout->addElement(mMaxInput);
  282. break;
  283. case PDT_Curve:
  284. mMinInput = nullptr;
  285. mMaxInput = nullptr;
  286. for(int i = 0; i < NumComponents; i++)
  287. {
  288. mCurveDisplay[i] = GUICurves::create(CurveDrawOption::DrawMarkers, getSubStyleName(CURVES_FIELD_STYLE_TYPE));
  289. mCurveDisplay[i]->setCurves({ CurveDrawInfo(mMinCurve[i], Color::BansheeOrange) });
  290. mCurveDisplay[i]->setPadding(3);
  291. mCurveDisplay[i]->centerAndZoom();
  292. mCurveDisplay[i]->onClicked.connect([this,i]() { onClicked(i); });
  293. valueLayout->addElement(mCurveDisplay[i]);
  294. }
  295. break;
  296. case PDT_RandomCurveRange:
  297. mMinInput = nullptr;
  298. mMaxInput = nullptr;
  299. for(int i = 0; i < NumComponents; i++)
  300. {
  301. mCurveDisplay[i] = GUICurves::create(CurveDrawOption::DrawMarkers | CurveDrawOption::DrawRange,
  302. getSubStyleName(CURVES_FIELD_STYLE_TYPE));
  303. mCurveDisplay[i]->setCurves(
  304. {
  305. CurveDrawInfo(mMinCurve[i], Color::BansheeOrange),
  306. CurveDrawInfo(mMaxCurve[i], Color::Red)
  307. });
  308. mCurveDisplay[i]->setPadding(3);
  309. mCurveDisplay[i]->centerAndZoom();
  310. mCurveDisplay[i]->onClicked.connect([this,i]() { onClicked(i); });
  311. valueLayout->addElement(mCurveDisplay[i]);
  312. }
  313. break;
  314. }
  315. mDropDownButton = GUIButton::create(HString::dummy(), getSubStyleName(DROP_DOWN_FIELD_STYLE_TYPE));
  316. mDropDownButton->onClick.connect([this]()
  317. {
  318. const Rect2I bounds = mDropDownButton->getBounds(mParentWidget->getPanel());
  319. const Vector2I center(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
  320. mContextMenu->open(center, *mParentWidget);
  321. });
  322. mLayout->addNewElement<GUIFixedSpace>(10);
  323. mLayout->addElement(mDropDownButton);
  324. }
  325. template class BS_ED_EXPORT TGUIDistributionField<float, GUIFloatDistributionField>;
  326. template class BS_ED_EXPORT TGUIDistributionField<Vector2, GUIVector2DistributionField>;
  327. template class BS_ED_EXPORT TGUIDistributionField<Vector3, GUIVector3DistributionField>;
  328. const String& GUIFloatDistributionField::getGUITypeName()
  329. {
  330. static String typeName = "GUIFloatDistributionField";
  331. return typeName;
  332. }
  333. const String& GUIVector2DistributionField::getGUITypeName()
  334. {
  335. static String typeName = "GUIVector2DistributionField";
  336. return typeName;
  337. }
  338. const String& GUIVector3DistributionField::getGUITypeName()
  339. {
  340. static String typeName = "GUIVector3DistributionField";
  341. return typeName;
  342. }
  343. }