StringNodePropertyDisplay.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 <QLineEdit>
  9. #include <QGraphicsProxyWidget>
  10. #include <Components/NodePropertyDisplays/StringNodePropertyDisplay.h>
  11. #include <GraphCanvas/Components/Slots/Data/DataSlotBus.h>
  12. #include <GraphCanvas/Widgets/NodePropertyBus.h>
  13. #include <Widgets/GraphCanvasLabel.h>
  14. namespace GraphCanvas
  15. {
  16. //////////////////////////////
  17. // StringNodePropertyDisplay
  18. //////////////////////////////
  19. StringNodePropertyDisplay::StringNodePropertyDisplay(StringDataInterface* dataInterface)
  20. : NodePropertyDisplay(dataInterface)
  21. , m_dataInterface(dataInterface)
  22. , m_displayLabel(nullptr)
  23. , m_lineEdit(nullptr)
  24. , m_proxyWidget(nullptr)
  25. , m_isNudging(false)
  26. {
  27. m_dataInterface->RegisterDisplay(this);
  28. m_disabledLabel = aznew GraphCanvasLabel();
  29. m_displayLabel = aznew GraphCanvasLabel();
  30. if (m_dataInterface->ResizeToContents())
  31. {
  32. m_displayLabel->SetWrapMode(GraphCanvasLabel::WrapMode::ResizeToContent);
  33. m_displayLabel->SetElide(false);
  34. }
  35. }
  36. StringNodePropertyDisplay::~StringNodePropertyDisplay()
  37. {
  38. CleanupProxyWidget();
  39. delete m_dataInterface;
  40. delete m_displayLabel;
  41. delete m_disabledLabel;
  42. }
  43. void StringNodePropertyDisplay::RefreshStyle()
  44. {
  45. m_disabledLabel->SetSceneStyle(GetSceneId(), NodePropertyDisplay::CreateDisabledLabelStyle("string").c_str());
  46. m_displayLabel->SetSceneStyle(GetSceneId(), NodePropertyDisplay::CreateDisplayLabelStyle("string").c_str());
  47. QSizeF minimumSize = m_displayLabel->minimumSize();
  48. if (m_lineEdit)
  49. {
  50. m_lineEdit->setMinimumSize(aznumeric_cast<int>(minimumSize.width()), aznumeric_cast<int>(minimumSize.height()));
  51. if (m_dataInterface->ResizeToContents())
  52. {
  53. ResizeToContents();
  54. }
  55. else
  56. {
  57. int minWidth = aznumeric_cast<int>(m_displayLabel->size().width());
  58. m_lineEdit->setFixedWidth(AZStd::max(minWidth, 10));
  59. }
  60. }
  61. }
  62. void StringNodePropertyDisplay::UpdateDisplay()
  63. {
  64. AZStd::string value = m_dataInterface->GetString();
  65. m_displayLabel->SetLabel(value);
  66. if (m_lineEdit)
  67. {
  68. QSignalBlocker signalBlocker(m_lineEdit);
  69. m_lineEdit->setText(value.c_str());
  70. m_lineEdit->setCursorPosition(0);
  71. }
  72. ResizeToContents();
  73. if (m_proxyWidget)
  74. {
  75. m_proxyWidget->update();
  76. }
  77. }
  78. QGraphicsLayoutItem* StringNodePropertyDisplay::GetDisabledGraphicsLayoutItem()
  79. {
  80. CleanupProxyWidget();
  81. return m_disabledLabel;
  82. }
  83. QGraphicsLayoutItem* StringNodePropertyDisplay::GetDisplayGraphicsLayoutItem()
  84. {
  85. CleanupProxyWidget();
  86. return m_displayLabel;
  87. }
  88. QGraphicsLayoutItem* StringNodePropertyDisplay::GetEditableGraphicsLayoutItem()
  89. {
  90. SetupProxyWidget();
  91. return m_proxyWidget;
  92. }
  93. void StringNodePropertyDisplay::OnDragDropStateStateChanged(const DragDropState& dragState)
  94. {
  95. Styling::StyleHelper& styleHelper = m_displayLabel->GetStyleHelper();
  96. UpdateStyleForDragDrop(dragState, styleHelper);
  97. m_displayLabel->update();
  98. }
  99. void StringNodePropertyDisplay::OnSystemTick()
  100. {
  101. EditFinished();
  102. AZ::SystemTickBus::Handler::BusDisconnect();
  103. }
  104. void StringNodePropertyDisplay::EditStart()
  105. {
  106. NodePropertiesRequestBus::Event(GetNodeId(), &NodePropertiesRequests::LockEditState, this);
  107. SceneRequestBus::Event(GetSceneId(), &SceneRequests::CancelNudging);
  108. TryAndSelectNode();
  109. }
  110. void StringNodePropertyDisplay::SubmitValue()
  111. {
  112. if (m_lineEdit)
  113. {
  114. AZStd::string value = m_lineEdit->text().toUtf8().data();
  115. m_dataInterface->SetString(value);
  116. m_lineEdit->setCursorPosition(m_lineEdit->text().size());
  117. m_lineEdit->selectAll();
  118. }
  119. else
  120. {
  121. AZ_Error("GraphCanvas", false, "line edit doesn't exist!");
  122. }
  123. }
  124. void StringNodePropertyDisplay::EditFinished()
  125. {
  126. SubmitValue();
  127. UpdateDisplay();
  128. NodePropertiesRequestBus::Event(GetNodeId(), &NodePropertiesRequests::UnlockEditState, this);
  129. if (m_isNudging)
  130. {
  131. m_isNudging = false;
  132. SceneRequestBus::Event(GetSceneId(), &SceneRequests::FinalizeNudging);
  133. }
  134. }
  135. void StringNodePropertyDisplay::OnFocusOut()
  136. {
  137. // String property changes can sometimes change the visual layouts of nodes.
  138. // Need to delay this to the start of the next tick to avoid running into
  139. // issues with Qt processing.
  140. AZ::SystemTickBus::Handler::BusConnect();
  141. }
  142. void StringNodePropertyDisplay::SetupProxyWidget()
  143. {
  144. if (!m_lineEdit)
  145. {
  146. m_proxyWidget = new QGraphicsProxyWidget();
  147. m_lineEdit = aznew Internal::FocusableLineEdit();
  148. m_lineEdit->setProperty("HasNoWindowDecorations", true);
  149. m_lineEdit->setEnabled(true);
  150. QObject::connect(m_lineEdit, &QLineEdit::textChanged, [this]() { ResizeToContents(); });
  151. QObject::connect(m_lineEdit, &Internal::FocusableLineEdit::OnFocusIn, [this]() { EditStart(); });
  152. QObject::connect(m_lineEdit, &Internal::FocusableLineEdit::OnFocusOut, [this]() { EditFinished(); });
  153. QObject::connect(m_lineEdit, &QLineEdit::editingFinished, [this]() { SubmitValue(); });
  154. m_proxyWidget->setWidget(m_lineEdit);
  155. UpdateDisplay();
  156. RefreshStyle();
  157. RegisterShortcutDispatcher(m_lineEdit);
  158. }
  159. }
  160. void StringNodePropertyDisplay::CleanupProxyWidget()
  161. {
  162. if (m_lineEdit)
  163. {
  164. UnregisterShortcutDispatcher(m_lineEdit);
  165. delete m_lineEdit; // NB: this implicitly deletes m_proxy widget
  166. m_lineEdit = nullptr;
  167. m_proxyWidget = nullptr;
  168. }
  169. }
  170. void StringNodePropertyDisplay::ResizeToContents()
  171. {
  172. if (m_lineEdit && m_dataInterface->ResizeToContents())
  173. {
  174. int originalWidth = m_lineEdit->width();
  175. m_displayLabel->SetLabel(m_lineEdit->text().toUtf8().data());
  176. QFontMetrics fm = m_lineEdit->fontMetrics();
  177. int width = aznumeric_cast<int>(fm.boundingRect(m_lineEdit->text()).width());
  178. if (width < m_displayLabel->minimumSize().width())
  179. {
  180. width = aznumeric_cast<int>(m_displayLabel->minimumSize().width()) + 2;
  181. }
  182. m_lineEdit->setFixedWidth(width);
  183. // Don't want to start nudging unless we actually have the focus
  184. if (width != originalWidth && m_lineEdit->hasFocus())
  185. {
  186. NodeUIRequestBus::Event(GetNodeId(), &NodeUIRequests::AdjustSize);
  187. if (!m_isNudging)
  188. {
  189. m_isNudging = true;
  190. AZStd::unordered_set< NodeId > fixedNodes = { GetNodeId() };
  191. SceneRequestBus::Event(GetSceneId(), &SceneRequests::StartNudging, fixedNodes);
  192. }
  193. }
  194. }
  195. }
  196. #include <Source/Components/NodePropertyDisplays/moc_StringNodePropertyDisplay.cpp>
  197. }