ViewportWidget.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  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 "EditorCommon.h"
  9. #include "UiCanvasComponent.h"
  10. #include "EditorDefs.h"
  11. #include "Settings.h"
  12. #include <AzCore/std/containers/map.h>
  13. #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
  14. #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
  15. #include <LyShine/Bus/UiEditorCanvasBus.h>
  16. #include "LyShine.h"
  17. #include "UiRenderer.h"
  18. #include "ViewportNudge.h"
  19. #include "ViewportPivot.h"
  20. #include "ViewportSnap.h"
  21. #include "ViewportElement.h"
  22. #include "RulerWidget.h"
  23. #include "CanvasHelpers.h"
  24. #include "AssetDropHelpers.h"
  25. #include "Draw2d.h"
  26. #include "QtHelpers.h"
  27. #include <QtGui/private/qhighdpiscaling_p.h>
  28. #include <QGridLayout>
  29. #include <Atom/RPI.Public/Scene.h>
  30. #include <Atom/RPI.Public/RenderPipeline.h>
  31. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  32. #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_KEY "ViewportWidget::m_drawElementBordersFlags"
  33. #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_DEFAULT ( ViewportWidget::DrawElementBorders_Unselected )
  34. #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_RULERS_KEY "ViewportWidget::m_rulersVisible"
  35. #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_RULERS_DEFAULT ( false )
  36. #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_GUIDES_KEY "ViewportWidget::m_guidesVisible"
  37. #define UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_GUIDES_DEFAULT ( false )
  38. namespace
  39. {
  40. uint32 GetDrawElementBordersFlags()
  41. {
  42. QSettings settings(QSettings::IniFormat, QSettings::UserScope, AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME);
  43. settings.beginGroup(UICANVASEDITOR_NAME_SHORT);
  44. uint32 result = settings.value(UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_KEY,
  45. UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_DEFAULT).toInt();
  46. settings.endGroup();
  47. return result;
  48. }
  49. // Persistence.
  50. void SetDrawElementBordersFlags(uint32 flags)
  51. {
  52. QSettings settings(QSettings::IniFormat, QSettings::UserScope, AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME);
  53. settings.beginGroup(UICANVASEDITOR_NAME_SHORT);
  54. settings.setValue(UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_ELEMENT_BORDERS_KEY,
  55. flags);
  56. settings.endGroup();
  57. }
  58. bool GetPersistentRulerVisibility()
  59. {
  60. QSettings settings(QSettings::IniFormat, QSettings::UserScope, AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME);
  61. settings.beginGroup(UICANVASEDITOR_NAME_SHORT);
  62. bool result = settings.value(UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_RULERS_KEY,
  63. UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_RULERS_DEFAULT).toBool();
  64. settings.endGroup();
  65. return result;
  66. }
  67. // Persistence.
  68. void SetPersistentRulerVisibility(bool rulersVisible)
  69. {
  70. QSettings settings(QSettings::IniFormat, QSettings::UserScope, AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME);
  71. settings.beginGroup(UICANVASEDITOR_NAME_SHORT);
  72. settings.setValue(UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_RULERS_KEY,
  73. rulersVisible);
  74. settings.endGroup();
  75. }
  76. bool GetPersistentGuideVisibility()
  77. {
  78. QSettings settings(QSettings::IniFormat, QSettings::UserScope, AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME);
  79. settings.beginGroup(UICANVASEDITOR_NAME_SHORT);
  80. bool result = settings.value(UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_GUIDES_KEY,
  81. UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_GUIDES_DEFAULT).toBool();
  82. settings.endGroup();
  83. return result;
  84. }
  85. // Persistence.
  86. void SetPersistentGuideVisibility(bool guidesVisible)
  87. {
  88. QSettings settings(QSettings::IniFormat, QSettings::UserScope, AZ_QCOREAPPLICATION_SETTINGS_ORGANIZATION_NAME);
  89. settings.beginGroup(UICANVASEDITOR_NAME_SHORT);
  90. settings.setValue(UICANVASEDITOR_SETTINGS_VIEWPORTWIDGET_DRAW_GUIDES_KEY,
  91. guidesVisible);
  92. settings.endGroup();
  93. }
  94. // Map Qt event key codes to the game input system keyboard codes
  95. const AzFramework::InputChannelId* MapQtKeyToAzInputChannelId(int qtKey)
  96. {
  97. // The UI runtime only cares about a few special keys
  98. switch (qtKey)
  99. {
  100. case Qt::Key_Tab: return &AzFramework::InputDeviceKeyboard::Key::EditTab;
  101. case Qt::Key_Backspace: return &AzFramework::InputDeviceKeyboard::Key::EditBackspace;
  102. case Qt::Key_Return: return &AzFramework::InputDeviceKeyboard::Key::EditEnter;
  103. case Qt::Key_Enter: return &AzFramework::InputDeviceKeyboard::Key::EditEnter;
  104. case Qt::Key_Delete: return &AzFramework::InputDeviceKeyboard::Key::NavigationDelete;
  105. case Qt::Key_Left: return &AzFramework::InputDeviceKeyboard::Key::NavigationArrowLeft;
  106. case Qt::Key_Up: return &AzFramework::InputDeviceKeyboard::Key::NavigationArrowUp;
  107. case Qt::Key_Right: return &AzFramework::InputDeviceKeyboard::Key::NavigationArrowRight;
  108. case Qt::Key_Down: return &AzFramework::InputDeviceKeyboard::Key::NavigationArrowDown;
  109. case Qt::Key_Home: return &AzFramework::InputDeviceKeyboard::Key::NavigationHome;
  110. case Qt::Key_End: return &AzFramework::InputDeviceKeyboard::Key::NavigationEnd;
  111. default: return nullptr;
  112. }
  113. }
  114. // Map Qt event modifiers to the AzFramework input system modifiers
  115. AzFramework::ModifierKeyMask MapQtModifiersToAzInputModifierKeys(Qt::KeyboardModifiers qtMods)
  116. {
  117. int modifiers = static_cast<int>(AzFramework::ModifierKeyMask::None);
  118. if (qtMods & Qt::ShiftModifier)
  119. {
  120. modifiers |= static_cast<int>(AzFramework::ModifierKeyMask::ShiftAny);
  121. }
  122. if (qtMods & Qt::ControlModifier)
  123. {
  124. modifiers |= static_cast<int>(AzFramework::ModifierKeyMask::CtrlAny);
  125. }
  126. if (qtMods & Qt::AltModifier)
  127. {
  128. modifiers |= static_cast<int>(AzFramework::ModifierKeyMask::AltAny);
  129. }
  130. return static_cast<AzFramework::ModifierKeyMask>(modifiers);
  131. }
  132. bool HandleCanvasInputEvent(AZ::EntityId canvasEntityId,
  133. const AzFramework::InputChannel::Snapshot& inputSnapshot,
  134. const AZ::Vector2* viewportPos = nullptr,
  135. const AzFramework::ModifierKeyMask activeModifierKeys = AzFramework::ModifierKeyMask::None)
  136. {
  137. bool handled = false;
  138. UiCanvasBus::EventResult(
  139. handled, canvasEntityId, &UiCanvasBus::Events::HandleInputEvent, inputSnapshot, viewportPos, activeModifierKeys);
  140. // Execute events that have been queued during the input event handler
  141. AZ::Interface<ILyShine>::Get()->ExecuteQueuedEvents();
  142. return handled;
  143. }
  144. bool HandleCanvasTextEvent(AZ::EntityId canvasEntityId, const AZStd::string& textUTF8)
  145. {
  146. bool handled = false;
  147. UiCanvasBus::EventResult(handled, canvasEntityId, &UiCanvasBus::Events::HandleTextEvent, textUTF8);
  148. // Execute events that have been queued during the input event handler
  149. AZ::Interface<ILyShine>::Get()->ExecuteQueuedEvents();
  150. return handled;
  151. }
  152. } // anonymous namespace.
  153. ViewportWidget::ViewportWidget(EditorWindow* parent)
  154. : AtomToolsFramework::RenderViewportWidget(parent)
  155. , m_editorWindow(parent)
  156. , m_viewportInteraction(new ViewportInteraction(m_editorWindow))
  157. , m_viewportAnchor(new ViewportAnchor())
  158. , m_viewportHighlight(new ViewportHighlight())
  159. , m_viewportBackground(new ViewportCanvasBackground())
  160. , m_viewportPivot(new ViewportPivot())
  161. , m_drawElementBordersFlags(GetDrawElementBordersFlags())
  162. , m_refreshRequested(true)
  163. , m_canvasRenderIsEnabled(true)
  164. , m_updateTimer(this)
  165. , m_previewCanvasScale(1.0f)
  166. , m_rulersVisible(GetPersistentRulerVisibility())
  167. , m_guidesVisible(GetPersistentGuideVisibility())
  168. {
  169. setAcceptDrops(true);
  170. InitUiRenderer();
  171. SetupShortcuts();
  172. installEventFilter(m_editorWindow);
  173. // Setup a timer for the maximum refresh rate we want.
  174. // Refresh is actually triggered by interaction events and by the IdleUpdate. This avoids the UI
  175. // Editor slowing down the main editor when no UI interaction is occurring.
  176. QObject::connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(RefreshTick()));
  177. const int kUpdateIntervalInMillseconds = 1000 / 60; // 60 Hz
  178. m_updateTimer.start(kUpdateIntervalInMillseconds);
  179. // listen to the editor window for changes in mode. When in preview mode hide the rulers.
  180. QObject::connect(parent,
  181. &EditorWindow::EditorModeChanged,
  182. [this](UiEditorMode mode)
  183. {
  184. if (mode == UiEditorMode::Preview)
  185. {
  186. m_rulersVisible = false;
  187. }
  188. else
  189. {
  190. m_rulersVisible = GetPersistentRulerVisibility();
  191. }
  192. ApplyRulerVisibility();
  193. });
  194. FontNotificationBus::Handler::BusConnect();
  195. AZ::TickBus::Handler::BusConnect();
  196. AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(GetCurrentContextName());
  197. }
  198. ViewportWidget::~ViewportWidget()
  199. {
  200. AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
  201. FontNotificationBus::Handler::BusDisconnect();
  202. AZ::TickBus::Handler::BusDisconnect();
  203. LyShinePassDataRequestBus::Handler::BusDisconnect();
  204. AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
  205. removeEventFilter(m_editorWindow);
  206. m_uiRenderer.reset();
  207. // Notify LyShine that this is no longer a valid UiRenderer.
  208. // Only one viewport/renderer is currently supported in the UI Editor
  209. CLyShine* lyShine = static_cast<CLyShine*>(AZ::Interface<ILyShine>::Get());
  210. lyShine->SetUiRendererForEditor(nullptr);
  211. }
  212. void ViewportWidget::InitUiRenderer()
  213. {
  214. m_uiRenderer = AZStd::make_shared<UiRenderer>(GetViewportContext());
  215. // Notify LyShine that this is the UiRenderer to be used for rendering
  216. // UI canvases that are loaded in the UI Editor.
  217. // Only one viewport/renderer is currently supported in the UI Editor
  218. CLyShine* lyShine = static_cast<CLyShine*>(AZ::Interface<ILyShine>::Get());
  219. lyShine->SetUiRendererForEditor(m_uiRenderer);
  220. m_draw2d = AZStd::make_shared<CDraw2d>(GetViewportContext());
  221. LyShinePassDataRequestBus::Handler::BusConnect(GetViewportContext()->GetRenderScene()->GetId());
  222. }
  223. ViewportInteraction* ViewportWidget::GetViewportInteraction()
  224. {
  225. return m_viewportInteraction.get();
  226. }
  227. bool ViewportWidget::IsDrawingElementBorders(uint32 flags) const
  228. {
  229. return (m_drawElementBordersFlags & flags) ? true : false;
  230. }
  231. void ViewportWidget::ToggleDrawElementBorders(uint32 flags)
  232. {
  233. m_drawElementBordersFlags ^= flags;
  234. // Persistence.
  235. SetDrawElementBordersFlags(m_drawElementBordersFlags);
  236. }
  237. void ViewportWidget::ActiveCanvasChanged()
  238. {
  239. bool canvasLoaded = m_editorWindow->GetCanvas().IsValid();
  240. if (canvasLoaded)
  241. {
  242. m_viewportInteraction->CenterCanvasInViewport();
  243. }
  244. m_viewportInteraction->InitializeToolbars();
  245. EntityContextChanged();
  246. }
  247. void ViewportWidget::EntityContextChanged()
  248. {
  249. if (m_inObjectPickMode)
  250. {
  251. OnEntityPickModeStopped();
  252. }
  253. // Disconnect from the PickModeRequests bus and reconnect with the new entity context
  254. AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
  255. UiEditorEntityContext* context = m_editorWindow->GetEntityContext();
  256. if (context)
  257. {
  258. AzToolsFramework::EditorPickModeNotificationBus::Handler::BusConnect(context->GetContextId());
  259. }
  260. }
  261. void ViewportWidget::Refresh()
  262. {
  263. m_refreshRequested = true;
  264. }
  265. void ViewportWidget::ClearUntilSafeToRedraw()
  266. {
  267. // set flag so that Update will just clear the screen rather than rendering canvas
  268. m_canvasRenderIsEnabled = false;
  269. // Schedule a timer to set the m_canvasRenderIsEnabled flag
  270. // using a time of zero just waits until there is nothing on the event queue
  271. QTimer::singleShot(0, this, SLOT(EnableCanvasRender()));
  272. }
  273. void ViewportWidget::SetRedrawEnabled(bool enabled)
  274. {
  275. m_canvasRenderIsEnabled = enabled;
  276. }
  277. AZ::Vector2 ViewportWidget::GetRenderViewportSize() const
  278. {
  279. AZ::Vector2 widgetSize(aznumeric_cast<float>(size().width()), aznumeric_cast<float>(size().height()));
  280. return widgetSize * WidgetToViewportFactor();
  281. }
  282. float ViewportWidget::WidgetToViewportFactor() const
  283. {
  284. return GetViewportContext()->GetDpiScalingFactor();
  285. }
  286. void ViewportWidget::PickItem(AZ::EntityId entityId)
  287. {
  288. AzToolsFramework::EditorPickModeRequestBus::Broadcast(
  289. &AzToolsFramework::EditorPickModeRequests::PickModeSelectEntity, entityId);
  290. AzToolsFramework::EditorPickModeRequestBus::Broadcast(
  291. &AzToolsFramework::EditorPickModeRequests::StopEntityPickMode);
  292. }
  293. QWidget* ViewportWidget::CreateViewportWithRulersWidget(QWidget* parent)
  294. {
  295. QWidget* viewportWithRulersWidget = new QWidget(parent);
  296. QGridLayout* viewportWithRulersLayout = new QGridLayout(viewportWithRulersWidget);
  297. viewportWithRulersLayout->setContentsMargins(0, 0, 0, 0);
  298. viewportWithRulersLayout->setSpacing(0);
  299. m_rulerHorizontal = new RulerWidget(RulerWidget::Orientation::Horizontal, viewportWithRulersWidget, m_editorWindow);
  300. m_rulerVertical = new RulerWidget(RulerWidget::Orientation::Vertical, viewportWithRulersWidget, m_editorWindow);
  301. m_rulerCorner = new QWidget();
  302. m_rulerCorner->setBackgroundRole(QPalette::Window);
  303. viewportWithRulersLayout->addWidget(m_rulerCorner,0,0);
  304. viewportWithRulersLayout->addWidget(m_rulerHorizontal,0,1);
  305. viewportWithRulersLayout->addWidget(m_rulerVertical,1,0);
  306. viewportWithRulersLayout->addWidget(this,1,1);
  307. ApplyRulerVisibility();
  308. return viewportWithRulersWidget;
  309. }
  310. void ViewportWidget::ShowRulers(bool show)
  311. {
  312. if (show != m_rulersVisible)
  313. {
  314. m_rulersVisible = show;
  315. ApplyRulerVisibility();
  316. SetPersistentRulerVisibility(m_rulersVisible);
  317. }
  318. }
  319. void ViewportWidget::RefreshRulers()
  320. {
  321. if (m_rulersVisible)
  322. {
  323. m_rulerHorizontal->update();
  324. m_rulerVertical->update();
  325. }
  326. }
  327. void ViewportWidget::SetRulerCursorPositions(const QPoint& globalPos)
  328. {
  329. if (m_rulersVisible)
  330. {
  331. m_rulerHorizontal->SetCursorPos(globalPos);
  332. m_rulerVertical->SetCursorPos(globalPos);
  333. }
  334. }
  335. void ViewportWidget::ShowGuides(bool show)
  336. {
  337. if (show != m_guidesVisible)
  338. {
  339. m_guidesVisible = show;
  340. SetPersistentGuideVisibility(m_guidesVisible);
  341. }
  342. }
  343. void ViewportWidget::contextMenuEvent(QContextMenuEvent* e)
  344. {
  345. if (m_editorWindow->GetCanvas().IsValid())
  346. {
  347. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  348. if (editorMode == UiEditorMode::Edit)
  349. {
  350. // The context menu.
  351. const QPoint pos = e->pos();
  352. HierarchyMenu contextMenu(m_editorWindow->GetHierarchy(),
  353. HierarchyMenu::Show::kCutCopyPaste |
  354. HierarchyMenu::Show::kNew_EmptyElement |
  355. HierarchyMenu::Show::kDeleteElement |
  356. HierarchyMenu::Show::kNewSlice |
  357. HierarchyMenu::Show::kNew_InstantiateSlice |
  358. HierarchyMenu::Show::kPushToSlice |
  359. HierarchyMenu::Show::kEditorOnly |
  360. HierarchyMenu::Show::kFindElements,
  361. true,
  362. &pos);
  363. contextMenu.exec(e->globalPos());
  364. }
  365. }
  366. RenderViewportWidget::contextMenuEvent(e);
  367. }
  368. void ViewportWidget::UserSelectionChanged(HierarchyItemRawPtrList* items)
  369. {
  370. Refresh();
  371. if (!items)
  372. {
  373. m_viewportInteraction->ClearInteraction();
  374. }
  375. }
  376. void ViewportWidget::EnableCanvasRender()
  377. {
  378. m_canvasRenderIsEnabled = true;
  379. // force a redraw
  380. Refresh();
  381. RefreshTick();
  382. }
  383. void ViewportWidget::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  384. {
  385. // Update
  386. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  387. if (editorMode == UiEditorMode::Edit)
  388. {
  389. UpdateEditMode(deltaTime);
  390. }
  391. else // if (editorMode == UiEditorMode::Preview)
  392. {
  393. UpdatePreviewMode(deltaTime);
  394. }
  395. }
  396. ////////////////////////////////////////////////////////////////////////////////////////////////////
  397. int ViewportWidget::GetTickOrder()
  398. {
  399. return AZ::TICK_PRE_RENDER;
  400. }
  401. ////////////////////////////////////////////////////////////////////////////////////////////////////
  402. void ViewportWidget::OnRenderTick()
  403. {
  404. if (!m_uiRenderer->IsReady() || !m_canvasRenderIsEnabled)
  405. {
  406. return;
  407. }
  408. const float dpiScale = WidgetToViewportFactor();
  409. ViewportIcon::SetDpiScaleFactor(dpiScale);
  410. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  411. if (editorMode == UiEditorMode::Edit)
  412. {
  413. RenderEditMode();
  414. }
  415. else // if (editorMode == UiEditorMode::Preview)
  416. {
  417. RenderPreviewMode();
  418. }
  419. }
  420. ////////////////////////////////////////////////////////////////////////////////////////////////////
  421. void ViewportWidget::OnViewportDpiScalingChanged(float dpiScale)
  422. {
  423. ViewportIcon::SetDpiScaleFactor(dpiScale);
  424. }
  425. void ViewportWidget::RefreshTick()
  426. {
  427. #ifdef LYSHINE_EDITOR_TODO // still need this?
  428. if (m_refreshRequested)
  429. {
  430. if (m_canvasRenderIsEnabled)
  431. {
  432. // Redraw the canvas
  433. Update();
  434. }
  435. m_refreshRequested = false;
  436. // in case we were called manually, reset the timer
  437. m_updateTimer.start();
  438. }
  439. #endif
  440. }
  441. void ViewportWidget::mousePressEvent(QMouseEvent* ev)
  442. {
  443. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  444. QPointF scaledPosition = WidgetToViewport(ev->localPos());
  445. QMouseEvent scaledEvent(ev->type(), scaledPosition, ev->button(), ev->buttons(), ev->modifiers());
  446. if (editorMode == UiEditorMode::Edit)
  447. {
  448. // in Edit mode just send input to ViewportInteraction
  449. m_viewportInteraction->MousePressEvent(&scaledEvent);
  450. }
  451. else // if (editorMode == UiEditorMode::Preview)
  452. {
  453. // In Preview mode convert the event into a game input event and send to canvas
  454. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  455. if (canvasEntityId.IsValid())
  456. {
  457. if (ev->button() == Qt::LeftButton)
  458. {
  459. // Send event to this canvas
  460. const AZ::Vector2 viewportPosition(aznumeric_cast<float>(scaledPosition.x()), aznumeric_cast<float>(scaledPosition.y()));
  461. const AzFramework::InputChannel::Snapshot inputSnapshot(AzFramework::InputDeviceMouse::Button::Left,
  462. AzFramework::InputDeviceMouse::Id,
  463. AzFramework::InputChannel::State::Began);
  464. HandleCanvasInputEvent(canvasEntityId, inputSnapshot, &viewportPosition);
  465. }
  466. }
  467. }
  468. // Note: do not propagate this event to parent QViewport, otherwise
  469. // it will manipulate the mouse position in unexpected ways.
  470. Refresh();
  471. }
  472. void ViewportWidget::mouseMoveEvent(QMouseEvent* ev)
  473. {
  474. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  475. QPointF scaledPosition = WidgetToViewport(ev->localPos());
  476. QMouseEvent scaledEvent(ev->type(), scaledPosition, ev->button(), ev->buttons(), ev->modifiers());
  477. if (editorMode == UiEditorMode::Edit)
  478. {
  479. // in Edit mode just send input to ViewportInteraction
  480. m_viewportInteraction->MouseMoveEvent(&scaledEvent,
  481. m_editorWindow->GetHierarchy()->selectedItems());
  482. QPointF screenPosition = WidgetToViewport(ev->screenPos());
  483. SetRulerCursorPositions(screenPosition.toPoint());
  484. }
  485. else // if (editorMode == UiEditorMode::Preview)
  486. {
  487. // In Preview mode convert the event into a game input event and send to canvas
  488. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  489. if (canvasEntityId.IsValid())
  490. {
  491. const AZ::Vector2 viewportPosition(aznumeric_cast<float>(scaledPosition.x()), aznumeric_cast<float>(scaledPosition.y()));
  492. const AzFramework::InputChannelId& channelId = (ev->buttons() & Qt::LeftButton) ?
  493. AzFramework::InputDeviceMouse::Button::Left :
  494. AzFramework::InputDeviceMouse::SystemCursorPosition;
  495. const AzFramework::InputChannel::Snapshot inputSnapshot(channelId,
  496. AzFramework::InputDeviceMouse::Id,
  497. AzFramework::InputChannel::State::Updated);
  498. HandleCanvasInputEvent(canvasEntityId, inputSnapshot, &viewportPosition);
  499. }
  500. }
  501. // Note: do not propagate this event to parent QViewport, otherwise
  502. // it will manipulate the mouse position in unexpected ways.
  503. Refresh();
  504. }
  505. void ViewportWidget::mouseReleaseEvent(QMouseEvent* ev)
  506. {
  507. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  508. QPointF scaledPosition = WidgetToViewport(ev->localPos());
  509. QMouseEvent scaledEvent(ev->type(), scaledPosition, ev->button(), ev->buttons(), ev->modifiers());
  510. if (editorMode == UiEditorMode::Edit)
  511. {
  512. // in Edit mode just send input to ViewportInteraction
  513. m_viewportInteraction->MouseReleaseEvent(&scaledEvent,
  514. m_editorWindow->GetHierarchy()->selectedItems());
  515. }
  516. else // if (editorMode == UiEditorMode::Preview)
  517. {
  518. // In Preview mode convert the event into a game input event and send to canvas
  519. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  520. if (canvasEntityId.IsValid())
  521. {
  522. if (ev->button() == Qt::LeftButton)
  523. {
  524. // Send event to this canvas
  525. const AZ::Vector2 viewportPosition(aznumeric_cast<float>(scaledPosition.x()), aznumeric_cast<float>(scaledPosition.y()));
  526. const AzFramework::InputChannel::Snapshot inputSnapshot(AzFramework::InputDeviceMouse::Button::Left,
  527. AzFramework::InputDeviceMouse::Id,
  528. AzFramework::InputChannel::State::Ended);
  529. HandleCanvasInputEvent(canvasEntityId, inputSnapshot, &viewportPosition);
  530. }
  531. }
  532. }
  533. // Note: do not propagate this event to parent QViewport, otherwise
  534. // it will manipulate the mouse position in unexpected ways.
  535. Refresh();
  536. }
  537. void ViewportWidget::wheelEvent(QWheelEvent* ev)
  538. {
  539. bool handled = false;
  540. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  541. if (editorMode == UiEditorMode::Edit)
  542. {
  543. QWheelEvent scaledEvent(
  544. WidgetToViewport(ev->position()),
  545. ev->globalPosition(),
  546. ev->pixelDelta(),
  547. ev->angleDelta(),
  548. ev->buttons(),
  549. ev->modifiers(),
  550. ev->phase(),
  551. ev->inverted()
  552. );
  553. // in Edit mode just send input to ViewportInteraction
  554. handled = m_viewportInteraction->MouseWheelEvent(&scaledEvent);
  555. }
  556. if (handled)
  557. {
  558. ev->accept();
  559. Refresh();
  560. }
  561. else
  562. {
  563. RenderViewportWidget::wheelEvent(ev);
  564. }
  565. }
  566. bool ViewportWidget::eventFilter([[maybe_unused]] QObject* watched, QEvent* event)
  567. {
  568. if (event->type() == QEvent::ShortcutOverride)
  569. {
  570. // When a shortcut is matched, Qt's event processing sends out a shortcut override event
  571. // to allow other systems to override it. If it's not overridden, then the key events
  572. // get processed as a shortcut, even if the widget that's the target has a keyPress event
  573. // handler. In our case this causes a problem in preview mode for the Key_Delete event.
  574. // So, if we are preview mode avoid treating Key_Delete as a shortcut.
  575. QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
  576. int key = keyEvent->key();
  577. // Override the space bar shortcut so that the key gets handled by the viewport's KeyPress/KeyRelease
  578. // events when the viewport has the focus. The space bar is set up as a shortcut in order to give the
  579. // viewport the focus and activate the space bar when another widget has the focus. Once the shortcut
  580. // is pressed and focus is given to the viewport, the viewport takes over handling the space bar via
  581. // the KeyPress/KeyRelease events.
  582. // Also ignore nudge shortcuts in edit/preview mode so that the KeyPressEvent will be sent.
  583. switch (key)
  584. {
  585. case Qt::Key_Space:
  586. case Qt::Key_Up:
  587. case Qt::Key_Down:
  588. case Qt::Key_Left:
  589. case Qt::Key_Right:
  590. {
  591. event->accept();
  592. return true;
  593. }
  594. default:
  595. {
  596. break;
  597. }
  598. }
  599. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  600. if (editorMode == UiEditorMode::Preview)
  601. {
  602. if (key == Qt::Key_Delete)
  603. {
  604. event->accept();
  605. return true;
  606. }
  607. }
  608. }
  609. return false;
  610. }
  611. bool ViewportWidget::event(QEvent* ev)
  612. {
  613. bool result = RenderViewportWidget::event(ev);
  614. return result;
  615. }
  616. void ViewportWidget::keyPressEvent(QKeyEvent* event)
  617. {
  618. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  619. if (editorMode == UiEditorMode::Edit)
  620. {
  621. // in Edit mode just send input to ViewportInteraction
  622. if (!m_viewportInteraction->KeyPressEvent(event))
  623. {
  624. RenderViewportWidget::keyPressEvent(event);
  625. }
  626. }
  627. else // if (editorMode == UiEditorMode::Preview)
  628. {
  629. // In Preview mode convert the event into a game input event and send to canvas
  630. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  631. if (canvasEntityId.IsValid())
  632. {
  633. // Send event to this canvas
  634. const AzFramework::InputChannelId* inputChannelId = MapQtKeyToAzInputChannelId(event->key());
  635. const AzFramework::ModifierKeyMask activeModifierKeys = MapQtModifiersToAzInputModifierKeys(event->modifiers());
  636. if (inputChannelId)
  637. {
  638. const AzFramework::InputChannel::Snapshot inputSnapshot(*inputChannelId,
  639. AzFramework::InputDeviceKeyboard::Id,
  640. AzFramework::InputChannel::State::Began);
  641. HandleCanvasInputEvent(canvasEntityId, inputSnapshot, nullptr, activeModifierKeys);
  642. }
  643. }
  644. }
  645. }
  646. void ViewportWidget::focusOutEvent([[maybe_unused]] QFocusEvent* ev)
  647. {
  648. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  649. if (editorMode == UiEditorMode::Edit)
  650. {
  651. m_viewportInteraction->ClearInteraction();
  652. }
  653. }
  654. void ViewportWidget::keyReleaseEvent(QKeyEvent* event)
  655. {
  656. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  657. if (editorMode == UiEditorMode::Edit)
  658. {
  659. // in Edit mode just send input to ViewportInteraction
  660. bool handled = m_viewportInteraction->KeyReleaseEvent(event);
  661. if (!handled)
  662. {
  663. RenderViewportWidget::keyReleaseEvent(event);
  664. }
  665. }
  666. else if (editorMode == UiEditorMode::Preview)
  667. {
  668. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  669. if (canvasEntityId.IsValid())
  670. {
  671. bool handled = false;
  672. // Send event to this canvas
  673. const AzFramework::InputChannelId* inputChannelId = MapQtKeyToAzInputChannelId(event->key());
  674. const AzFramework::ModifierKeyMask activeModifierKeys = MapQtModifiersToAzInputModifierKeys(event->modifiers());
  675. if (inputChannelId)
  676. {
  677. const AzFramework::InputChannel::Snapshot inputSnapshot(*inputChannelId,
  678. AzFramework::InputDeviceKeyboard::Id,
  679. AzFramework::InputChannel::State::Ended);
  680. HandleCanvasInputEvent(canvasEntityId, inputSnapshot, nullptr, activeModifierKeys);
  681. }
  682. QString string = event->text();
  683. if (string.length() != 0 && !handled)
  684. {
  685. AZStd::string textUTF8 = string.toUtf8().data();
  686. HandleCanvasTextEvent(canvasEntityId, textUTF8);
  687. }
  688. }
  689. }
  690. else
  691. {
  692. AZ_Assert(0, "Invalid editorMode: %d", editorMode);
  693. }
  694. }
  695. void ViewportWidget::resizeEvent(QResizeEvent* ev)
  696. {
  697. m_editorWindow->GetPreviewToolbar()->ViewportHasResized(ev);
  698. if (m_editorWindow->GetCanvas().IsValid())
  699. {
  700. UiEditorMode editorMode = m_editorWindow->GetEditorMode();
  701. if (editorMode == UiEditorMode::Edit)
  702. {
  703. if (m_viewportInteraction->ShouldScaleToFitOnViewportResize())
  704. {
  705. m_viewportInteraction->CenterCanvasInViewport();
  706. }
  707. }
  708. }
  709. RenderViewportWidget::resizeEvent(ev);
  710. }
  711. bool ViewportWidget::AcceptsMimeData(const QMimeData* mimeData)
  712. {
  713. bool canvasLoaded = m_editorWindow->GetCanvas().IsValid();
  714. if (!canvasLoaded)
  715. {
  716. return false;
  717. }
  718. return AssetDropHelpers::DoesMimeDataContainSliceOrComponentAssets(mimeData);
  719. }
  720. void ViewportWidget::dragEnterEvent(QDragEnterEvent* event)
  721. {
  722. if (AcceptsMimeData(event->mimeData()))
  723. {
  724. event->accept();
  725. }
  726. else
  727. {
  728. event->ignore();
  729. }
  730. }
  731. void ViewportWidget::dropEvent(QDropEvent* event)
  732. {
  733. if (AcceptsMimeData(event->mimeData()))
  734. {
  735. const AZ::EntityId targetEntityId;
  736. const bool onElement = false;
  737. const int childIndex = -1;
  738. const QPoint pos = event->pos();
  739. m_editorWindow->GetHierarchy()->DropMimeDataAssets(event->mimeData(), targetEntityId, onElement, childIndex, &pos);
  740. event->accept();
  741. // Put focus on the viewport widget
  742. activateWindow();
  743. setFocus();
  744. }
  745. }
  746. void ViewportWidget::OnEntityPickModeStarted()
  747. {
  748. m_inObjectPickMode = true;
  749. m_viewportInteraction->StartObjectPickMode();
  750. }
  751. void ViewportWidget::OnEntityPickModeStopped()
  752. {
  753. if (m_inObjectPickMode)
  754. {
  755. m_inObjectPickMode = false;
  756. m_viewportInteraction->StopObjectPickMode();
  757. }
  758. }
  759. void ViewportWidget::OnFontsReloaded()
  760. {
  761. m_fontTextureHasChanged = true;
  762. }
  763. void ViewportWidget::OnFontTextureUpdated([[maybe_unused]] IFFont* font)
  764. {
  765. m_fontTextureHasChanged = true;
  766. }
  767. LyShine::AttachmentImagesAndDependencies ViewportWidget::GetRenderTargets()
  768. {
  769. LyShine::AttachmentImagesAndDependencies canvasTargets;
  770. AZ::EntityId canvasEntityId = m_editorWindow->GetCanvasForCurrentEditorMode();
  771. if (canvasEntityId.IsValid())
  772. {
  773. AZ::Entity* canvasEntity = nullptr;
  774. AZ::ComponentApplicationBus::BroadcastResult(canvasEntity, &AZ::ComponentApplicationBus::Events::FindEntity, canvasEntityId);
  775. AZ_Assert(canvasEntity, "Canvas entity not found by ID");
  776. if (canvasEntity)
  777. {
  778. UiCanvasComponent* canvasComponent = canvasEntity->FindComponent<UiCanvasComponent>();
  779. AZ_Assert(canvasComponent, "Canvas entity has no canvas component");
  780. if (canvasComponent)
  781. {
  782. canvasComponent->GetRenderTargets(canvasTargets);
  783. }
  784. }
  785. }
  786. return canvasTargets;
  787. }
  788. QPointF ViewportWidget::WidgetToViewport(const QPointF & point) const
  789. {
  790. return point * WidgetToViewportFactor();
  791. }
  792. void ViewportWidget::UpdateEditMode(float deltaTime)
  793. {
  794. if (m_fontTextureHasChanged)
  795. {
  796. // A font texture has changed since we last rendered. Force a render graph update for each loaded canvas
  797. m_editorWindow->FontTextureHasChanged();
  798. m_fontTextureHasChanged = false;
  799. }
  800. AZ::EntityId canvasEntityId = m_editorWindow->GetCanvas();
  801. if (!canvasEntityId.IsValid())
  802. {
  803. return; // this can happen if a render happens during a restart
  804. }
  805. AZ::Vector2 canvasSize;
  806. UiCanvasBus::EventResult(canvasSize, canvasEntityId, &UiCanvasBus::Events::GetCanvasSize);
  807. // Set the target size of the canvas
  808. UiCanvasBus::Event(canvasEntityId, &UiCanvasBus::Events::SetTargetCanvasSize, false, canvasSize);
  809. // Update this canvas (must be done after SetTargetCanvasSize)
  810. UiEditorCanvasBus::Event(canvasEntityId, &UiEditorCanvasBus::Events::UpdateCanvasInEditorViewport, deltaTime, false);
  811. }
  812. void ViewportWidget::RenderEditMode()
  813. {
  814. // sort keys for different layers
  815. static const int64_t backgroundKey = -0x1000;
  816. static const int64_t topLayerKey = 0x1000000;
  817. AZ::EntityId canvasEntityId = m_editorWindow->GetCanvas();
  818. if (!canvasEntityId.IsValid())
  819. {
  820. return; // this can happen if a render happens during a restart
  821. }
  822. Draw2dHelper draw2d(m_draw2d.get()); // sets and resets 2D draw mode in constructor/destructor
  823. QTreeWidgetItemRawPtrQList selection = m_editorWindow->GetHierarchy()->selectedItems();
  824. AZ::Vector2 canvasSize;
  825. UiCanvasBus::EventResult(canvasSize, canvasEntityId, &UiCanvasBus::Events::GetCanvasSize);
  826. m_draw2d->SetSortKey(backgroundKey);
  827. // Render a rectangle covering the entire editor viewport area
  828. RenderViewportBackground();
  829. // Render a checkerboard background covering the canvas area which represents transparency
  830. m_viewportBackground->Draw(draw2d,
  831. canvasSize,
  832. m_viewportInteraction->GetCanvasToViewportScale(),
  833. m_viewportInteraction->GetCanvasToViewportTranslation());
  834. // Set the target size of the canvas
  835. UiCanvasBus::Event(canvasEntityId, &UiCanvasBus::Events::SetTargetCanvasSize, false, canvasSize);
  836. // Render this canvas
  837. AZ::Vector2 viewportSize = GetRenderViewportSize();
  838. UiEditorCanvasBus::Event(canvasEntityId, &UiEditorCanvasBus::Events::RenderCanvasInEditorViewport, false, viewportSize);
  839. m_draw2d->SetSortKey(topLayerKey);
  840. // Draw borders around selected and unselected UI elements in the viewport
  841. // depending on the flags in m_drawElementBordersFlags
  842. HierarchyItemRawPtrList selectedItems = SelectionHelpers::GetSelectedHierarchyItems(m_editorWindow->GetHierarchy(), selection);
  843. m_viewportHighlight->Draw(draw2d,
  844. m_editorWindow->GetHierarchy()->invisibleRootItem(),
  845. selectedItems,
  846. m_drawElementBordersFlags);
  847. // Draw primary gizmos and guide lines
  848. m_viewportInteraction->Draw(draw2d, selection);
  849. // Draw any interaction display for the rulers that is in the viewport
  850. m_rulerHorizontal->DrawForViewport(draw2d);
  851. m_rulerVertical->DrawForViewport(draw2d);
  852. // Draw secondary gizmos
  853. if (ViewportInteraction::InteractionMode::ROTATE == m_viewportInteraction->GetMode())
  854. {
  855. // Draw the pivots and degrees only in Rotate mode
  856. LyShine::EntityArray selectedElements = SelectionHelpers::GetTopLevelSelectedElements(m_editorWindow->GetHierarchy(), selection);
  857. for (auto element : selectedElements)
  858. {
  859. bool isHighlighted = (m_viewportInteraction->GetActiveElement() == element) &&
  860. (m_viewportInteraction->GetInteractionType() == ViewportInteraction::InteractionType::PIVOT);
  861. m_viewportPivot->Draw(draw2d, element, isHighlighted);
  862. ViewportHelpers::DrawRotationValue(element, m_viewportInteraction.get(), m_viewportPivot.get(), draw2d);
  863. }
  864. }
  865. else if (ViewportInteraction::InteractionMode::MOVE == m_viewportInteraction->GetMode() ||
  866. ViewportInteraction::InteractionMode::ANCHOR == m_viewportInteraction->GetMode())
  867. {
  868. // Draw the anchors only if we're in Anchor or Move mode
  869. // We draw extra anchor related data when we are in the middle of an interaction
  870. bool leftButtonIsActive = m_viewportInteraction->GetLeftButtonIsActive();
  871. bool spaceBarIsActive = m_viewportInteraction->GetSpaceBarIsActive();
  872. bool isInteracting = leftButtonIsActive && !spaceBarIsActive &&
  873. m_viewportInteraction->GetInteractionType() != ViewportInteraction::InteractionType::NONE &&
  874. m_viewportInteraction->GetInteractionType() != ViewportInteraction::InteractionType::GUIDE;
  875. ViewportHelpers::SelectedAnchors highlightedAnchors = m_viewportInteraction->GetGrabbedAnchors();
  876. // These flags affect what parts of the anchor display is drawn
  877. bool drawUnTransformedRect = false;
  878. bool drawAnchorLines = false;
  879. bool drawLinesToParent = false;
  880. bool anchorInteractionEnabled = m_viewportInteraction->GetMode() == ViewportInteraction::InteractionMode::ANCHOR && selectedItems.size() == 1;
  881. if (isInteracting)
  882. {
  883. if (m_viewportInteraction->GetMode() == ViewportInteraction::InteractionMode::MOVE)
  884. {
  885. // when interacting in move mode (changing offsets) we draw the anchor lines from the anchor to the element
  886. // and also draw a faint untransformed rect around the element
  887. drawUnTransformedRect = true;
  888. drawAnchorLines = true;
  889. }
  890. else
  891. {
  892. // when interacting in anchor mode we draw lines from the anchor to the parent rect
  893. drawLinesToParent = true;
  894. }
  895. }
  896. else
  897. {
  898. // not interacting but could be hovering over anchors
  899. if (highlightedAnchors.Any())
  900. {
  901. // if the anchors are highlighted (whether actually moving or not) we want to draw distance
  902. // lines from the anchor to the edges of it's parent rect. In this case we do NOT want to
  903. // draw the lines from the anchor to this element's rect or pivot
  904. drawLinesToParent = true;
  905. }
  906. }
  907. // for all the top level selected elements, draw the anchors
  908. LyShine::EntityArray selectedElements = SelectionHelpers::GetTopLevelSelectedElements(m_editorWindow->GetHierarchy(), selection);
  909. for (auto element : selectedElements)
  910. {
  911. m_viewportAnchor->Draw(draw2d,
  912. element,
  913. drawUnTransformedRect,
  914. drawAnchorLines,
  915. drawLinesToParent,
  916. anchorInteractionEnabled,
  917. highlightedAnchors);
  918. }
  919. }
  920. }
  921. void ViewportWidget::UpdatePreviewMode(float deltaTime)
  922. {
  923. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  924. if (m_fontTextureHasChanged)
  925. {
  926. // A font texture has changed since we last rendered. Force a render graph update for each loaded canvas
  927. m_editorWindow->FontTextureHasChanged();
  928. m_fontTextureHasChanged = false;
  929. }
  930. if (canvasEntityId.IsValid())
  931. {
  932. // Get the canvas size
  933. AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize();
  934. if (canvasSize.GetX() == 0.0f && canvasSize.GetY() == 0.0f)
  935. {
  936. // special value of (0,0) means use the viewport size
  937. canvasSize = GetRenderViewportSize();;
  938. }
  939. // Set the target size of the canvas
  940. UiCanvasBus::Event(canvasEntityId, &UiCanvasBus::Events::SetTargetCanvasSize, true, canvasSize);
  941. // Update this canvas (must be done after SetTargetCanvasSize)
  942. UiEditorCanvasBus::Event(canvasEntityId, &UiEditorCanvasBus::Events::UpdateCanvasInEditorViewport, deltaTime, true);
  943. // Execute events that have been queued during the canvas update
  944. AZ::Interface<ILyShine>::Get()->ExecuteQueuedEvents();
  945. }
  946. }
  947. void ViewportWidget::RenderPreviewMode()
  948. {
  949. // sort keys for different layers
  950. static const int64_t backgroundKey = -0x1000;
  951. AZ::EntityId canvasEntityId = m_editorWindow->GetPreviewModeCanvas();
  952. // Rather than scaling to exactly fit we try to draw at one of these preset scale factors
  953. // to make it it bit more obvious that the canvas size is changing
  954. float zoomScales[] = {
  955. 1.00f,
  956. 0.75f,
  957. 0.50f,
  958. 0.25f,
  959. 0.10f,
  960. 0.05f
  961. };
  962. if (canvasEntityId.IsValid())
  963. {
  964. AZ::Vector2 viewportSize = GetRenderViewportSize();
  965. // Get the canvas size
  966. AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize();
  967. if (canvasSize.GetX() == 0.0f && canvasSize.GetY() == 0.0f)
  968. {
  969. // special value of (0,0) means use the viewport size
  970. canvasSize = viewportSize;
  971. }
  972. // work out what scale to use for the canvasToViewport matrix
  973. float scale = 1.0f;
  974. if (canvasSize.GetX() > viewportSize.GetX())
  975. {
  976. if (canvasSize.GetX() >= 1.0f) // avoid divide by zero
  977. {
  978. scale = viewportSize.GetX() / canvasSize.GetX();
  979. }
  980. }
  981. if (canvasSize.GetY() > viewportSize.GetY())
  982. {
  983. if (canvasSize.GetY() >= 1.0f) // avoid divide by zero
  984. {
  985. float scaleY = viewportSize.GetY() / canvasSize.GetY();
  986. if (scaleY < scale)
  987. {
  988. scale = scaleY;
  989. }
  990. }
  991. }
  992. // match scale to one of the predefined scales. If the scale is so small
  993. // that it is less than the smallest scale then leave it as it is
  994. for (int i = 0; i < AZ_ARRAY_SIZE(zoomScales); ++i)
  995. {
  996. if (scale >= zoomScales[i])
  997. {
  998. scale = zoomScales[i];
  999. break;
  1000. }
  1001. }
  1002. // Update the toolbar to show the current scale
  1003. if (scale != m_previewCanvasScale)
  1004. {
  1005. m_previewCanvasScale = scale;
  1006. m_editorWindow->GetPreviewToolbar()->UpdatePreviewCanvasScale(scale);
  1007. }
  1008. // Set up the canvasToViewportMatrix
  1009. AZ::Vector3 scale3(scale, scale, 1.0f);
  1010. AZ::Vector3 translation((viewportSize.GetX() - (canvasSize.GetX() * scale)) * 0.5f,
  1011. (viewportSize.GetY() - (canvasSize.GetY() * scale)) * 0.5f, 0.0f);
  1012. AZ::Matrix4x4 canvasToViewportMatrix = AZ::Matrix4x4::CreateScale(scale3);
  1013. canvasToViewportMatrix.SetTranslation(translation);
  1014. UiCanvasBus::Event(canvasEntityId, &UiCanvasBus::Events::SetCanvasToViewportMatrix, canvasToViewportMatrix);
  1015. m_draw2d->SetSortKey(backgroundKey);
  1016. RenderViewportBackground();
  1017. // Render a black rectangle covering the canvas area. This allows the canvas bounds to be visible when the canvas size is
  1018. // not exactly the same as the viewport size
  1019. AZ::Vector2 topLeftInViewportSpace = CanvasHelpers::GetViewportPoint(canvasEntityId, AZ::Vector2(0.0f, 0.0f));
  1020. AZ::Vector2 bottomRightInViewportSpace = CanvasHelpers::GetViewportPoint(canvasEntityId, canvasSize);
  1021. AZ::Vector2 sizeInViewportSpace = bottomRightInViewportSpace - topLeftInViewportSpace;
  1022. Draw2dHelper draw2d(m_draw2d.get());
  1023. auto image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::Black);
  1024. draw2d.DrawImage(image, topLeftInViewportSpace, sizeInViewportSpace);
  1025. // Render this canvas
  1026. // NOTE: the displayBounds param is always false. If we wanted a debug option to display the bounds
  1027. // in preview mode we would need to render the deferred primitives after this call so that they
  1028. // show up in the correct viewport
  1029. UiEditorCanvasBus::Event(canvasEntityId, &UiEditorCanvasBus::Events::RenderCanvasInEditorViewport, true, viewportSize);
  1030. }
  1031. }
  1032. void ViewportWidget::RenderViewportBackground()
  1033. {
  1034. AZ::Vector2 viewportSize = GetRenderViewportSize();
  1035. AZ::Color backgroundColor = ViewportHelpers::backgroundColorDark;
  1036. const AZ::Data::Instance<AZ::RPI::Image>& image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
  1037. Draw2dHelper draw2d(m_draw2d.get());
  1038. draw2d.SetImageColor(backgroundColor.GetAsVector3());
  1039. draw2d.DrawImage(image, AZ::Vector2(0.0f, 0.0f), viewportSize);
  1040. }
  1041. void ViewportWidget::SetupShortcuts()
  1042. {
  1043. // Actions with shortcuts are created instead of direct shortcuts because the shortcut dispatcher only looks for matching actions
  1044. // Give the viewport focus and activate the space bar
  1045. {
  1046. QAction* action = new QAction("Viewport Focus", this);
  1047. action->setShortcut(QKeySequence(Qt::Key_Space));
  1048. QObject::connect(action,
  1049. &QAction::triggered,
  1050. [this]()
  1051. {
  1052. setFocus();
  1053. m_viewportInteraction->ActivateSpaceBar();
  1054. });
  1055. addAction(action);
  1056. }
  1057. }
  1058. void ViewportWidget::ApplyRulerVisibility()
  1059. {
  1060. // Since we are using a grid layout, setting the width of the corner widget (the square at the top left of the grid)
  1061. // determines whether the rulers are zero size or not.
  1062. int rulerBreadth = (m_rulersVisible) ? RulerWidget::GetRulerBreadth() : 0;
  1063. m_rulerCorner->setFixedSize(rulerBreadth, rulerBreadth);
  1064. }
  1065. #include <moc_ViewportWidget.cpp>