BsGUIFloatDistributionField.cpp 11 KB

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