LUAEditorView.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279
  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 "LUAEditorView.hxx"
  9. #include <AzToolsFramework/UI/UICore/ProgressShield.hxx>
  10. #include <Source/LUA/moc_LUAEditorView.cpp>
  11. #include "LUAEditorContextMessages.h"
  12. #include "LUAEditorContextInterface.h"
  13. #include "LUAEditorViewMessages.h"
  14. #include "LUAEditorMainWindow.hxx"
  15. #include "LUABreakpointTrackerMessages.h"
  16. #include "LUAEditorSyntaxHighlighter.hxx"
  17. #include "LUAEditorStyleMessages.h"
  18. #include <Source/LUA/ui_LUAEditorView.h>
  19. #include <AzToolsFramework/SourceControl/SourceControlAPI.h>
  20. #include <QFileInfo>
  21. #include <QTimer>
  22. #include <QMessageBox>
  23. #include <QMimeData>
  24. namespace LUAEditor
  25. {
  26. struct FindOperationImpl
  27. {
  28. AZ_CLASS_ALLOCATOR(FindOperationImpl, AZ::SystemAllocator);
  29. QTextCursor m_cursor;
  30. QString m_searchString;
  31. bool m_isRegularExpression;
  32. bool m_isCaseSensitiveSearch;
  33. bool m_wholeWord;
  34. bool m_wrap;
  35. bool m_searchDown;
  36. };
  37. LUAViewWidget::FindOperation::FindOperation()
  38. : m_impl(nullptr)
  39. {
  40. }
  41. LUAViewWidget::FindOperation::FindOperation(FindOperation&& other)
  42. {
  43. m_impl = nullptr;
  44. *this = AZStd::move(other);
  45. }
  46. LUAViewWidget::FindOperation::FindOperation(FindOperationImpl* impl)
  47. {
  48. m_impl = impl;
  49. }
  50. LUAViewWidget::FindOperation::~FindOperation()
  51. {
  52. delete m_impl;
  53. }
  54. LUAViewWidget::FindOperation& LUAViewWidget::FindOperation::operator=(FindOperation&& other)
  55. {
  56. if (m_impl)
  57. {
  58. delete m_impl;
  59. }
  60. m_impl = other.m_impl;
  61. other.m_impl = nullptr;
  62. return *this;
  63. }
  64. LUAViewWidget::FindOperation::operator bool()
  65. {
  66. return m_impl && !m_impl->m_cursor.isNull();
  67. }
  68. //////////////////////////////////////////////////////////////////////////
  69. //LUADockWidget
  70. LUADockWidget::LUADockWidget(QWidget* parent, Qt::WindowFlags flags)
  71. : QDockWidget("LUADockWidget", parent, flags)
  72. {
  73. connect(this, &LUADockWidget::dockLocationChanged, this, &LUADockWidget::OnDockLocationChanged);
  74. }
  75. void LUADockWidget::closeEvent(QCloseEvent* event)
  76. {
  77. if (QMainWindow* pQMainWindow = qobject_cast<QMainWindow*>(parentWidget()))
  78. {
  79. if (LUAEditorMainWindow* pLUAEditorMainWindow = qobject_cast<LUAEditorMainWindow*>(pQMainWindow->parentWidget()))
  80. {
  81. pLUAEditorMainWindow->RequestCloseDocument(m_assetId);
  82. event->accept();
  83. }
  84. }
  85. }
  86. void LUADockWidget::OnDockLocationChanged(Qt::DockWidgetArea newArea)
  87. {
  88. (void)newArea;
  89. if (QMainWindow* pQMainWindow = qobject_cast<QMainWindow*>(parentWidget()))
  90. {
  91. if (LUAEditorMainWindow* pLUAEditorMainWindow = qobject_cast<LUAEditorMainWindow*>(pQMainWindow->parentWidget()))
  92. {
  93. pLUAEditorMainWindow->OnDockWidgetLocationChanged(m_assetId);
  94. }
  95. }
  96. }
  97. //////////////////////////////////////////////////////////////////////////
  98. //LUAViewWidget
  99. LUAViewWidget::LUAViewWidget(QWidget* pParent /*=NULL*/)
  100. : QWidget(pParent)
  101. , m_gui(azcreate(Ui::LUAEditorView, ()))
  102. , m_pLUADockWidget(NULL)
  103. , m_pLoadingProgressShield(NULL)
  104. , m_pSavingProgressShield(NULL)
  105. , m_pRequestingEditProgressShield(NULL)
  106. , m_PullRequestQueued(false)
  107. , m_AutoCompletionEnabled(true)
  108. {
  109. m_gui->setupUi(this);
  110. setAcceptDrops(true);
  111. m_gui->m_luaTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  112. m_gui->m_breakpoints->SetTextEdit(m_gui->m_luaTextEdit);
  113. m_gui->m_folding->SetTextEdit(m_gui->m_luaTextEdit);
  114. m_Highlighter = aznew LUASyntaxHighlighter(m_gui->m_luaTextEdit->document());
  115. QTextDocument* doc = m_gui->m_luaTextEdit->document();
  116. QTextOption option = doc->defaultTextOption();
  117. option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
  118. doc->setDefaultTextOption(option);
  119. UpdateFont();
  120. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::modificationChanged, this, &LUAViewWidget::modificationChanged);
  121. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::cursorPositionChanged, this, &LUAViewWidget::UpdateBraceHighlight);
  122. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::Scrolled, m_gui->m_folding, static_cast<void(FoldingWidget::*)()>(&FoldingWidget::update));
  123. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::blockCountChanged, m_gui->m_breakpoints, &LUAEditorBreakpointWidget::OnBlockCountChange);
  124. connect(m_gui->m_luaTextEdit->document(), &QTextDocument::contentsChange, m_gui->m_breakpoints, &LUAEditorBreakpointWidget::OnCharsRemoved);
  125. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::FocusChanged, this, &LUAViewWidget::OnPlainTextFocusChanged);
  126. connect(m_gui->m_luaTextEdit->document(), &QTextDocument::contentsChange, m_gui->m_folding, &FoldingWidget::OnContentChanged);
  127. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::ZoomIn, this, &LUAViewWidget::OnZoomIn);
  128. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::ZoomOut, this, &LUAViewWidget::OnZoomOut);
  129. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::cursorPositionChanged, m_gui->m_folding, static_cast<void(FoldingWidget::*)()>(&FoldingWidget::update));
  130. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::cursorPositionChanged, m_gui->m_breakpoints, static_cast<void(LUAEditorBreakpointWidget::*)()>(&LUAEditorBreakpointWidget::update));
  131. connect(m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::Scrolled, m_gui->m_breakpoints, static_cast<void(LUAEditorBreakpointWidget::*)()>(&LUAEditorBreakpointWidget::update));
  132. connect(this, &LUAViewWidget::RegainFocus, this, &LUAViewWidget::RegainFocusFinal, Qt::QueuedConnection);
  133. connect(m_gui->m_folding, &FoldingWidget::TextBlockFoldingChanged, m_gui->m_breakpoints, static_cast<void(LUAEditorBreakpointWidget::*)()>(&LUAEditorBreakpointWidget::update));
  134. connect(m_gui->m_folding, &FoldingWidget::TextBlockFoldingChanged, m_gui->m_luaTextEdit, static_cast<void(LUAEditorPlainTextEdit::*)()>(&LUAEditorPlainTextEdit::update));
  135. connect(m_Highlighter, &LUASyntaxHighlighter::LUANamesInScopeChanged, m_gui->m_luaTextEdit, &LUAEditorPlainTextEdit::OnScopeNamesUpdated);
  136. connect(m_gui->m_breakpoints, &LUAEditorBreakpointWidget::toggleBreakpoint, this, &LUAViewWidget::BreakpointToggle);
  137. connect(m_gui->m_breakpoints, &LUAEditorBreakpointWidget::breakpointLineMove, this, &LUAViewWidget::OnBreakpointLineMoved);
  138. connect(m_gui->m_breakpoints, &LUAEditorBreakpointWidget::breakpointDelete, this, &LUAViewWidget::OnBreakpointLineDeleted);
  139. CreateStyleSheet();
  140. this->setMinimumSize(300, 300);
  141. SetReadonly(true);
  142. m_gui->m_luaTextEdit->SetGetLuaName([&](const QTextCursor& cursor) {return m_Highlighter->GetLUAName(cursor); });
  143. LUABreakpointTrackerMessages::Handler::BusConnect();
  144. }
  145. void LUAViewWidget::Initialize(const DocumentInfo& initialInfo)
  146. {
  147. m_Info = initialInfo;
  148. if (!m_pLoadingProgressShield)
  149. {
  150. m_pLoadingProgressShield = aznew AzToolsFramework::ProgressShield(this);
  151. }
  152. m_pLoadingProgressShield->setProgress(0, 0, AZStd::string::format("Loading '%s'...", initialInfo.m_displayName.c_str()).c_str());
  153. m_pLoadingProgressShield->show();
  154. }
  155. void LUAViewWidget::CreateStyleSheet()
  156. {
  157. auto colors = AZ::UserSettings::CreateFind<SyntaxStyleSettings>(AZ_CRC("LUA Editor Text Settings", 0xb6e15565), AZ::UserSettings::CT_GLOBAL);
  158. auto styleSheet = QString(R"(QPlainTextEdit:focus
  159. {
  160. background-color: %1;
  161. selection-background-color: %6;
  162. selection-color: %5;
  163. }
  164. QPlainTextEdit:!focus
  165. {
  166. background-color: %2;
  167. selection-color: %5;
  168. selection-background-color: %6;
  169. }
  170. QPlainTextEdit[readOnly="true"]:focus
  171. {
  172. background-color: %3;
  173. selection-color: %5;
  174. selection-background-color: %6;
  175. }
  176. QPlainTextEdit[readOnly="true"]:!focus
  177. {
  178. background-color: %4;
  179. selection-color: %5;
  180. selection-background-color: %6;
  181. }
  182. )");
  183. styleSheet = styleSheet.arg(colors->GetTextFocusedBackgroundColor().name())
  184. .arg(colors->GetTextUnfocusedBackgroundColor().name())
  185. .arg(colors->GetTextReadOnlyFocusedBackgroundColor().name())
  186. .arg(colors->GetTextReadOnlyUnfocusedBackgroundColor().name())
  187. .arg(colors->GetTextSelectedColor().name())
  188. .arg(colors->GetTextSelectedBackgroundColor().name());
  189. m_gui->m_luaTextEdit->setStyleSheet(styleSheet);
  190. styleSheet = QString(R"(LUAEditor--FoldingWidget:enabled {
  191. background-color: %1;
  192. }
  193. LUAEditor--FoldingWidget:!enabled {
  194. background-color: %2;
  195. }
  196. )");
  197. styleSheet = styleSheet.arg(colors->GetFoldingFocusedBackgroundColor().name())
  198. .arg(colors->GetFoldingUnfocusedBackgroundColor().name());
  199. m_gui->m_folding->setStyleSheet(styleSheet);
  200. }
  201. LUAViewWidget::~LUAViewWidget()
  202. {
  203. m_gui->m_breakpoints->PreDestruction();
  204. delete m_Highlighter;
  205. azdestroy(m_gui);
  206. LUABreakpointTrackerMessages::Handler::BusDisconnect();
  207. }
  208. template<typename Callable>
  209. void LUAViewWidget::UpdateCursor(Callable callable)
  210. {
  211. auto cursor = m_gui->m_luaTextEdit->textCursor();
  212. callable(cursor);
  213. m_gui->m_luaTextEdit->setTextCursor(cursor);
  214. }
  215. void LUAViewWidget::OnDocumentInfoUpdated(const DocumentInfo& newInfo)
  216. {
  217. AZ_Assert(newInfo.m_assetId == m_Info.m_assetId, "Asset ID mismatch.");
  218. //this is the the initial unmodified state
  219. bool modifiedValue = newInfo.m_bIsModified;
  220. //data loading///////////////////////////////////////////////
  221. if ((newInfo.m_bDataIsLoaded) && (!m_Info.m_bDataIsLoaded))
  222. {
  223. // load the data now that its ready!
  224. if (!newInfo.m_bUntitledDocument)
  225. {
  226. const char* buffer = NULL;
  227. AZStd::size_t actualSize = 0;
  228. Context_DocumentManagement::Bus::Broadcast(
  229. &Context_DocumentManagement::Bus::Events::GetDocumentData, newInfo.m_assetId, &buffer, actualSize);
  230. m_gui->m_luaTextEdit->setPlainText(buffer);
  231. LUAViewMessages::Bus::Broadcast(&LUAViewMessages::Bus::Events::OnDataLoadedAndSet, newInfo, this);
  232. }
  233. //remove the loading shield
  234. if (m_pLoadingProgressShield)
  235. {
  236. delete m_pLoadingProgressShield;
  237. m_pLoadingProgressShield = NULL;
  238. }
  239. // scan the breakpoint store from our context and pre-set the markers to get in sync
  240. const LUAEditor::BreakpointMap* myData = NULL;
  241. LUAEditor::LUABreakpointRequestMessages::Bus::BroadcastResult(
  242. myData, &LUAEditor::LUABreakpointRequestMessages::Bus::Events::RequestBreakpoints);
  243. AZ_Assert(myData, "LUAEditor::LUABreakpointRequestMessages::Bus, RequestBreakpoints failed to return any data.");
  244. BreakpointsUpdate(*myData);
  245. UpdateCurrentEditingLine(newInfo.m_PresetLineAtOpen);
  246. //AZ_TracePrintf("LUA", "Document Loaded Regain\n");
  247. emit RegainFocus();
  248. }
  249. if ((!newInfo.m_bDataIsLoaded) && (m_Info.m_bDataIsLoaded))
  250. {
  251. // wait for new data.
  252. if (!m_pLoadingProgressShield)
  253. {
  254. m_pLoadingProgressShield = aznew AzToolsFramework::ProgressShield(this);
  255. }
  256. m_pLoadingProgressShield->setProgress(0, 0, AZStd::string::format("Loading... ").c_str());
  257. m_pLoadingProgressShield->show();
  258. }
  259. //data saving/////////////////////////////
  260. if ((!newInfo.m_bIsBeingSaved) && (m_Info.m_bIsBeingSaved))
  261. {
  262. //remove the saving shield!
  263. if (m_pSavingProgressShield)
  264. {
  265. delete m_pSavingProgressShield;
  266. m_pSavingProgressShield = NULL;
  267. }
  268. }
  269. if ((newInfo.m_bDataIsWritten) && (!m_Info.m_bDataIsWritten))
  270. {
  271. m_gui->m_luaTextEdit->document()->setModified(false);
  272. }
  273. if ((newInfo.m_bIsBeingSaved) && (!m_Info.m_bIsBeingSaved))
  274. {
  275. // show the saving shield!
  276. if (!m_pSavingProgressShield)
  277. {
  278. m_pSavingProgressShield = aznew AzToolsFramework::ProgressShield(this);
  279. }
  280. m_pSavingProgressShield->setProgress(0, 0, AZStd::string::format("Saving... ").c_str());
  281. m_pSavingProgressShield->show();
  282. }
  283. //requesting edit (checking out)/////////////////////////////
  284. if ((!newInfo.m_bSourceControl_BusyRequestingEdit) && (m_Info.m_bSourceControl_BusyRequestingEdit))
  285. {
  286. //remove the checking out shield
  287. if (m_pRequestingEditProgressShield)
  288. {
  289. delete m_pRequestingEditProgressShield;
  290. m_pRequestingEditProgressShield = NULL;
  291. }
  292. }
  293. if ((newInfo.m_bSourceControl_BusyRequestingEdit) && (!m_Info.m_bSourceControl_BusyRequestingEdit))
  294. {
  295. // wait for edit request.
  296. if (!m_pRequestingEditProgressShield)
  297. {
  298. m_pRequestingEditProgressShield = aznew AzToolsFramework::ProgressShield(this);
  299. }
  300. m_pRequestingEditProgressShield->setProgress(0, 0, AZStd::string::format("Checking Out... ").c_str());
  301. m_pRequestingEditProgressShield->show();
  302. }
  303. //update view properties//////////////////////////////////////////////
  304. if ((newInfo.m_bSourceControl_CanWrite) && (newInfo.m_bDataIsLoaded))
  305. {
  306. if (m_gui->m_luaTextEdit->isReadOnly())
  307. {
  308. SetReadonly(false);
  309. update();
  310. }
  311. }
  312. else
  313. {
  314. // in all other cases we are waiting for more.
  315. if (!m_gui->m_luaTextEdit->isReadOnly())
  316. {
  317. SetReadonly(true);
  318. update();
  319. }
  320. }
  321. QString statusString(tr("P4:"));
  322. {
  323. // this flag goes true when a file's read-only status should be verified
  324. bool checkWriteIsWrong = false;
  325. if (newInfo.m_sourceControlInfo.m_status == AzToolsFramework::SCS_ProviderIsDown)
  326. {
  327. statusString += tr(" Unknown: P4 Down");
  328. }
  329. else if (newInfo.m_sourceControlInfo.m_status == AzToolsFramework::SCS_ProviderError)
  330. {
  331. statusString += tr(" Unknown: P4 Error");
  332. }
  333. else if (newInfo.m_sourceControlInfo.m_status == AzToolsFramework::SCS_CertificateInvalid)
  334. {
  335. statusString += tr(" Unknown: P4 SSL Certificate Invalid");
  336. }
  337. else if (newInfo.m_sourceControlInfo.m_flags & AzToolsFramework::SCF_OpenByUser)
  338. {
  339. if (newInfo.m_sourceControlInfo.m_flags & AzToolsFramework::SCF_PendingAdd)
  340. {
  341. statusString += tr(" Adding");
  342. }
  343. else if (newInfo.m_sourceControlInfo.m_flags & AzToolsFramework::SCF_PendingDelete)
  344. {
  345. statusString += tr(" Deleting");
  346. }
  347. else
  348. {
  349. QString msg = tr(" Checked Out");
  350. msg += QString(tr(" By You"));
  351. // m_StatusUser only has contents if someone other than you has this file checked out, too
  352. if (newInfo.m_sourceControlInfo.m_StatusUser.length())
  353. {
  354. msg += QString(tr(" and Others"));
  355. }
  356. statusString += msg;
  357. }
  358. }
  359. else if (newInfo.m_sourceControlInfo.m_flags & AzToolsFramework::SCF_OtherOpen)
  360. {
  361. QString msg = tr(" Checked Out");
  362. msg += QString(tr(" By ")) + newInfo.m_sourceControlInfo.m_StatusUser.c_str();
  363. statusString += msg;
  364. checkWriteIsWrong = true;
  365. }
  366. else if (!newInfo.m_sourceControlInfo.IsManaged())
  367. {
  368. statusString += tr(" Not Tracked");
  369. }
  370. else
  371. {
  372. statusString += tr(" Not Checked Out");
  373. checkWriteIsWrong = true;
  374. }
  375. if (checkWriteIsWrong)
  376. {
  377. QFileInfo fi(newInfo.m_sourceControlInfo.m_filePath.c_str());
  378. if (fi.exists() && fi.isWritable())
  379. {
  380. statusString += tr(" But Writable?");
  381. }
  382. }
  383. if ((!newInfo.m_bSourceControl_BusyRequestingEdit) && (!m_Info.m_bSourceControl_BusyGettingStats))
  384. {
  385. //remove the checking out shield
  386. if (m_pRequestingEditProgressShield)
  387. {
  388. delete m_pRequestingEditProgressShield;
  389. m_pRequestingEditProgressShield = NULL;
  390. }
  391. }
  392. }
  393. emit sourceControlStatusUpdated(statusString);
  394. //save new state
  395. m_Info = newInfo;
  396. m_gui->m_luaTextEdit->document()->setModified(modifiedValue);
  397. UpdateModifyFlag();
  398. }
  399. void LUAViewWidget::OnPlainTextFocusChanged(bool hasFocus)
  400. {
  401. if (!m_gui->m_folding || !m_gui->m_breakpoints)
  402. {
  403. return;
  404. }
  405. if (hasFocus)
  406. {
  407. m_gui->m_breakpoints->setEnabled(true);
  408. m_gui->m_folding->setEnabled(true);
  409. LUAEditorMainWindowMessages::Bus::Broadcast(&LUAEditorMainWindowMessages::Bus::Events::OnFocusInEvent, m_Info.m_assetId);
  410. }
  411. else
  412. {
  413. m_gui->m_breakpoints->setEnabled(false);
  414. m_gui->m_folding->setEnabled(false);
  415. LUAEditorMainWindowMessages::Bus::Broadcast(&LUAEditorMainWindowMessages::Bus::Events::OnFocusOutEvent, m_Info.m_assetId);
  416. }
  417. }
  418. void LUAViewWidget::RegainFocusFinal()
  419. {
  420. //AZ_TracePrintf("LUA", "RegainFocusFinal\n");
  421. show();
  422. activateWindow();
  423. setFocus(Qt::MouseFocusReason);
  424. }
  425. void LUAViewWidget::OnVisibilityChanged(bool vc)
  426. {
  427. if (vc)
  428. {
  429. if (!m_pLUADockWidget->isFloating())
  430. {
  431. RegainFocusFinal();
  432. }
  433. }
  434. }
  435. void LUAViewWidget::OnBreakpointLineMoved(int fromLineNumber, int toLineNumber)
  436. {
  437. auto breakpoint = m_Breakpoints.find(fromLineNumber);
  438. if (breakpoint != m_Breakpoints.end())
  439. {
  440. Context_DebuggerManagement::Bus::Broadcast(
  441. &Context_DebuggerManagement::Bus::Events::MoveBreakpoint, breakpoint->second.m_editorId, toLineNumber);
  442. }
  443. }
  444. void LUAViewWidget::OnBreakpointLineDeleted(int removedLineNumber)
  445. {
  446. auto breakpoint = m_Breakpoints.find(removedLineNumber);
  447. if (breakpoint != m_Breakpoints.end())
  448. {
  449. Context_DebuggerManagement::Bus::Broadcast(
  450. &Context_DebuggerManagement::Bus::Events::DeleteBreakpoint, breakpoint->second.m_editorId);
  451. }
  452. }
  453. void LUAViewWidget::modificationChanged(bool m)
  454. {
  455. Context_DocumentManagement::Bus::Broadcast(&Context_DocumentManagement::Bus::Events::NotifyDocumentModified, m_Info.m_assetId, m);
  456. UpdateModifyFlag();
  457. }
  458. void LUAViewWidget::UpdateModifyFlag() {
  459. QString displayName = QString::fromUtf8(m_Info.m_displayName.c_str());
  460. if (m_gui->m_luaTextEdit->document()->isModified())
  461. {
  462. displayName += "*";
  463. }
  464. this->luaDockWidget()->setWindowTitle(displayName);
  465. }
  466. void LUAViewWidget::UpdateCurrentExecutingLine(int lineNumber)
  467. {
  468. m_gui->m_breakpoints->SetCurrentlyExecutingLine(lineNumber);
  469. }
  470. void LUAViewWidget::UpdateCurrentEditingLine(int lineNumber)
  471. {
  472. SetCursorPosition(lineNumber, 0);
  473. }
  474. void LUAViewWidget::SyncToBreakpointLine(int line, AZ::Uuid existingID)
  475. {
  476. auto existingBreakPont = AZStd::find_if(m_Breakpoints.begin(), m_Breakpoints.end(), [&](const AZStd::pair<int, BreakpointData>& _data)
  477. {
  478. return _data.second.m_editorId == existingID;
  479. });
  480. if (existingBreakPont != m_Breakpoints.end())
  481. {
  482. m_gui->m_breakpoints->RemoveBreakpoint(existingBreakPont->first);
  483. if (existingBreakPont->first != line)
  484. {
  485. m_Breakpoints.insert(AZStd::make_pair(line, BreakpointData(existingID, line)));
  486. m_gui->m_breakpoints->AddBreakpoint(line);
  487. m_Breakpoints.erase(existingBreakPont);
  488. }
  489. }
  490. else
  491. {
  492. m_Breakpoints.insert(AZStd::make_pair(line, BreakpointData(existingID, line)));
  493. m_gui->m_breakpoints->AddBreakpoint(line);
  494. }
  495. }
  496. //////////////////////////////////////////////////////////////////////////
  497. //Debugger Messages, from the LUAEditor::LUABreakpointTrackerMessages::Bus
  498. void LUAViewWidget::BreakpointsUpdate(const LUAEditor::BreakpointMap& uniqueBreakpoints)
  499. {
  500. (void)uniqueBreakpoints;
  501. if (!m_PullRequestQueued)
  502. {
  503. QTimer::singleShot(1, this, &LUAViewWidget::PullFreshBreakpoints);
  504. m_PullRequestQueued = true;
  505. return;
  506. }
  507. }
  508. void LUAViewWidget::PullFreshBreakpoints()
  509. {
  510. m_PullRequestQueued = false;
  511. m_Breakpoints.clear();
  512. m_gui->m_breakpoints->ClearBreakpoints();
  513. const LUAEditor::BreakpointMap* myData = NULL;
  514. LUAEditor::LUABreakpointRequestMessages::Bus::BroadcastResult(
  515. myData, &LUAEditor::LUABreakpointRequestMessages::Bus::Events::RequestBreakpoints);
  516. AZ_Assert(myData, "Nobody responded to the request breakpoints message.");
  517. // and slam down a new set
  518. for (LUAEditor::BreakpointMap::const_iterator it = myData->begin(); it != myData->end(); ++it)
  519. {
  520. const LUAEditor::Breakpoint& bp = it->second;
  521. if (m_Info.m_assetName == bp.m_assetName)
  522. {
  523. SyncToBreakpointLine(bp.m_documentLine, bp.m_breakpointId);
  524. }
  525. }
  526. }
  527. void LUAViewWidget::BreakpointHit(const LUAEditor::Breakpoint& bp)
  528. {
  529. if (bp.m_assetName == this->m_Info.m_assetName)
  530. {
  531. //AZ_TracePrintf("LUA", "Matching LUAViewWidget::BreakpointHit\n");
  532. SetCursorPosition(bp.m_documentLine, 0);
  533. emit RegainFocus();
  534. }
  535. }
  536. void LUAViewWidget::BreakpointResume()
  537. {
  538. m_gui->m_breakpoints->update();
  539. }
  540. void LUAViewWidget::BreakpointToggle(int line)
  541. {
  542. auto breakpoint = m_Breakpoints.find(line);
  543. if (breakpoint == m_Breakpoints.end())
  544. {
  545. Context_DebuggerManagement::Bus::Broadcast(&Context_DebuggerManagement::Bus::Events::CreateBreakpoint, m_Info.m_assetId, line);
  546. }
  547. else
  548. {
  549. Context_DebuggerManagement::Bus::Broadcast(
  550. &Context_DebuggerManagement::Bus::Events::DeleteBreakpoint, breakpoint->second.m_editorId);
  551. }
  552. }
  553. void LUAViewWidget::keyPressEvent(QKeyEvent* ev)
  554. {
  555. if (m_gui->m_luaTextEdit->isReadOnly())
  556. {
  557. bool isUseful = false;
  558. switch (ev->key())
  559. {
  560. case Qt::Key_Return:
  561. case Qt::Key_Enter:
  562. case Qt::Key_Backspace:
  563. case Qt::Key_Delete:
  564. isUseful = true;
  565. break;
  566. }
  567. bool isModified = false;
  568. if (ev->modifiers() & (Qt::ControlModifier | Qt::AltModifier))
  569. {
  570. // every Ctrl+ key combination is "modified" except for Ctrl+V, which should cause a check-out request
  571. if (((ev->key() != Qt::Key_V) && (ev->modifiers() & Qt::ControlModifier)))
  572. {
  573. isModified = true;
  574. }
  575. }
  576. if ((!isModified) && (isascii(ev->key()) || isUseful))
  577. {
  578. QMessageBox msgBox;
  579. msgBox.setText("Checkout This File To Edit?");
  580. msgBox.setInformativeText(m_Info.m_assetName.c_str());
  581. msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
  582. msgBox.setDefaultButton(QMessageBox::Ok);
  583. msgBox.setIcon(QMessageBox::Warning);
  584. int ret = msgBox.exec();
  585. if (ret == QMessageBox::Ok)
  586. {
  587. LUAEditorMainWindowMessages::Bus::Broadcast(
  588. &LUAEditorMainWindowMessages::Bus::Events::OnRequestCheckOut, m_Info.m_assetId);
  589. }
  590. }
  591. }
  592. ev->accept();
  593. QWidget::keyPressEvent(ev);
  594. }
  595. void LUAViewWidget::dropEvent(QDropEvent* e)
  596. {
  597. if (e->mimeData()->hasUrls())
  598. {
  599. LUADockWidget* ldw = luaDockWidget();
  600. if (ldw)
  601. {
  602. if (QMainWindow* pQMainWindow = qobject_cast<QMainWindow*>(ldw->parentWidget()))
  603. {
  604. if (LUAEditorMainWindow* pLUAEditorMainWindow = qobject_cast<LUAEditorMainWindow*>(pQMainWindow->parentWidget()))
  605. {
  606. e->setDropAction(Qt::CopyAction);
  607. pLUAEditorMainWindow->dropEvent(e);
  608. e->accept();
  609. }
  610. }
  611. }
  612. }
  613. else
  614. {
  615. QWidget::dropEvent(e);
  616. }
  617. }
  618. bool LUAViewWidget::IsReadOnly() const
  619. {
  620. return m_gui->m_luaTextEdit->isReadOnly();
  621. }
  622. bool LUAViewWidget::IsModified() const
  623. {
  624. return m_gui->m_luaTextEdit->document()->isModified();
  625. }
  626. void LUAViewWidget::SelectAll()
  627. {
  628. m_gui->m_luaTextEdit->selectAll();
  629. }
  630. bool LUAViewWidget::HasSelectedText() const
  631. {
  632. return m_gui->m_luaTextEdit->textCursor().hasSelection();
  633. }
  634. void LUAViewWidget::RemoveSelectedText()
  635. {
  636. auto cursor = m_gui->m_luaTextEdit->textCursor();
  637. if (!cursor.isNull() && cursor.hasSelection())
  638. {
  639. cursor.deleteChar();
  640. }
  641. }
  642. void LUAViewWidget::ReplaceSelectedText(const QString& newText)
  643. {
  644. auto cursor = m_gui->m_luaTextEdit->textCursor();
  645. if (!cursor.isNull())
  646. {
  647. cursor.insertText(newText);
  648. }
  649. }
  650. QString LUAViewWidget::GetSelectedText() const
  651. {
  652. return m_gui->m_luaTextEdit->textCursor().selectedText();
  653. }
  654. int LUAViewWidget::CalcDocPosition(int line, int column)
  655. {
  656. // Offset line number by one, because line number starts from 1, not 0.
  657. line = line - 1;
  658. if (line < 0)
  659. {
  660. line = column = 0;
  661. }
  662. int blockCount = m_gui->m_luaTextEdit->document()->blockCount();
  663. if (line > blockCount - 1)
  664. {
  665. line = blockCount - 1;
  666. column = INT_MAX;
  667. }
  668. auto block = m_gui->m_luaTextEdit->document()->findBlockByLineNumber(line);
  669. if (!block.isValid())
  670. {
  671. return m_gui->m_luaTextEdit->document()->characterCount() - 1;
  672. }
  673. column = AZStd::max(column, 0);
  674. column = AZStd::min(column, block.length() - 1);
  675. return block.position() + column;
  676. }
  677. void LUAViewWidget::GetCursorPosition(int& line, int& column) const
  678. {
  679. auto cursor = m_gui->m_luaTextEdit->textCursor();
  680. if (cursor.isNull())
  681. {
  682. line = 0;
  683. column = 0;
  684. }
  685. else
  686. {
  687. line = cursor.blockNumber() + 1; // offset by one because line number start from 1
  688. column = cursor.positionInBlock();
  689. }
  690. }
  691. void LUAViewWidget::SetCursorPosition(int line, int column)
  692. {
  693. UpdateCursor([&](QTextCursor& cursor)
  694. {
  695. cursor.setPosition(CalcDocPosition(line, column));
  696. });
  697. }
  698. void LUAViewWidget::MoveCursor(int relativePosition)
  699. {
  700. UpdateCursor([&](QTextCursor& cursor)
  701. {
  702. cursor.movePosition(relativePosition > 0 ? QTextCursor::MoveOperation::Right : QTextCursor::MoveOperation::Left,
  703. QTextCursor::MoveMode::MoveAnchor, abs(relativePosition));
  704. });
  705. }
  706. LUAViewWidget::FindOperation LUAViewWidget::FindFirst(const QString& searchString, bool isRegularExpression, bool isCaseSensitiveSearch, bool wholeWord, bool wrap, bool searchDown) const
  707. {
  708. FindOperation start(aznew FindOperationImpl);
  709. start.m_impl->m_cursor = m_gui->m_luaTextEdit->textCursor();
  710. start.m_impl->m_searchString = searchString;
  711. start.m_impl->m_isRegularExpression = isRegularExpression;
  712. start.m_impl->m_isCaseSensitiveSearch = isCaseSensitiveSearch;
  713. start.m_impl->m_wholeWord = wholeWord;
  714. start.m_impl->m_wrap = wrap;
  715. start.m_impl->m_searchDown = searchDown;
  716. FindNext(start);
  717. return start;
  718. }
  719. void LUAViewWidget::FindNext(FindOperation& operation) const
  720. {
  721. if (!operation)
  722. {
  723. return;
  724. }
  725. int flags = 0;
  726. if (operation.m_impl->m_wholeWord)
  727. {
  728. flags |= QTextDocument::FindFlag::FindWholeWords;
  729. }
  730. if (operation.m_impl->m_isCaseSensitiveSearch)
  731. {
  732. flags |= QTextDocument::FindFlag::FindCaseSensitively;
  733. }
  734. if (!operation.m_impl->m_searchDown)
  735. {
  736. flags |= QTextDocument::FindFlag::FindBackward;
  737. }
  738. if (operation.m_impl->m_isRegularExpression)
  739. {
  740. QRegExp regEx;
  741. regEx.setCaseSensitivity(operation.m_impl->m_isCaseSensitiveSearch ? Qt::CaseSensitivity::CaseSensitive : Qt::CaseSensitivity::CaseInsensitive);
  742. regEx.setPattern(operation.m_impl->m_searchString);
  743. operation.m_impl->m_cursor = m_gui->m_luaTextEdit->document()->find(regEx, operation.m_impl->m_cursor, static_cast<QTextDocument::FindFlag>(flags));
  744. if (!operation && operation.m_impl->m_wrap)
  745. {
  746. if (operation.m_impl->m_searchDown)
  747. {
  748. operation.m_impl->m_cursor.setPosition(0);
  749. }
  750. else
  751. {
  752. operation.m_impl->m_cursor.setPosition(m_gui->m_luaTextEdit->document()->characterCount() - 1);
  753. }
  754. operation.m_impl->m_cursor = m_gui->m_luaTextEdit->document()->find(regEx, operation.m_impl->m_cursor, static_cast<QTextDocument::FindFlag>(flags));
  755. }
  756. }
  757. else
  758. {
  759. operation.m_impl->m_cursor = m_gui->m_luaTextEdit->document()->find(operation.m_impl->m_searchString, operation.m_impl->m_cursor, static_cast<QTextDocument::FindFlag>(flags));
  760. if (!operation && operation.m_impl->m_wrap)
  761. {
  762. if (operation.m_impl->m_searchDown)
  763. {
  764. operation.m_impl->m_cursor.setPosition(0);
  765. }
  766. else
  767. {
  768. operation.m_impl->m_cursor.setPosition(m_gui->m_luaTextEdit->document()->characterCount() - 1);
  769. }
  770. operation.m_impl->m_cursor = m_gui->m_luaTextEdit->document()->find(operation.m_impl->m_searchString, operation.m_impl->m_cursor, static_cast<QTextDocument::FindFlag>(flags));
  771. }
  772. }
  773. if (operation)
  774. {
  775. m_gui->m_luaTextEdit->setTextCursor(operation.m_impl->m_cursor);
  776. }
  777. }
  778. QString LUAViewWidget::GetLineText(int line) const
  779. {
  780. auto block = m_gui->m_luaTextEdit->document()->findBlockByLineNumber(line);
  781. return block.text();
  782. }
  783. bool LUAViewWidget::GetSelection(int& lineStart, int& columnStart, int& lineEnd, int& columnEnd) const
  784. {
  785. auto doc = m_gui->m_luaTextEdit->document();
  786. auto cursor = m_gui->m_luaTextEdit->textCursor();
  787. if (cursor.isNull())
  788. {
  789. lineStart = columnStart = lineEnd = columnEnd = -1;
  790. return false;
  791. }
  792. auto startPos = cursor.selectionStart();
  793. auto endPos = cursor.selectionEnd();
  794. auto startBlock = doc->findBlock(startPos);
  795. lineStart = startBlock.blockNumber();
  796. columnStart = startPos - startBlock.position();
  797. auto endBlock = doc->findBlock(endPos);
  798. lineEnd = endBlock.blockNumber();
  799. columnEnd = endPos - endBlock.position();
  800. return true;
  801. }
  802. void LUAViewWidget::SetSelection(int lineStart, int columnStart, int lineEnd, int columnEnd)
  803. {
  804. auto startPos = CalcDocPosition(lineStart, columnStart);
  805. auto endPos = CalcDocPosition(lineEnd, columnEnd);
  806. UpdateCursor([&](QTextCursor& cursor)
  807. {
  808. // Go back to front to keep cursor position consistent
  809. cursor.setPosition(endPos);
  810. cursor.setPosition(startPos, QTextCursor::MoveMode::KeepAnchor);
  811. });
  812. }
  813. QString LUAViewWidget::GetText()
  814. {
  815. return m_gui->m_luaTextEdit->toPlainText();
  816. }
  817. void LUAViewWidget::Cut()
  818. {
  819. m_gui->m_luaTextEdit->cut();
  820. }
  821. void LUAViewWidget::Copy()
  822. {
  823. m_gui->m_luaTextEdit->copy();
  824. }
  825. template<typename Callable>
  826. //callabe sig (QString&, QTextBlock&)
  827. QString LUAViewWidget::AcumulateSelectedLines(int& startLine, int& endLine, Callable callable)
  828. {
  829. int startColumn;
  830. int endColumn;
  831. GetSelection(startLine, startColumn, endLine, endColumn);
  832. AZ_Assert(startLine <= endLine, "assume selection is always forward");
  833. auto cursor = m_gui->m_luaTextEdit->textCursor();
  834. QString newText;
  835. for (int i = startLine; i <= endLine; ++i)
  836. {
  837. auto block = m_gui->m_luaTextEdit->document()->findBlockByNumber(i);
  838. if (block.isValid())
  839. {
  840. callable(newText, block);
  841. }
  842. }
  843. return newText;
  844. }
  845. template<typename Callable>
  846. void LUAViewWidget::CommentHelper(Callable callable)
  847. {
  848. int startLine;
  849. int endLine;
  850. auto newText = AcumulateSelectedLines(startLine, endLine, callable);
  851. SetSelection(startLine + 1, 0, endLine + 2, 0);
  852. RemoveSelectedText();
  853. SetCursorPosition(startLine + 1, 0);
  854. ReplaceSelectedText(newText);
  855. SetSelection(startLine + 1, 0, endLine + 1, INT_MAX);
  856. }
  857. void LUAViewWidget::CommentSelectedLines()
  858. {
  859. CommentHelper([&](QString& newText, QTextBlock& block)
  860. {
  861. newText.append("-- ");
  862. newText.append(block.text());
  863. newText.append("\n");
  864. });
  865. }
  866. void LUAViewWidget::UncommentSelectedLines()
  867. {
  868. CommentHelper([&](QString& newText, QTextBlock& block)
  869. {
  870. auto blockText = block.text();
  871. if (blockText.startsWith("--"))
  872. {
  873. int removeCount = 2;
  874. if (blockText.at(2).isSpace())
  875. {
  876. ++removeCount;
  877. }
  878. blockText.remove(0, removeCount);
  879. }
  880. newText.append(blockText);
  881. newText.append("\n");
  882. });
  883. }
  884. void LUAViewWidget::MoveSelectedLinesUp()
  885. {
  886. int startLine;
  887. int endLine;
  888. auto currText = AcumulateSelectedLines(startLine, endLine, [&](QString& newText, QTextBlock& block)
  889. {
  890. newText.append(block.text());
  891. newText.append("\n");
  892. });
  893. currText.remove(currText.count() - 1, 1);
  894. if (startLine == 0)
  895. {
  896. return;
  897. }
  898. auto upText = GetLineText(startLine -1);
  899. SetSelection(startLine, 0, startLine, INT_MAX);
  900. RemoveSelectedText();
  901. SetSelection(startLine + 1, 0, endLine + 1, INT_MAX);
  902. RemoveSelectedText();
  903. SetCursorPosition(startLine , 0);
  904. ReplaceSelectedText(currText);
  905. SetCursorPosition(endLine + 1, 0);
  906. ReplaceSelectedText(upText);
  907. SetSelection(startLine, 0, endLine, INT_MAX);
  908. }
  909. void LUAViewWidget::MoveSelectedLinesDn()
  910. {
  911. int startLine;
  912. int endLine;
  913. auto newText = AcumulateSelectedLines(startLine, endLine, [&](QString& newText, QTextBlock& block)
  914. {
  915. newText.append(block.text());
  916. newText.append("\n");
  917. });
  918. if (endLine == m_gui->m_luaTextEdit->document()->blockCount() - 1)
  919. {
  920. return;
  921. }
  922. //hack if we are going to be the new last line
  923. if (endLine == m_gui->m_luaTextEdit->document()->blockCount() - 2)
  924. {
  925. newText.remove(newText.length() - 1, 1);
  926. newText.prepend("\n");
  927. }
  928. SetSelection(startLine + 1, 0, endLine + 2, 0);
  929. RemoveSelectedText();
  930. SetCursorPosition(startLine + 2, 0);
  931. ReplaceSelectedText(newText);
  932. SetSelection(startLine + 2, 0, endLine + 2, INT_MAX);
  933. }
  934. void LUAViewWidget::SetReadonly(bool readonly)
  935. {
  936. m_gui->m_luaTextEdit->setReadOnly(readonly);
  937. m_gui->m_luaTextEdit->style()->unpolish(m_gui->m_luaTextEdit);
  938. m_gui->m_luaTextEdit->style()->polish(m_gui->m_luaTextEdit);
  939. if (readonly)
  940. {
  941. // For readonly documents we set the TextSelectableByKeyboard to display a solid cursor.
  942. m_gui->m_luaTextEdit->setTextInteractionFlags(m_gui->m_luaTextEdit->textInteractionFlags() | Qt::TextSelectableByKeyboard);
  943. }
  944. }
  945. template<typename Callable>
  946. void LUAViewWidget::FindMatchingBrace(Callable callable)
  947. {
  948. auto doc = m_gui->m_luaTextEdit->document();
  949. auto cursor = m_gui->m_luaTextEdit->textCursor();
  950. int bracePos = cursor.position();
  951. QChar braceChar {
  952. QChar::Null
  953. };
  954. bool openingBrace {
  955. true
  956. };
  957. auto detect = [&]()
  958. {
  959. auto testChar = doc->characterAt(bracePos);
  960. if (testChar == '{' || testChar == '[' || testChar == '(')
  961. {
  962. braceChar = testChar;
  963. openingBrace = true;
  964. }
  965. if (testChar == '}' || testChar == ']' || testChar == ')')
  966. {
  967. braceChar = testChar;
  968. openingBrace = false;
  969. }
  970. };
  971. detect();
  972. if (braceChar == QChar::Null && bracePos > 0) //try previous char too so we can detect on either side of brace
  973. {
  974. --bracePos;
  975. detect();
  976. }
  977. if (braceChar != QChar::Null) //found one
  978. {
  979. int startPos = bracePos;
  980. QChar endChar {
  981. QChar::Null
  982. };
  983. if (braceChar == '{')
  984. {
  985. endChar = '}';
  986. }
  987. if (braceChar == '}')
  988. {
  989. endChar = '{';
  990. }
  991. if (braceChar == '[')
  992. {
  993. endChar = ']';
  994. }
  995. if (braceChar == ']')
  996. {
  997. endChar = '[';
  998. }
  999. if (braceChar == '(')
  1000. {
  1001. endChar = ')';
  1002. }
  1003. if (braceChar == ')')
  1004. {
  1005. endChar = '(';
  1006. }
  1007. int step {
  1008. openingBrace ? 1 : -1
  1009. };
  1010. int level {
  1011. 0
  1012. };
  1013. bracePos += step;
  1014. auto testChar = doc->characterAt(bracePos);
  1015. while (testChar != QChar::Null)
  1016. {
  1017. if (testChar == braceChar)
  1018. {
  1019. ++level;
  1020. }
  1021. else if (testChar == endChar)
  1022. {
  1023. --level;
  1024. if (level < 0)
  1025. {
  1026. if (step > 0)
  1027. {
  1028. ++bracePos;
  1029. }
  1030. else
  1031. {
  1032. ++startPos;
  1033. }
  1034. callable(startPos, bracePos);
  1035. return;
  1036. }
  1037. }
  1038. bracePos += step;
  1039. testChar = doc->characterAt(bracePos);
  1040. }
  1041. callable(startPos, -1); //had an opening brace, but no matching close brace
  1042. }
  1043. }
  1044. void LUAViewWidget::SelectToMatchingBrace()
  1045. {
  1046. auto cursor = m_gui->m_luaTextEdit->textCursor();
  1047. FindMatchingBrace([&](int startPos, int endPos)
  1048. {
  1049. if (endPos >= 0)
  1050. {
  1051. cursor.setPosition(startPos);
  1052. cursor.setPosition(endPos, QTextCursor::MoveMode::KeepAnchor);
  1053. m_gui->m_luaTextEdit->setTextCursor(cursor);
  1054. }
  1055. });
  1056. }
  1057. void LUAViewWidget::UpdateBraceHighlight()
  1058. {
  1059. m_Highlighter->SetBracketHighlighting(-1, -1);
  1060. FindMatchingBrace([&](int startPos, int endPos)
  1061. {
  1062. if (endPos > 0 && endPos < startPos)
  1063. {
  1064. AZStd::swap(startPos, endPos);
  1065. }
  1066. m_Highlighter->SetBracketHighlighting(startPos, endPos - 1);
  1067. });
  1068. auto cursor = m_gui->m_luaTextEdit->textCursor();
  1069. auto text = m_gui->m_luaTextEdit->document()->toPlainText();
  1070. m_gui->m_luaTextEdit->setExtraSelections(m_Highlighter->HighlightMatchingNames(cursor, text));
  1071. m_gui->m_luaTextEdit->update();
  1072. }
  1073. void LUAViewWidget::focusInEvent(QFocusEvent* pEvent)
  1074. {
  1075. QWidget::focusInEvent(pEvent);
  1076. m_gui->m_luaTextEdit->setFocus();
  1077. }
  1078. void LUAViewWidget::FoldAll()
  1079. {
  1080. m_gui->m_folding->FoldAll();
  1081. }
  1082. void LUAViewWidget::UnfoldAll()
  1083. {
  1084. m_gui->m_folding->UnfoldAll();
  1085. }
  1086. void LUAViewWidget::UpdateFont()
  1087. {
  1088. auto syntaxSettings = AZ::UserSettings::CreateFind<SyntaxStyleSettings>(AZ_CRC("LUA Editor Text Settings", 0xb6e15565), AZ::UserSettings::CT_GLOBAL);
  1089. auto font = syntaxSettings->GetFont();
  1090. font.setPointSize(static_cast<int>(font.pointSize() * (m_zoomPercent / 100.0f)));
  1091. m_gui->m_luaTextEdit->SetTabSize(syntaxSettings->GetTabSize());
  1092. m_gui->m_luaTextEdit->SetUseSpaces(syntaxSettings->UseSpacesInsteadOfTabs());
  1093. m_gui->m_luaTextEdit->UpdateFont(font, syntaxSettings->GetTabSize());
  1094. m_gui->m_breakpoints->SetFont(font);
  1095. m_Highlighter->SetFont(font);
  1096. m_gui->m_folding->SetFont(font);
  1097. m_gui->m_luaTextEdit->update();
  1098. m_gui->m_breakpoints->update();
  1099. m_gui->m_folding->update();
  1100. m_Highlighter->rehighlight();
  1101. CreateStyleSheet();
  1102. m_gui->m_luaTextEdit->repaint();
  1103. }
  1104. void LUAViewWidget::OnZoomIn()
  1105. {
  1106. m_zoomPercent = AZStd::min(m_zoomPercent + m_zoomPercent / 5, 500);
  1107. UpdateFont();
  1108. }
  1109. void LUAViewWidget::OnZoomOut()
  1110. {
  1111. m_zoomPercent = AZStd::max(m_zoomPercent - m_zoomPercent / 5, 50);
  1112. UpdateFont();
  1113. }
  1114. void LUAViewWidget::ResetZoom()
  1115. {
  1116. m_zoomPercent = 100;
  1117. UpdateFont();
  1118. }
  1119. }