Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,335 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : For listing available script commands with their descriptions
#include "ScriptHelpDialog.h"
#include <array>
// Qt
#include <QClipboard>
#include <QApplication>
#include <QLineEdit>
// AzQtComponents
#include <AzQtComponents/Components/Widgets/LineEdit.h>
// AzToolsFramework
#include <AzToolsFramework/API/EditorPythonConsoleBus.h> // for EditorPythonConsoleInterface
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <AzToolsFramework/PythonTerminal/ui_ScriptHelpDialog.h>
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
namespace AzToolsFramework
{
HeaderView::HeaderView(QWidget* parent)
: QHeaderView(Qt::Horizontal, parent)
, m_commandFilter(new QLineEdit(this))
, m_moduleFilter(new QLineEdit(this))
, m_descriptionFilter(new QLineEdit(this))
, m_exampleFilter(new QLineEdit(this))
{
// Allow the header sections to be clickable so we can change change the
// sort order on click
setSectionsClickable(true);
connect(this, &QHeaderView::geometriesChanged, this, &HeaderView::repositionLineEdits);
connect(this, &QHeaderView::sectionMoved, this, &HeaderView::repositionLineEdits);
connect(this, &QHeaderView::sectionResized, this, &HeaderView::repositionLineEdits);
connect(m_commandFilter, &QLineEdit::textChanged, this, &HeaderView::commandFilterChanged);
connect(m_moduleFilter, &QLineEdit::textChanged, this, &HeaderView::moduleFilterChanged);
connect(m_descriptionFilter, &QLineEdit::textChanged, this, &HeaderView::descriptionFilterChanged);
connect(m_exampleFilter, &QLineEdit::textChanged, this, &HeaderView::exampleFilterChanged);
AzQtComponents::LineEdit::applySearchStyle(m_commandFilter);
AzQtComponents::LineEdit::applySearchStyle(m_moduleFilter);
AzQtComponents::LineEdit::applySearchStyle(m_descriptionFilter);
AzQtComponents::LineEdit::applySearchStyle(m_exampleFilter);
// Calculate our height offset to embed our line edits in the header
const int margins = frameWidth() * 2 + 1;
m_lineEditHeightOffset = m_commandFilter->sizeHint().height() + margins;
}
QSize HeaderView::sizeHint() const
{
// Adjust our height to include the line edit offset
QSize size = QHeaderView::sizeHint();
size.setHeight(size.height() + m_lineEditHeightOffset);
return size;
}
void HeaderView::resizeEvent(QResizeEvent* ev)
{
QHeaderView::resizeEvent(ev);
repositionLineEdits();
}
void HeaderView::repositionLineEdits()
{
const int headerHeight = sizeHint().height();
const int lineEditYPos = headerHeight - m_lineEditHeightOffset;
const int col0Width = sectionSize(0);
const int col1Width = sectionSize(1);
const int col2Width = sectionSize(2);
const int col3Width = sectionSize(3);
const int adjustment = 2;
if (col0Width <= adjustment || col1Width <= adjustment)
{
return;
}
m_commandFilter->setFixedWidth(col0Width - adjustment);
m_moduleFilter->setFixedWidth(col1Width - adjustment);
m_descriptionFilter->setFixedWidth(col2Width - adjustment);
m_exampleFilter->setFixedWidth(col3Width - adjustment);
m_commandFilter->move(1, lineEditYPos);
m_moduleFilter->move(col0Width + 1, lineEditYPos);
m_descriptionFilter->move(col0Width + col1Width + 1, lineEditYPos);
m_exampleFilter->move(col0Width + col1Width + col2Width + 1, lineEditYPos);
m_commandFilter->show();
m_moduleFilter->show();
m_descriptionFilter->show();
// The example field is currently unused so will always be empty. Remove this when examples are added.
m_exampleFilter->hide();
}
ScriptHelpProxyModel::ScriptHelpProxyModel(QObject* parent)
: QSortFilterProxyModel(parent)
{
}
bool ScriptHelpProxyModel::filterAcceptsRow(int source_row, [[maybe_unused]] const QModelIndex& source_parent) const
{
if (!sourceModel())
{
return false;
}
const QString command = sourceModel()->index(source_row, ScriptHelpModel::ColumnCommand).data(Qt::DisplayRole).toString().toLower();
const QString module = sourceModel()->index(source_row, ScriptHelpModel::ColumnModule).data(Qt::DisplayRole).toString().toLower();
const QString description = sourceModel()->index(source_row, ScriptHelpModel::ColumnDescription).data(Qt::DisplayRole).toString().toLower();
return command.contains(m_commandFilter) && module.contains(m_moduleFilter) && description.contains(m_descriptionFilter);
}
void ScriptHelpProxyModel::setCommandFilter(const QString& text)
{
const QString lowerText = text.toLower();
if (m_commandFilter != lowerText)
{
m_commandFilter = lowerText;
invalidateFilter();
}
}
void ScriptHelpProxyModel::setModuleFilter(const QString& text)
{
const QString lowerText = text.toLower();
if (m_moduleFilter != lowerText)
{
m_moduleFilter = lowerText;
invalidateFilter();
}
}
void ScriptHelpProxyModel::setDescriptionFilter(const QString& text)
{
const QString lowerText = text.toLower();
if (m_descriptionFilter != lowerText)
{
m_descriptionFilter = lowerText;
invalidateFilter();
}
}
void ScriptHelpProxyModel::setExampleFilter(const QString& text)
{
const QString lowerText = text.toLower();
if (m_exampleFilter != lowerText)
{
m_exampleFilter = lowerText;
invalidateFilter();
}
}
ScriptHelpModel::ScriptHelpModel(QObject* parent)
: QAbstractTableModel(parent)
{
}
QVariant ScriptHelpModel::data(const QModelIndex& index, int role) const
{
if (index.row() < 0 || index.row() >= rowCount() || index.column() < 0 || index.column() >= ColumnCount)
{
return QVariant();
}
const int col = index.column();
const Item& item = m_items[index.row()];
if (role == Qt::DisplayRole)
{
if (col == ColumnCommand)
{
return item.command;
}
else if (col == ColumnModule)
{
return item.module;
}
else if (col == ColumnDescription)
{
return item.description;
}
}
return QVariant();
}
int ScriptHelpModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
{
return 0;
}
return m_items.size();
}
int ScriptHelpModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid())
{
return 0;
}
return ColumnCount;
}
Qt::ItemFlags ScriptHelpModel::flags([[maybe_unused]] const QModelIndex& index) const
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
QVariant ScriptHelpModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (section < 0 || section >= ColumnCount || orientation == Qt::Vertical)
{
return QVariant();
}
if (role == Qt::DisplayRole)
{
static const QStringList headers = { tr("Command"), tr("Module"), tr("Description"), tr("Example") };
return headers.at(section);
}
else if (role == Qt::TextAlignmentRole)
{
return Qt::AlignLeft;
}
return QAbstractTableModel::headerData(section, orientation, role);
}
void ScriptHelpModel::Reload()
{
beginResetModel();
using namespace AzToolsFramework;
EditorPythonConsoleInterface* editorPythonConsoleInterface = AZ::Interface<EditorPythonConsoleInterface>::Get();
if (editorPythonConsoleInterface)
{
EditorPythonConsoleInterface::GlobalFunctionCollection globalFunctionCollection;
editorPythonConsoleInterface->GetGlobalFunctionList(globalFunctionCollection);
m_items.reserve(globalFunctionCollection.size());
for (const EditorPythonConsoleInterface::GlobalFunction& globalFunction : globalFunctionCollection)
{
Item item;
item.command = globalFunction.m_functionName.data();
item.module = globalFunction.m_moduleName.data();
item.description = globalFunction.m_description.data();
m_items.push_back(item);
}
}
endResetModel();
}
ScriptTableView::ScriptTableView(QWidget* parent)
: QTableView(parent)
, m_model(new ScriptHelpModel(this))
, m_proxyModel(new ScriptHelpProxyModel(parent))
{
HeaderView* headerView = new HeaderView(this);
setHorizontalHeader(headerView); // our header view embeds filter line edits
QObject::connect(headerView, SIGNAL(sectionPressed(int)), this, SLOT(sortByColumn(int)));
m_proxyModel->setSourceModel(m_model);
setModel(m_proxyModel);
m_model->Reload();
setSortingEnabled(true);
horizontalHeader()->setSortIndicatorShown(false);
horizontalHeader()->setStretchLastSection(true);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::ContiguousSelection); // Not very useful for this dialog, but the MFC code allowed to select many rows
static const std::array<int, ScriptHelpModel::ColumnCount> colWidths = { { 100, 60, 300 } };
for (int col = 0; col < ScriptHelpModel::ColumnCount; ++col)
{
setColumnWidth(col, colWidths[col]);
}
setAlternatingRowColors(true);
connect(headerView, &HeaderView::commandFilterChanged,
m_proxyModel, &ScriptHelpProxyModel::setCommandFilter);
connect(headerView, &HeaderView::moduleFilterChanged,
m_proxyModel, &ScriptHelpProxyModel::setModuleFilter);
connect(headerView, &HeaderView::descriptionFilterChanged,
m_proxyModel, &ScriptHelpProxyModel::setDescriptionFilter);
connect(headerView, &HeaderView::exampleFilterChanged,
m_proxyModel, &ScriptHelpProxyModel::setExampleFilter);
}
CScriptHelpDialog::CScriptHelpDialog(QWidget* parent)
: QDialog(parent)
{
ui.reset(new Ui::ScriptDialog);
ui->setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("Script Help"));
setMinimumSize(QSize(480, 360));
connect(ui->tableView, &ScriptTableView::doubleClicked, this, &CScriptHelpDialog::OnDoubleClick);
}
void CScriptHelpDialog::OnDoubleClick(const QModelIndex& index)
{
if (!index.isValid())
{
return;
}
const QString command = index.sibling(index.row(), ScriptHelpModel::ColumnCommand).data(Qt::DisplayRole).toString();
const QString module = index.sibling(index.row(), ScriptHelpModel::ColumnModule).data(Qt::DisplayRole).toString();
const QString textForClipboard = module + QLatin1Char('.') + command + "()";
QApplication::clipboard()->setText(textForClipboard);
setWindowTitle(QString("Script Help (Copied \"%1\" to clipboard)").arg(textForClipboard));
}
} // namespace AzToolsFramework
#include <moc_ScriptHelpDialog.cpp>
@@ -0,0 +1,179 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : For listing available script commands with their descriptions
#ifndef CRYINCLUDE_EDITOR_SCRIPTHELPDIALOG_H
#define CRYINCLUDE_EDITOR_SCRIPTHELPDIALOG_H
#pragma once
#include <AzCore/Debug/Trace.h>
#if !defined(Q_MOC_RUN)
#include <QApplication>
#include <QMainWindow>
#include <QDialog>
#include <QAbstractTableModel>
#include <QSortFilterProxyModel>
#include <QTableView>
#include <QVector>
#include <QMouseEvent>
#include <QHeaderView>
#include <QScopedPointer>
#endif
class QResizeEvent;
namespace Ui {
class ScriptDialog;
}
namespace AzToolsFramework
{
class HeaderView
: public QHeaderView
{
Q_OBJECT
public:
explicit HeaderView(QWidget* parent = nullptr);
QSize sizeHint() const override;
Q_SIGNALS:
void commandFilterChanged(const QString& text);
void moduleFilterChanged(const QString& text);
void descriptionFilterChanged(const QString& text);
void exampleFilterChanged(const QString& text);
private Q_SLOTS:
void repositionLineEdits();
protected:
void resizeEvent(QResizeEvent* ev) override;
private:
QLineEdit* const m_commandFilter;
QLineEdit* const m_moduleFilter;
QLineEdit* const m_descriptionFilter;
QLineEdit* const m_exampleFilter;
int m_lineEditHeightOffset;
};
class ScriptHelpProxyModel
: public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit ScriptHelpProxyModel(QObject* parent = nullptr);
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
void setCommandFilter(const QString&);
void setModuleFilter(const QString&);
void setDescriptionFilter(const QString& text);
void setExampleFilter(const QString& text);
private:
QString m_commandFilter;
QString m_moduleFilter;
QString m_descriptionFilter;
QString m_exampleFilter;
};
class ScriptHelpModel
: public QAbstractTableModel
{
Q_OBJECT
public:
enum Column
{
ColumnCommand,
ColumnModule,
ColumnDescription,
ColumnCount // keep at end, for iteration purposes
};
struct Item
{
QString command;
QString module;
QString description;
QString example;
};
typedef QVector<Item> Items;
explicit ScriptHelpModel(QObject* parent = nullptr);
QVariant data(const QModelIndex& index, int role) const override;
int rowCount(const QModelIndex & = {}) const override;
int columnCount(const QModelIndex & = {}) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void Reload();
private:
Items m_items;
};
class ScriptTableView
: public QTableView
{
Q_OBJECT
public:
explicit ScriptTableView(QWidget* parent = nullptr);
private:
ScriptHelpModel* const m_model;
ScriptHelpProxyModel* const m_proxyModel;
};
class CScriptHelpDialog
: public QDialog
{
Q_OBJECT
public:
static CScriptHelpDialog* GetInstance()
{
static CScriptHelpDialog* pInstance = nullptr;
if (!pInstance)
{
QMainWindow* mainWindow = GetMainWindowOfCurrentApplication();
if (!mainWindow)
{
AZ_Assert(false, "Failed to find MainWindow.");
return nullptr;
}
QWidget* parentWidget = mainWindow->window() ? mainWindow->window() : mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS.
pInstance = new CScriptHelpDialog(parentWidget);
}
return pInstance;
}
private Q_SLOTS:
void OnDoubleClick(const QModelIndex&);
private:
static QMainWindow* GetMainWindowOfCurrentApplication()
{
QMainWindow* mainWindow = nullptr;
for (QWidget* w : qApp->topLevelWidgets())
{
if (mainWindow = qobject_cast<QMainWindow*>(w))
{
return mainWindow;
}
}
return nullptr;
}
explicit CScriptHelpDialog(QWidget* parent = nullptr);
QScopedPointer<Ui::ScriptDialog> ui;
};
} // namespace AzToolsFramework
#endif // CRYINCLUDE_EDITOR_SCRIPTHELPDIALOG_H
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScriptDialog</class>
<widget class="QDialog" name="ScriptDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>601</width>
<height>551</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="AzToolsFramework::ScriptTableView" name="tableView">
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>AzToolsFramework::ScriptTableView</class>
<extends>QTableView</extends>
<header>PythonTerminal/ScriptHelpDialog.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,269 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Dialog for python script terminal
#include "ScriptTermDialog.h"
// Qt
#include <QCompleter>
#include <QDesktopServices>
#include <QStringListModel>
#include <QStringBuilder>
#include <QToolButton>
#include <QLineEdit>
// AzToolsFramework
#include <AzToolsFramework/API/ViewPaneOptions.h> // for AzToolsFramework::ViewPaneOptions
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h> // for AzToolsFramework::EditorPythonRunnerRequestBus
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
// AzQtComponents
#include <AzQtComponents/Components/Widgets/ScrollBar.h>
// Editor
#include "ScriptHelpDialog.h"
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <AzToolsFramework/PythonTerminal/ui_ScriptTermDialog.h>
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
namespace AzToolsFramework
{
static constexpr const char* OtherCategory = "Other";
CScriptTermDialog::CScriptTermDialog(QWidget* parent)
: QWidget(parent)
, ui(new Ui::CScriptTermDialog)
{
ui->setupUi(this);
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect();
ui->SCRIPT_INPUT->installEventFilter(this);
connect(ui->SCRIPT_INPUT, &QLineEdit::returnPressed, this, &CScriptTermDialog::OnOK);
connect(ui->SCRIPT_INPUT, &QLineEdit::textChanged, this, &CScriptTermDialog::OnScriptInputTextChanged);
connect(ui->SCRIPT_HELP, &QToolButton::clicked, this, &CScriptTermDialog::OnScriptHelp);
connect(ui->SCRIPT_DOCS, &QToolButton::clicked, this, []() {
QDesktopServices::openUrl(QUrl("https://docs.aws.amazon.com/lumberyard/latest/tutorials/tutorials-python.html"));
});
InitCompleter();
RefreshStyle();
EditorPreferencesNotificationBus::Handler::BusConnect();
}
CScriptTermDialog::~CScriptTermDialog()
{
EditorPreferencesNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
}
void CScriptTermDialog::RegisterViewClass()
{
AzToolsFramework::ViewPaneOptions options;
options.canHaveMultipleInstances = true;
AzToolsFramework::RegisterViewPane<CScriptTermDialog>(SCRIPT_TERM_WINDOW_NAME, OtherCategory, options);
}
void CScriptTermDialog::RefreshStyle()
{
// Set the debug/warning text colors appropriately for the background theme
// (e.g. not have black text on black background)
m_textColor = Qt::black;
m_errorColor = QColor(200, 0, 0); // Error (Red)
m_warningColor = QColor(128, 112, 0); // Warning (Yellow)
ConsoleColorTheme consoleColorTheme(ConsoleColorTheme::Dark);
EditorSettingsAPIBus::BroadcastResult(consoleColorTheme, &EditorSettingsAPIBus::Handler::GetConsoleColorTheme);
if (consoleColorTheme == ConsoleColorTheme::Dark)
{
m_textColor = Qt::white;
m_errorColor = QColor(0xfa, 0x27, 0x27); // Error (Red)
m_warningColor = QColor(0xff, 0xaa, 0x22); // Warning (Yellow)
}
QColor bgColor;
if (consoleColorTheme == ConsoleColorTheme::Dark)
{
bgColor = QColor(0x22, 0x22, 0x22);
AzQtComponents::ScrollBar::applyLightStyle(ui->SCRIPT_OUTPUT);
}
else
{
bgColor = Qt::white;
AzQtComponents::ScrollBar::applyDarkStyle(ui->SCRIPT_OUTPUT);
}
ui->SCRIPT_OUTPUT->setStyleSheet(QString("QPlainTextEdit{ background: %1 }").arg(bgColor.name(QColor::HexRgb)));
// Clear out the console text when we change our background color since
// some of the previous text colors may not be appropriate for the
// new background color
QString text = ui->SCRIPT_OUTPUT->toPlainText();
ui->SCRIPT_OUTPUT->clear();
AppendToConsole(text, m_textColor);
}
void CScriptTermDialog::InitCompleter()
{
QStringList inputs;
AzToolsFramework::EditorPythonConsoleInterface* editorPythonConsoleInterface = AZ::Interface<AzToolsFramework::EditorPythonConsoleInterface>::Get();
if (editorPythonConsoleInterface)
{
AzToolsFramework::EditorPythonConsoleInterface::GlobalFunctionCollection globalFunctionCollection;
editorPythonConsoleInterface->GetGlobalFunctionList(globalFunctionCollection);
for (const AzToolsFramework::EditorPythonConsoleInterface::GlobalFunction& globalFunction : globalFunctionCollection)
{
inputs.append(QString("%1.%2()").arg(globalFunction.m_moduleName.data()).arg(globalFunction.m_functionName.data()));
}
}
m_lastCommandModel = new QStringListModel(ui->SCRIPT_INPUT);
m_completionModel = new QStringListModel(inputs, ui->SCRIPT_INPUT);
auto completer = new QCompleter(m_completionModel, ui->SCRIPT_INPUT);
ui->SCRIPT_INPUT->setCompleter(completer);
}
void CScriptTermDialog::OnOK()
{
const QString command = ui->SCRIPT_INPUT->text();
QString command2 = QLatin1String("] ")
% ui->SCRIPT_INPUT->text()
% QLatin1String("\r\n");
AppendToConsole(command2, m_textColor);
// Add the command to the history.
m_lastCommands.removeOne(command);
if (!command.isEmpty())
{
m_lastCommands.prepend(command);
}
ExecuteAndPrint(command.toLocal8Bit().data());
//clear script input via a QueuedConnection because completer sets text when it's done, undoing our clear.
QMetaObject::invokeMethod(ui->SCRIPT_INPUT, "setText", Qt::QueuedConnection, Q_ARG(QString, ""));
}
void CScriptTermDialog::OnScriptInputTextChanged(const QString& text)
{
if (text.isEmpty())
{
ui->SCRIPT_INPUT->completer()->setModel(m_completionModel);
}
}
void CScriptTermDialog::OnScriptHelp()
{
CScriptHelpDialog::GetInstance()->show();
}
void CScriptTermDialog::ExecuteAndPrint(const char* cmd)
{
if (AzToolsFramework::EditorPythonRunnerRequestBus::HasHandlers())
{
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByString, cmd, true);
}
else
{
AZ_Warning("python", false, "EditorPythonRunnerRequestBus has no handlers");
}
}
void CScriptTermDialog::AppendText(const char* pText)
{
AppendToConsole(pText, m_textColor);
}
void CScriptTermDialog::OnTraceMessage(AZStd::string_view message)
{
AppendToConsole(message.data(), m_textColor);
}
void CScriptTermDialog::OnErrorMessage(AZStd::string_view message)
{
AppendToConsole(message.data(), m_errorColor, true);
}
void CScriptTermDialog::OnExceptionMessage(AZStd::string_view message)
{
AppendToConsole(message.data(), m_warningColor, true);
}
void CScriptTermDialog::OnEditorPreferencesChanged()
{
RefreshStyle();
}
void CScriptTermDialog::AppendToConsole(const QString& string, const QColor& color, bool bold)
{
QTextCharFormat format;
format.setForeground(color);
if (bold)
{
format.setFontWeight(QFont::Bold);
}
QTextCursor cursor(ui->SCRIPT_OUTPUT->document());
cursor.movePosition(QTextCursor::End);
cursor.insertText(string, format);
}
bool CScriptTermDialog::eventFilter(QObject* obj, QEvent* e)
{
if (e->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e);
if (keyEvent->key() == Qt::Key_Down)
{
m_lastCommandModel->setStringList(m_lastCommands);
ui->SCRIPT_INPUT->completer()->setModel(m_lastCommandModel);
ui->SCRIPT_INPUT->completer()->setCompletionPrefix("");
ui->SCRIPT_INPUT->completer()->complete();
m_upArrowLastCommandIndex = -1;
return true;
}
else if (keyEvent->key() == Qt::Key_Up)
{
if (!m_lastCommands.isEmpty())
{
m_upArrowLastCommandIndex++;
if (m_upArrowLastCommandIndex < 0)
{
m_upArrowLastCommandIndex = 0;
}
else if (m_upArrowLastCommandIndex >= m_lastCommands.size())
{
// Already at the last item, nothing to do
return true;
}
ui->SCRIPT_INPUT->setText(m_lastCommands.at(m_upArrowLastCommandIndex));
}
}
else
{
// Reset cycling, we only want for sequential up arrow presses
m_upArrowLastCommandIndex = -1;
}
}
return QObject::eventFilter(obj, e);
}
} // namespace AzToolsFramework
#include <moc_ScriptTermDialog.cpp>
@@ -0,0 +1,89 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Dialog for python script terminal
#ifndef CRYINCLUDE_EDITOR_SCRIPTTERMDIALOG_H
#define CRYINCLUDE_EDITOR_SCRIPTTERMDIALOG_H
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzToolsFramework/API/EditorPythonConsoleBus.h>
#include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
#include <AzToolsFramework/Editor/EditorSettingsAPIBus.h>
#include <QWidget>
#include <QColor>
#include <QScopedPointer>
#endif
#define SCRIPT_TERM_WINDOW_NAME "Python Console"
class QStringListModel;
namespace Ui {
class CScriptTermDialog;
}
namespace AzToolsFramework
{
class CScriptTermDialog
: public QWidget
, protected EditorPythonConsoleNotificationBus::Handler
, protected EditorPreferencesNotificationBus::Handler
{
Q_OBJECT
public:
explicit CScriptTermDialog(QWidget* parent = nullptr);
~CScriptTermDialog();
void AppendText(const char* pText);
static void RegisterViewClass();
protected:
bool eventFilter(QObject* obj, QEvent* e) override;
//! EditorPythonConsoleNotificationBus::Handler
void OnTraceMessage(AZStd::string_view message) override;
void OnErrorMessage(AZStd::string_view message) override;
void OnExceptionMessage(AZStd::string_view message) override;
//! EditorPreferencesNotificationBus
void OnEditorPreferencesChanged() override;
private slots:
void OnScriptHelp();
void OnOK();
void OnScriptInputTextChanged(const QString& text);
private:
void RefreshStyle();
void InitCompleter();
void ExecuteAndPrint(const char* cmd);
void AppendToConsole(const QString& string, const QColor& color, bool bold = false);
QScopedPointer<Ui::CScriptTermDialog> ui;
QStringListModel* m_completionModel;
QStringListModel* m_lastCommandModel;
QStringList m_lastCommands;
QColor m_textColor;
QColor m_warningColor;
QColor m_errorColor;
int m_upArrowLastCommandIndex = -1;
};
} // namespace AzToolsFramework
#endif // CRYINCLUDE_EDITOR_SCRIPTTERMDIALOG_H
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CScriptTermDialog</class>
<widget class="QWidget" name="CScriptTermDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>678</width>
<height>300</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPlainTextEdit" name="SCRIPT_OUTPUT">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="SCRIPT_HELP">
<property name="text">
<string>?</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/stylesheet/img/UI20/Info.svg</normaloff>:/stylesheet/img/UI20/Info.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="SCRIPT_DOCS">
<property name="text">
<string>i</string>
</property>
<property name="icon">
<iconset>
<normaloff>:/stylesheet/img/UI20/Helpers.svg</normaloff>:/stylesheet/img/UI20/Helpers.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="SCRIPT_INPUT">
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="spacing" stdset="0">
<number>0</number>
</property>
<property name="leftMargin" stdset="0">
<number>0</number>
</property>
<property name="topMargin" stdset="0">
<number>0</number>
</property>
<property name="rightMargin" stdset="0">
<number>0</number>
</property>
<property name="bottomMargin" stdset="0">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>