VectorNodePropertyDisplay.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <QGraphicsLinearLayout>
  9. #include <QGraphicsPixmapItem>
  10. #include <QGraphicsProxyWidget>
  11. #include <QGraphicsSceneDragDropEvent>
  12. #include <QGraphicsView>
  13. #include <QHBoxLayout>
  14. #include <QMimeData>
  15. #include <QPixmap>
  16. #include <QToolButton>
  17. #include <AzQtComponents/Components/Widgets/SpinBox.h>
  18. #include <Components/NodePropertyDisplays/VectorNodePropertyDisplay.h>
  19. #include <GraphCanvas/Components/Slots/Data/DataSlotBus.h>
  20. #include <GraphCanvas/Components/VisualBus.h>
  21. #include <GraphCanvas/Widgets/NodePropertyBus.h>
  22. #include <Widgets/GraphCanvasLabel.h>
  23. namespace GraphCanvas
  24. {
  25. //////////////////////
  26. // VectorEventFilter
  27. //////////////////////
  28. VectorEventFilter::VectorEventFilter(VectorNodePropertyDisplay* owner)
  29. : m_owner(owner)
  30. {
  31. }
  32. bool VectorEventFilter::eventFilter(QObject*, QEvent* event)
  33. {
  34. switch (event->type())
  35. {
  36. case QEvent::FocusIn:
  37. m_owner->EditStart();
  38. break;
  39. case QEvent::FocusOut:
  40. m_owner->EditFinished();
  41. break;
  42. default:
  43. break;
  44. }
  45. return false;
  46. }
  47. //////////////////////////
  48. // ReadOnlyVectorControl
  49. //////////////////////////
  50. ReadOnlyVectorControl::ReadOnlyVectorControl(int index, const VectorDataInterface& dataInterface)
  51. : m_index(index)
  52. , m_dataInterface(dataInterface)
  53. {
  54. m_textLabel = aznew GraphCanvasLabel();
  55. m_textLabel->SetRoundedCornersMode(GraphCanvasLabel::RoundedCornersMode::LeftCorners);
  56. m_textLabel->SetLabel(dataInterface.GetLabel(index));
  57. m_valueLabel = aznew GraphCanvasLabel();
  58. m_valueLabel->SetRoundedCornersMode(GraphCanvasLabel::RoundedCornersMode::RightCorners);
  59. m_layout = new QGraphicsLinearLayout(Qt::Orientation::Horizontal);
  60. m_layout->setSpacing(0);
  61. m_layout->setContentsMargins(0, 0, 0, 0);
  62. m_layout->addItem(m_textLabel);
  63. m_layout->addItem(m_valueLabel);
  64. setLayout(m_layout);
  65. setContentsMargins(0, 0, 0, 0);
  66. }
  67. ReadOnlyVectorControl::~ReadOnlyVectorControl()
  68. {
  69. }
  70. void ReadOnlyVectorControl::RefreshStyle(const AZ::EntityId& sceneId)
  71. {
  72. const AZStd::string styleName = m_dataInterface.GetElementStyle(m_index);
  73. m_textLabel->SetSceneStyle(sceneId, NodePropertyDisplay::CreateDisplayLabelStyle(styleName + "_text").c_str());
  74. m_valueLabel->SetSceneStyle(sceneId, NodePropertyDisplay::CreateDisplayLabelStyle(styleName + "_value").c_str());
  75. }
  76. void ReadOnlyVectorControl::UpdateDisplay()
  77. {
  78. m_valueLabel->SetLabel(AZStd::string::format(
  79. "%.*g%s",
  80. m_dataInterface.GetDisplayDecimalPlaces(m_index),
  81. m_dataInterface.GetValue(m_index),
  82. m_dataInterface.GetSuffix(m_index)));
  83. }
  84. int ReadOnlyVectorControl::GetIndex() const
  85. {
  86. return m_index;
  87. }
  88. GraphCanvasLabel* ReadOnlyVectorControl::GetTextLabel()
  89. {
  90. return m_textLabel;
  91. }
  92. const GraphCanvasLabel* ReadOnlyVectorControl::GetTextLabel() const
  93. {
  94. return m_textLabel;
  95. }
  96. GraphCanvasLabel* ReadOnlyVectorControl::GetValueLabel()
  97. {
  98. return m_valueLabel;
  99. }
  100. const GraphCanvasLabel* ReadOnlyVectorControl::GetValueLabel() const
  101. {
  102. return m_valueLabel;
  103. }
  104. IconLayoutItem::IconLayoutItem(QGraphicsItem* parent)
  105. : QGraphicsWidget(parent)
  106. , m_pixmap(new QGraphicsPixmapItem(this))
  107. {
  108. m_pixmap->setVisible(false);
  109. setGraphicsItem(m_pixmap);
  110. setContentsMargins(0, 0, 0, 0);
  111. }
  112. void IconLayoutItem::setIcon(const QPixmap& pixmap)
  113. {
  114. m_pixmap->setVisible(!pixmap.isNull());
  115. m_pixmap->setPixmap(pixmap);
  116. }
  117. IconLayoutItem::~IconLayoutItem()
  118. {
  119. }
  120. //////////////////////////////
  121. // VectorNodePropertyDisplay
  122. //////////////////////////////
  123. VectorNodePropertyDisplay::VectorNodePropertyDisplay(VectorDataInterface* dataInterface)
  124. : NodePropertyDisplay(dataInterface)
  125. , m_dataInterface(dataInterface)
  126. , m_disabledLabel(nullptr)
  127. , m_propertyVectorCtrl(nullptr)
  128. , m_button(nullptr)
  129. , m_proxyWidget(nullptr)
  130. , m_displayWidget(nullptr)
  131. , m_iconDisplay(nullptr)
  132. {
  133. m_displayWidget = new QGraphicsWidget();
  134. m_displayWidget->setContentsMargins(0, 0, 0, 0);
  135. m_displayWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  136. QGraphicsLinearLayout* displayLayout = new QGraphicsLinearLayout(Qt::Orientation::Horizontal);
  137. displayLayout->setSpacing(5);
  138. displayLayout->setContentsMargins(0, 0, 0, 0);
  139. displayLayout->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  140. m_iconDisplay = new IconLayoutItem();
  141. m_iconDisplay->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  142. displayLayout->addItem(m_iconDisplay);
  143. displayLayout->setAlignment(m_iconDisplay, Qt::AlignBottom);
  144. const int elementCount = dataInterface->GetElementCount();
  145. m_vectorDisplays.reserve(elementCount);
  146. for (int i = 0; i < elementCount; ++i)
  147. {
  148. m_vectorDisplays.push_back(aznew ReadOnlyVectorControl(i, (*dataInterface)));
  149. displayLayout->addItem(m_vectorDisplays.back());
  150. }
  151. m_displayWidget->setLayout(displayLayout);
  152. m_disabledLabel = aznew GraphCanvasLabel();
  153. }
  154. VectorNodePropertyDisplay::~VectorNodePropertyDisplay()
  155. {
  156. delete m_dataInterface;
  157. m_dataInterface = nullptr;
  158. delete m_disabledLabel;
  159. delete m_displayWidget;
  160. CleanupProxyWidget();
  161. }
  162. void VectorNodePropertyDisplay::RefreshStyle()
  163. {
  164. const AZ::EntityId sceneId = GetSceneId();
  165. const AZStd::string elementStyle = m_dataInterface->GetStyle();
  166. m_styleHelper.SetScene(sceneId);
  167. m_styleHelper.SetStyle(NodePropertyDisplay::CreateDisplayLabelStyle(elementStyle).c_str());
  168. m_disabledLabel->SetSceneStyle(GetSceneId(), NodePropertyDisplay::CreateDisabledLabelStyle(elementStyle).c_str());
  169. QPalette palette = m_displayWidget->palette();
  170. const QColor backgroundColor = m_styleHelper.GetAttribute(GraphCanvas::Styling::Attribute::BackgroundColor, QColor(0, 0, 0, 0));
  171. palette.setColor(QPalette::ColorRole::Window, backgroundColor);
  172. m_displayWidget->setPalette(palette);
  173. m_displayWidget->setAutoFillBackground(true);
  174. const qreal spacing = static_cast<QGraphicsLinearLayout*>(m_displayWidget->layout())->spacing();
  175. // Start off with - spacing to make the iteration logic cleaner.
  176. qreal elementWidth = -spacing;
  177. qreal elementHeight = m_styleHelper.GetAttribute(GraphCanvas::Styling::Attribute::Height, 0);
  178. const qreal k_sizingConstraint = 200;
  179. for (auto control : m_vectorDisplays)
  180. {
  181. control->RefreshStyle(sceneId);
  182. const QSizeF maximumSize = control->maximumSize();
  183. // Maximum size might be stupidly large, which will cause an error
  184. // from Qt as it tries to overly allocate space for something.
  185. //
  186. // As such we want to put an upper limit on this that is large but not unreasonable.
  187. // Can't really do this at the element level since it messes with the styling
  188. // when I set it. So instead we'll do it here.
  189. elementWidth += AZ::GetMin(k_sizingConstraint, maximumSize.width()) + spacing;
  190. elementHeight = AZ::GetMax(elementHeight, AZ::GetMin(k_sizingConstraint, maximumSize.height()));
  191. }
  192. if (m_iconDisplay && m_iconDisplay->isVisible())
  193. {
  194. elementWidth += m_iconDisplay->preferredWidth();
  195. }
  196. m_displayWidget->setMinimumSize(elementWidth, elementHeight);
  197. m_displayWidget->setPreferredSize(elementWidth, elementHeight);
  198. m_displayWidget->setMaximumSize(elementWidth, elementHeight);
  199. m_displayWidget->adjustSize();
  200. if (m_widgetContainer)
  201. {
  202. const QSizeF minimumSize = m_displayWidget->minimumSize();
  203. const QSizeF maximumSize = m_displayWidget->maximumSize();
  204. m_widgetContainer->setMinimumSize(aznumeric_cast<int>(minimumSize.width()), aznumeric_cast<int>(minimumSize.height()));
  205. m_widgetContainer->setMaximumSize(aznumeric_cast<int>(maximumSize.width()), aznumeric_cast<int>(maximumSize.height()));
  206. m_widgetContainer->adjustSize();
  207. }
  208. }
  209. void VectorNodePropertyDisplay::UpdateDisplay()
  210. {
  211. for (auto control : m_vectorDisplays)
  212. {
  213. control->UpdateDisplay();
  214. }
  215. const auto buttonIcon = m_dataInterface->GetIcon();
  216. if (m_iconDisplay)
  217. {
  218. m_iconDisplay->setIcon(buttonIcon);
  219. m_iconDisplay->setPreferredSize(buttonIcon.size());
  220. m_iconDisplay->setVisible(!buttonIcon.isNull());
  221. }
  222. if (m_button)
  223. {
  224. const QIcon newIcon(buttonIcon);
  225. m_button->setIcon(newIcon);
  226. m_button->setFixedSize(buttonIcon.size());
  227. m_button->setIconSize(buttonIcon.size());
  228. m_button->setVisible(!buttonIcon.isNull());
  229. }
  230. if (m_propertyVectorCtrl)
  231. {
  232. for (int i = 0; i < m_vectorDisplays.size(); ++i)
  233. {
  234. m_propertyVectorCtrl->setValuebyIndex(m_dataInterface->GetValue(i), i);
  235. }
  236. m_proxyWidget->update();
  237. }
  238. }
  239. QGraphicsLayoutItem* VectorNodePropertyDisplay::GetDisabledGraphicsLayoutItem()
  240. {
  241. CleanupProxyWidget();
  242. return m_disabledLabel;
  243. }
  244. QGraphicsLayoutItem* VectorNodePropertyDisplay::GetDisplayGraphicsLayoutItem()
  245. {
  246. CleanupProxyWidget();
  247. return m_displayWidget;
  248. }
  249. QGraphicsLayoutItem* VectorNodePropertyDisplay::GetEditableGraphicsLayoutItem()
  250. {
  251. SetupProxyWidget();
  252. return m_proxyWidget;
  253. }
  254. void VectorNodePropertyDisplay::OnDragDropStateStateChanged(const DragDropState& dragState)
  255. {
  256. for (ReadOnlyVectorControl* vectorControl : m_vectorDisplays)
  257. {
  258. {
  259. Styling::StyleHelper& styleHelper = vectorControl->GetTextLabel()->GetStyleHelper();
  260. UpdateStyleForDragDrop(dragState, styleHelper);
  261. vectorControl->GetTextLabel()->update();
  262. }
  263. {
  264. Styling::StyleHelper& styleHelper = vectorControl->GetValueLabel()->GetStyleHelper();
  265. UpdateStyleForDragDrop(dragState, styleHelper);
  266. vectorControl->GetValueLabel()->update();
  267. }
  268. }
  269. }
  270. void VectorNodePropertyDisplay::EditStart()
  271. {
  272. NodePropertiesRequestBus::Event(GetNodeId(), &NodePropertiesRequests::LockEditState, this);
  273. TryAndSelectNode();
  274. }
  275. void VectorNodePropertyDisplay::SubmitValue()
  276. {
  277. AzQtComponents::VectorElement** elements = m_propertyVectorCtrl->getElements();
  278. const int elementCount = m_propertyVectorCtrl->getSize();
  279. for (int i = 0; i < elementCount; ++i)
  280. {
  281. const AzQtComponents::VectorElement* element = elements[i];
  282. m_dataInterface->SetValue(i, element->getValue());
  283. }
  284. UpdateDisplay();
  285. }
  286. void VectorNodePropertyDisplay::EditFinished()
  287. {
  288. SubmitValue();
  289. NodePropertiesRequestBus::Event(GetNodeId(), &NodePropertiesRequests::UnlockEditState, this);
  290. }
  291. void VectorNodePropertyDisplay::SetupProxyWidget()
  292. {
  293. if (!m_propertyVectorCtrl)
  294. {
  295. m_widgetContainer = new QWidget();
  296. m_widgetContainer->setContentsMargins(0, 0, 0, 0);
  297. m_widgetContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  298. m_widgetContainer->setProperty("HasNoWindowDecorations", true);
  299. QHBoxLayout* layout = new QHBoxLayout(m_widgetContainer);
  300. layout->setAlignment(Qt::AlignLeft);
  301. layout->setMargin(0);
  302. layout->setSpacing(0);
  303. layout->setContentsMargins(0, 0, 0, 0);
  304. m_button = new QToolButton(m_widgetContainer);
  305. m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  306. m_button->setVisible(false);
  307. QObject::connect(m_button, &QToolButton::clicked, [this] () {
  308. NodePropertiesRequestBus::Event(GetNodeId(), &NodePropertiesRequests::LockEditState, this);
  309. m_dataInterface->OnPressButton();
  310. UpdateDisplay();
  311. NodePropertiesRequestBus::Event(GetNodeId(), &NodePropertiesRequests::UnlockEditState, this);
  312. });
  313. layout->addWidget(m_button);
  314. const int elementCount = m_dataInterface->GetElementCount();
  315. m_propertyVectorCtrl = new AzQtComponents::VectorInput(m_widgetContainer, elementCount);
  316. m_propertyVectorCtrl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  317. QObject::connect(m_propertyVectorCtrl, &AzQtComponents::VectorInput::editingFinished, [this]() { SubmitValue(); });
  318. for (int i = 0; i < elementCount; ++i)
  319. {
  320. m_propertyVectorCtrl->setLabel(i, m_dataInterface->GetLabel(i));
  321. m_propertyVectorCtrl->setMinimum(m_dataInterface->GetMinimum(i));
  322. m_propertyVectorCtrl->setMaximum(m_dataInterface->GetMaximum(i));
  323. m_propertyVectorCtrl->setDecimals(m_dataInterface->GetDecimalPlaces(i));
  324. m_propertyVectorCtrl->setDisplayDecimals(m_dataInterface->GetDisplayDecimalPlaces(i));
  325. m_propertyVectorCtrl->setSuffix(m_dataInterface->GetSuffix(i));
  326. }
  327. layout->addWidget(m_propertyVectorCtrl);
  328. m_proxyWidget = new QGraphicsProxyWidget();
  329. m_proxyWidget->setFlag(QGraphicsItem::ItemIsFocusable, true);
  330. m_proxyWidget->setFocusPolicy(Qt::StrongFocus);
  331. m_proxyWidget->setAcceptDrops(false);
  332. m_proxyWidget->setWidget(m_widgetContainer);
  333. UpdateDisplay();
  334. RefreshStyle();
  335. RegisterShortcutDispatcher(m_propertyVectorCtrl);
  336. }
  337. }
  338. void VectorNodePropertyDisplay::CleanupProxyWidget()
  339. {
  340. if (m_propertyVectorCtrl)
  341. {
  342. UnregisterShortcutDispatcher(m_propertyVectorCtrl);
  343. delete m_widgetContainer; // NB: this implicitly deletes m_proxy widget
  344. m_widgetContainer = nullptr;
  345. m_propertyVectorCtrl = nullptr;
  346. m_button = nullptr;
  347. m_proxyWidget = nullptr;
  348. }
  349. }
  350. #include <Source/Components/NodePropertyDisplays/moc_VectorNodePropertyDisplay.cpp>
  351. } // namespace GraphCanvas