mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-24 23:46:41 +00:00
Make editor wrapper a true wrapper to allow displaying warnings per-view
This commit is contained in:
+232
-224
@@ -36,6 +36,7 @@
|
||||
#include "Code/Resources.h"
|
||||
#include "Code/ScintillaSyntax.h"
|
||||
#include "Code/pyrenderdoc/PythonContext.h"
|
||||
#include "Widgets/Extended/RDLabel.h"
|
||||
#include "Widgets/Extended/RDToolTip.h"
|
||||
#include "Widgets/FindReplace.h"
|
||||
#include "scintilla/include/SciLexer.h"
|
||||
@@ -49,86 +50,92 @@ enum
|
||||
FirstExtensionOutputFilter,
|
||||
};
|
||||
|
||||
void updateEditorTitle(ScintillaEdit *editor);
|
||||
|
||||
void setEditorFilename(ScintillaEdit *editor, QString filename)
|
||||
EditorWrapper::EditorWrapper(PythonShell *parent) : QFrame(parent), m_PyShell(parent)
|
||||
{
|
||||
if(!editor)
|
||||
return;
|
||||
m_Scintilla = new ScintillaEdit(this);
|
||||
|
||||
QObject *obj = (QObject *)editor;
|
||||
obj->setProperty("filename", filename);
|
||||
m_Warning = new RDLabel(this);
|
||||
|
||||
ToolWindowManager *manager = ToolWindowManager::managerOf(editor);
|
||||
m_Warning->setForegroundRole(QPalette::ToolTipText);
|
||||
m_Warning->setBackgroundRole(QPalette::ToolTipBase);
|
||||
m_Warning->setAutoFillBackground(true);
|
||||
m_Warning->setMargin(6);
|
||||
m_Warning->setFrameStyle(QFrame::Box);
|
||||
m_Warning->setAlignment(Qt::AlignLeft);
|
||||
m_Warning->setIndent(1);
|
||||
|
||||
ToolWindowManagerArea *editorTabs = manager->areaOf(editor);
|
||||
int idx = editorTabs->indexOf(editor);
|
||||
if(idx >= 0)
|
||||
editorTabs->setTabToolTip(idx, filename);
|
||||
m_Warning->hide();
|
||||
|
||||
updateEditorTitle(editor);
|
||||
setLayout(new QVBoxLayout(this));
|
||||
|
||||
layout()->addWidget(m_Warning);
|
||||
layout()->addWidget(m_Scintilla);
|
||||
layout()->setSpacing(0);
|
||||
layout()->setMargin(0);
|
||||
layout()->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
QString getEditorFilename(ScintillaEdit *editor)
|
||||
EditorWrapper::~EditorWrapper()
|
||||
{
|
||||
if(!editor)
|
||||
return QString();
|
||||
QObject *obj = (QObject *)editor;
|
||||
return obj->property("filename").toString();
|
||||
m_PyShell->removeEditor(this);
|
||||
}
|
||||
|
||||
void markEditorModified(ScintillaEdit *editor, bool modified)
|
||||
void EditorWrapper::setFilename(QString filename)
|
||||
{
|
||||
if(!editor)
|
||||
return;
|
||||
|
||||
QObject *obj = (QObject *)editor;
|
||||
obj->setProperty("modified", modified);
|
||||
|
||||
updateEditorTitle(editor);
|
||||
m_Filename = filename;
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
bool isEditorModified(ScintillaEdit *editor)
|
||||
void EditorWrapper::setWarning(QString text)
|
||||
{
|
||||
if(!editor)
|
||||
return false;
|
||||
|
||||
QObject *obj = (QObject *)editor;
|
||||
return obj->property("modified").toBool();
|
||||
m_Warning->setText(text);
|
||||
m_Warning->setVisible(!text.isEmpty());
|
||||
}
|
||||
|
||||
void updateEditorTitle(ScintillaEdit *editor)
|
||||
void EditorWrapper::markModified(bool modified)
|
||||
{
|
||||
if(!editor)
|
||||
return;
|
||||
m_Modified = modified;
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
void EditorWrapper::updateTitle()
|
||||
{
|
||||
QString title;
|
||||
QString filename = getEditorFilename(editor);
|
||||
if(filename.isEmpty())
|
||||
if(m_Filename.isEmpty())
|
||||
{
|
||||
if(isEditorModified(editor))
|
||||
editor->setWindowTitle(lit("Untitled Script *"));
|
||||
if(isModified())
|
||||
setWindowTitle(lit("Untitled Script *"));
|
||||
else
|
||||
editor->setWindowTitle(lit("Untitled Script"));
|
||||
setWindowTitle(lit("Untitled Script"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isEditorModified(editor))
|
||||
editor->setWindowTitle(QFileInfo(filename).fileName() + lit(" *"));
|
||||
if(isModified())
|
||||
setWindowTitle(QFileInfo(m_Filename).fileName() + lit(" *"));
|
||||
else
|
||||
editor->setWindowTitle(QFileInfo(filename).fileName());
|
||||
}
|
||||
}
|
||||
setWindowTitle(QFileInfo(m_Filename).fileName());
|
||||
|
||||
EditorWrapper::EditorWrapper(PythonShell *parent) : ScintillaEdit(parent), m_PyShell(parent)
|
||||
{
|
||||
ToolWindowManager *manager = ToolWindowManager::managerOf(this);
|
||||
|
||||
if(manager)
|
||||
{
|
||||
ToolWindowManagerArea *editorTabs = manager->areaOf(this);
|
||||
|
||||
if(editorTabs)
|
||||
{
|
||||
int idx = editorTabs->indexOf(this);
|
||||
if(idx >= 0)
|
||||
editorTabs->setTabToolTip(idx, m_Filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorWrapper::checkAllowClose()
|
||||
{
|
||||
if(isEditorModified(this))
|
||||
if(isModified())
|
||||
{
|
||||
QString filename = getEditorFilename(this);
|
||||
QString filename = m_Filename;
|
||||
bool untitled = false;
|
||||
if(filename.isEmpty())
|
||||
{
|
||||
@@ -305,7 +312,7 @@ PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent)
|
||||
|
||||
ui->docking->addToolWindow(
|
||||
ui->replGroup, ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
|
||||
ui->docking->areaOf(m_Scintillas[0]), 0.3f));
|
||||
ui->docking->areaOf(m_Editors[0]), 0.3f));
|
||||
ui->docking->setToolWindowProperties(
|
||||
ui->replGroup, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
|
||||
|
||||
@@ -377,9 +384,9 @@ PythonShell::PythonShell(ICaptureContext &ctx, QWidget *parent)
|
||||
|
||||
ui->projectExplorer->expandItem(m_RecentFiles);
|
||||
|
||||
ui->docking->addToolWindow(ui->projectExplorer, ToolWindowManager::AreaReference(
|
||||
ToolWindowManager::LeftOf,
|
||||
ui->docking->areaOf(m_Scintillas[0]), 0.2f));
|
||||
ui->docking->addToolWindow(
|
||||
ui->projectExplorer, ToolWindowManager::AreaReference(
|
||||
ToolWindowManager::LeftOf, ui->docking->areaOf(m_Editors[0]), 0.2f));
|
||||
ui->docking->setToolWindowProperties(
|
||||
ui->projectExplorer,
|
||||
ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
|
||||
@@ -454,7 +461,7 @@ PythonShell::~PythonShell()
|
||||
if(!unsavedFile.isEmpty() && QFile::exists(unsavedFile))
|
||||
QFile::remove(unsavedFile);
|
||||
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
delete edit;
|
||||
|
||||
delete m_ToolTip;
|
||||
@@ -469,54 +476,56 @@ PythonShell::~PythonShell()
|
||||
|
||||
void PythonShell::doSyntaxCheck()
|
||||
{
|
||||
ScintillaEdit *editor = curEditor();
|
||||
EditorWrapper *editor = curEditor();
|
||||
|
||||
if(!editor)
|
||||
return;
|
||||
|
||||
if(editor->lexer() != SCLEX_PYTHON)
|
||||
ScintillaEdit *sc = editor->scintilla();
|
||||
|
||||
if(sc->lexer() != SCLEX_PYTHON)
|
||||
return;
|
||||
|
||||
// don't syntax check while the user still seems to be editing, e.g. with autocomplete or a
|
||||
// function tooltip active. The syntax check timer will be restarted when these go away
|
||||
if(editor->autoCActive() || m_FuncTip)
|
||||
if(sc->autoCActive() || m_FuncTip)
|
||||
return;
|
||||
|
||||
QByteArray script = editor->getText(editor->textLength() + 1);
|
||||
QByteArray script = sc->getText(sc->textLength() + 1);
|
||||
PyParseError parseError = completionContext->CheckPyParse(script, "script.py");
|
||||
|
||||
if(parseError.lineno >= 0)
|
||||
{
|
||||
sptr_t end = editor->lineLength(parseError.lineno - 1);
|
||||
sptr_t linePos = editor->positionFromLine(parseError.lineno - 1);
|
||||
sptr_t end = sc->lineLength(parseError.lineno - 1);
|
||||
sptr_t linePos = sc->positionFromLine(parseError.lineno - 1);
|
||||
while(QChar(QLatin1Char(script[int(linePos + end - 1)])).isSpace())
|
||||
end--;
|
||||
editor->setIndicatorCurrent(0);
|
||||
editor->indicatorFillRange(linePos + parseError.offset - 1, end + 1 - parseError.offset);
|
||||
sc->setIndicatorCurrent(0);
|
||||
sc->indicatorFillRange(linePos + parseError.offset - 1, end + 1 - parseError.offset);
|
||||
|
||||
editor->annotationSetText(parseError.lineno - 1, parseError.errStr.c_str());
|
||||
editor->annotationSetVisible(ANNOTATION_BOXED);
|
||||
editor->annotationSetStyle(parseError.lineno - 1, STYLE_ERROR);
|
||||
sc->annotationSetText(parseError.lineno - 1, parseError.errStr.c_str());
|
||||
sc->annotationSetVisible(ANNOTATION_BOXED);
|
||||
sc->annotationSetStyle(parseError.lineno - 1, STYLE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonShell::editorTab_Changed(int index)
|
||||
{
|
||||
ScintillaEdit *editor = curEditor();
|
||||
EditorWrapper *editor = curEditor();
|
||||
|
||||
ui->saveScript->setEnabled(getEditorFilename(editor) != QString());
|
||||
ui->saveScript->setEnabled(editor && editor->filename() != QString());
|
||||
}
|
||||
|
||||
void PythonShell::openFileModified(const QString &path)
|
||||
{
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
{
|
||||
if(getEditorFilename(edit) == path)
|
||||
if(edit->filename() == path)
|
||||
{
|
||||
// delay slightly to avoid reading while the file is being written or if it was deleted before
|
||||
// being written as some editors do
|
||||
QTimer::singleShot(150, [this, edit, path]() {
|
||||
bool mod = isEditorModified(edit);
|
||||
bool mod = edit->isModified();
|
||||
|
||||
// re-add the path, it may have been removed if the file was deleted
|
||||
m_Watcher->addPath(path);
|
||||
@@ -542,8 +551,8 @@ void PythonShell::openFileModified(const QString &path)
|
||||
QFile f(path);
|
||||
if(f.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
edit->setText(f.readAll().data());
|
||||
markEditorModified(edit, false);
|
||||
edit->scintilla()->setText(f.readAll().data());
|
||||
edit->markModified(false);
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -553,7 +562,7 @@ void PythonShell::openFileModified(const QString &path)
|
||||
|
||||
void PythonShell::editorTab_Menu(const QPoint &pos)
|
||||
{
|
||||
ToolWindowManagerArea *editorTabs = ui->docking->areaOf(m_Scintillas[0]);
|
||||
ToolWindowManagerArea *editorTabs = ui->docking->areaOf(m_Editors[0]);
|
||||
|
||||
int tabIndex = editorTabs->tabBar()->tabAt(pos);
|
||||
|
||||
@@ -649,9 +658,9 @@ void PythonShell::addExtensionDirItems(RDTreeWidgetItem *root, QDir dir)
|
||||
}
|
||||
}
|
||||
|
||||
ScintillaEdit *PythonShell::curEditor()
|
||||
EditorWrapper *PythonShell::curEditor()
|
||||
{
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
{
|
||||
if(edit->isVisible())
|
||||
return edit;
|
||||
@@ -660,36 +669,40 @@ ScintillaEdit *PythonShell::curEditor()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScintillaEdit *PythonShell::makeEditor(rdcstr filename)
|
||||
void PythonShell::makeEditor(rdcstr filename, rdcstr text)
|
||||
{
|
||||
ScintillaEdit *editor = new EditorWrapper(this);
|
||||
|
||||
editor->indicSetFore(0, 0x0000ff);
|
||||
|
||||
m_FindReplace->configureFindIndicator(editor);
|
||||
|
||||
editor->styleSetFont(STYLE_DEFAULT, Formatter::FixedFont().family().toUtf8().data());
|
||||
editor->styleSetSize(STYLE_DEFAULT, Formatter::FixedFont().pointSize());
|
||||
editor->styleSetFont(STYLE_ERROR, Formatter::FixedFont().family().toUtf8().data());
|
||||
editor->styleSetSize(STYLE_ERROR, Formatter::FixedFont().pointSize());
|
||||
editor->styleSetBack(
|
||||
STYLE_ERROR, IsDarkTheme() ? SCINTILLA_COLOUR(175, 70, 70) : SCINTILLA_COLOUR(255, 150, 150));
|
||||
|
||||
editor->setMarginLeft(4.0);
|
||||
editor->setMarginWidthN(0, 32.0);
|
||||
editor->setMarginWidthN(1, 0.0);
|
||||
editor->setMarginWidthN(2, 16.0);
|
||||
EditorWrapper *editor = new EditorWrapper(this);
|
||||
editor->setObjectName(lit("scriptEditor"));
|
||||
|
||||
editor->markerSetBack(CURRENT_MARKER, SCINTILLA_COLOUR(240, 128, 128));
|
||||
editor->markerSetBack(CURRENT_MARKER + 1, SCINTILLA_COLOUR(240, 128, 128));
|
||||
editor->markerDefine(CURRENT_MARKER, SC_MARK_SHORTARROW);
|
||||
editor->markerDefine(CURRENT_MARKER + 1, SC_MARK_BACKGROUND);
|
||||
ScintillaEdit *sc = editor->scintilla();
|
||||
|
||||
editor->usePopUp(SC_POPUP_NEVER);
|
||||
editor->setFilename(filename);
|
||||
|
||||
editor->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QObject::connect(editor, &ScintillaEdit::customContextMenuRequested, this,
|
||||
sc->indicSetFore(0, 0x0000ff);
|
||||
|
||||
m_FindReplace->configureFindIndicator(sc);
|
||||
|
||||
sc->styleSetFont(STYLE_DEFAULT, Formatter::FixedFont().family().toUtf8().data());
|
||||
sc->styleSetSize(STYLE_DEFAULT, Formatter::FixedFont().pointSize());
|
||||
sc->styleSetFont(STYLE_ERROR, Formatter::FixedFont().family().toUtf8().data());
|
||||
sc->styleSetSize(STYLE_ERROR, Formatter::FixedFont().pointSize());
|
||||
sc->styleSetBack(STYLE_ERROR,
|
||||
IsDarkTheme() ? SCINTILLA_COLOUR(175, 70, 70) : SCINTILLA_COLOUR(255, 150, 150));
|
||||
|
||||
sc->setMarginLeft(4.0);
|
||||
sc->setMarginWidthN(0, 32.0);
|
||||
sc->setMarginWidthN(1, 0.0);
|
||||
sc->setMarginWidthN(2, 16.0);
|
||||
|
||||
sc->markerSetBack(CURRENT_MARKER, SCINTILLA_COLOUR(240, 128, 128));
|
||||
sc->markerSetBack(CURRENT_MARKER + 1, SCINTILLA_COLOUR(240, 128, 128));
|
||||
sc->markerDefine(CURRENT_MARKER, SC_MARK_SHORTARROW);
|
||||
sc->markerDefine(CURRENT_MARKER + 1, SC_MARK_BACKGROUND);
|
||||
|
||||
sc->usePopUp(SC_POPUP_NEVER);
|
||||
|
||||
sc->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QObject::connect(sc, &ScintillaEdit::customContextMenuRequested, this,
|
||||
&PythonShell::editor_contextMenu);
|
||||
|
||||
QString suffix;
|
||||
@@ -698,104 +711,95 @@ ScintillaEdit *PythonShell::makeEditor(rdcstr filename)
|
||||
suffix = QFileInfo(filename).suffix().toLower();
|
||||
if(suffix == lit("md"))
|
||||
{
|
||||
ConfigureSyntax(editor, SCLEX_NULL);
|
||||
editor->setWrapMode(SC_WRAP_WORD);
|
||||
ConfigureSyntax(sc, SCLEX_NULL);
|
||||
sc->setWrapMode(SC_WRAP_WORD);
|
||||
}
|
||||
else if(suffix.toLower() == lit("json"))
|
||||
{
|
||||
ConfigureSyntax(editor, SCLEX_JSON);
|
||||
editor->setWrapMode(SC_WRAP_WORD);
|
||||
ConfigureSyntax(sc, SCLEX_JSON);
|
||||
sc->setWrapMode(SC_WRAP_WORD);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigureSyntax(editor, SCLEX_PYTHON);
|
||||
ConfigureSyntax(sc, SCLEX_PYTHON);
|
||||
}
|
||||
|
||||
editor->setTabWidth(4);
|
||||
editor->setUseTabs(false);
|
||||
sc->setTabWidth(4);
|
||||
sc->setUseTabs(false);
|
||||
|
||||
editor->setScrollWidth(1);
|
||||
editor->setScrollWidthTracking(true);
|
||||
sc->setScrollWidth(1);
|
||||
sc->setScrollWidthTracking(true);
|
||||
|
||||
editor->colourise(0, -1);
|
||||
sc->colourise(0, -1);
|
||||
|
||||
editor->autoCSetMaxHeight(10);
|
||||
editor->autoCSetCancelAtStart(false);
|
||||
sc->autoCSetMaxHeight(10);
|
||||
sc->autoCSetCancelAtStart(false);
|
||||
|
||||
editor->setMouseDwellTime(400);
|
||||
sc->setMouseDwellTime(400);
|
||||
|
||||
editor->installEventFilter(this);
|
||||
|
||||
QObject::connect(editor, &QWidget::destroyed, [this, editor]() {
|
||||
hideFunccompleteTooltip();
|
||||
m_Scintillas.removeOne(editor);
|
||||
m_Watcher->removePath(getEditorFilename(editor));
|
||||
updateEditorCloseButton();
|
||||
});
|
||||
sc->installEventFilter(this);
|
||||
|
||||
// start syntax checking if we exit autocomplete
|
||||
QObject::connect(editor, &ScintillaEdit::autoCompleteCancelled,
|
||||
QObject::connect(sc, &ScintillaEdit::autoCompleteCancelled,
|
||||
[this]() { m_SyntaxCheckTimer->start(); });
|
||||
QObject::connect(editor, &ScintillaEdit::autoCompleteSelection,
|
||||
QObject::connect(sc, &ScintillaEdit::autoCompleteSelection,
|
||||
[this]() { m_SyntaxCheckTimer->start(); });
|
||||
|
||||
QObject::connect(editor, &ScintillaEdit::modified,
|
||||
[this, editor](int type, int, int, int, const QByteArray &text, int, int, int) {
|
||||
if(type & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT | SC_MOD_BEFOREINSERT |
|
||||
SC_MOD_BEFOREDELETE))
|
||||
{
|
||||
m_FindReplace->clearFindState();
|
||||
QObject::connect(
|
||||
sc, &ScintillaEdit::modified,
|
||||
[this, editor, sc](int type, int, int, int, const QByteArray &text, int, int, int) {
|
||||
if(type & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT | SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
|
||||
{
|
||||
m_FindReplace->clearFindState();
|
||||
|
||||
markEditorModified(editor, true);
|
||||
updateEditorTitle(editor);
|
||||
editor->markModified(true);
|
||||
|
||||
editor->markerDeleteAll(CURRENT_MARKER);
|
||||
editor->markerDeleteAll(CURRENT_MARKER + 1);
|
||||
sc->markerDeleteAll(CURRENT_MARKER);
|
||||
sc->markerDeleteAll(CURRENT_MARKER + 1);
|
||||
|
||||
// always remove errors immediately
|
||||
editor->setIndicatorCurrent(0);
|
||||
editor->indicatorClearRange(0, editor->textLength());
|
||||
editor->annotationClearAll();
|
||||
// always remove errors immediately
|
||||
sc->setIndicatorCurrent(0);
|
||||
sc->indicatorClearRange(0, sc->textLength());
|
||||
sc->annotationClearAll();
|
||||
|
||||
m_SyntaxCheckTimer->start();
|
||||
}
|
||||
m_SyntaxCheckTimer->start();
|
||||
}
|
||||
|
||||
if(type & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT))
|
||||
{
|
||||
if(!editor->autoCActive() || text.contains('\r') || text.contains('\n'))
|
||||
{
|
||||
completionContext->reflectSource(
|
||||
QString::fromUtf8(editor->getText(editor->textLength() + 1)));
|
||||
}
|
||||
else if(editor->autoCActive())
|
||||
{
|
||||
// delay updating the autocomplete so the current cursor position is updated
|
||||
GUIInvoke::defer(this, [this, editor]() { doAutocomplete(editor); });
|
||||
}
|
||||
}
|
||||
});
|
||||
if(type & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT))
|
||||
{
|
||||
if(!sc->autoCActive() || text.contains('\r') || text.contains('\n'))
|
||||
{
|
||||
completionContext->reflectSource(QString::fromUtf8(sc->getText(sc->textLength() + 1)));
|
||||
}
|
||||
else if(sc->autoCActive())
|
||||
{
|
||||
// delay updating the autocomplete so the current cursor position is updated
|
||||
GUIInvoke::defer(this, [this, sc]() { doAutocomplete(sc); });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(editor, &ScintillaEdit::dwellStart, [this, editor](int x, int y) {
|
||||
if(editor->autoCActive())
|
||||
QObject::connect(sc, &ScintillaEdit::dwellStart, [this, sc](int x, int y) {
|
||||
if(sc->autoCActive())
|
||||
return;
|
||||
|
||||
if(m_ToolTip->isVisible() && m_FuncTip)
|
||||
return;
|
||||
|
||||
if(!editor->geometry().contains(editor->mapFromGlobal(QCursor::pos())))
|
||||
if(!sc->geometry().contains(sc->mapFromGlobal(QCursor::pos())))
|
||||
return;
|
||||
|
||||
QWidget *widgetInCursor = QApplication::widgetAt(QCursor::pos());
|
||||
if(widgetInCursor && editor != widgetInCursor && editor != widgetInCursor->parentWidget())
|
||||
if(widgetInCursor && sc != widgetInCursor && sc != widgetInCursor->parentWidget())
|
||||
return;
|
||||
|
||||
sptr_t pos = editor->positionFromPointClose(x, y);
|
||||
sptr_t pos = sc->positionFromPointClose(x, y);
|
||||
|
||||
if(pos == -1)
|
||||
return;
|
||||
|
||||
sptr_t line = editor->lineFromPosition(pos);
|
||||
sptr_t col = pos - editor->positionFromLine(line);
|
||||
sptr_t line = sc->lineFromPosition(pos);
|
||||
sptr_t col = pos - sc->positionFromLine(line);
|
||||
|
||||
QString tooltip = completionContext->tooltipForLoc(line + 1, col);
|
||||
|
||||
@@ -808,29 +812,28 @@ ScintillaEdit *PythonShell::makeEditor(rdcstr filename)
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(editor, &ScintillaEdit::dwellEnd, [this, editor](int, int) {
|
||||
if(editor->autoCActive())
|
||||
QObject::connect(sc, &ScintillaEdit::dwellEnd, [this, sc](int, int) {
|
||||
if(sc->autoCActive())
|
||||
return;
|
||||
|
||||
if(!m_FuncTip)
|
||||
m_ToolTip->hideTip();
|
||||
});
|
||||
|
||||
QObject::connect(editor, &ScintillaEdit::charAdded,
|
||||
[this, editor](int ch) { doAutocomplete(editor); });
|
||||
QObject::connect(sc, &ScintillaEdit::charAdded, [this, sc](int ch) { doAutocomplete(sc); });
|
||||
|
||||
QObject::connect(editor, &ScintillaEdit::buttonPressed,
|
||||
[this, editor](QMouseEvent *ev) { hideFunccompleteTooltip(); });
|
||||
QObject::connect(sc, &ScintillaEdit::buttonPressed,
|
||||
[this, sc](QMouseEvent *ev) { hideFunccompleteTooltip(); });
|
||||
|
||||
QObject::connect(editor, &ScintillaEdit::keyPressed, [this, editor](QKeyEvent *ev) {
|
||||
QObject::connect(sc, &ScintillaEdit::keyPressed, [this, sc](QKeyEvent *ev) {
|
||||
if(ev->key() == Qt::Key_Space && (ev->modifiers() & Qt::ControlModifier))
|
||||
doAutocomplete(editor);
|
||||
doAutocomplete(sc);
|
||||
|
||||
if(m_ToolTip->isVisible() && m_FuncTip)
|
||||
{
|
||||
if(editor->lineFromPosition(editor->currentPos()) == m_FuncTipLine)
|
||||
if(sc->lineFromPosition(sc->currentPos()) == m_FuncTipLine)
|
||||
{
|
||||
doFunccomplete(editor);
|
||||
doFunccomplete(sc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -839,12 +842,12 @@ ScintillaEdit *PythonShell::makeEditor(rdcstr filename)
|
||||
|
||||
if(ev->key() == Qt::Key_F1)
|
||||
{
|
||||
sptr_t pos = editor->currentPos();
|
||||
sptr_t pos = sc->currentPos();
|
||||
|
||||
if(pos >= 0)
|
||||
{
|
||||
sptr_t line = editor->lineFromPosition(pos);
|
||||
sptr_t col = pos - editor->positionFromLine(line);
|
||||
sptr_t line = sc->lineFromPosition(pos);
|
||||
sptr_t col = pos - sc->positionFromLine(line);
|
||||
|
||||
QString typeName = completionContext->typenameForLoc(line + 1, col);
|
||||
|
||||
@@ -853,36 +856,39 @@ ScintillaEdit *PythonShell::makeEditor(rdcstr filename)
|
||||
}
|
||||
}
|
||||
|
||||
m_FindReplace->handleEditorKeypress(editor, ev);
|
||||
m_FindReplace->handleEditorKeypress(sc, ev);
|
||||
});
|
||||
|
||||
if(m_Scintillas.empty())
|
||||
if(m_Editors.empty())
|
||||
{
|
||||
ui->docking->addToolWindow(editor, ToolWindowManager::EmptySpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->docking->addToolWindow(
|
||||
editor, ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->docking->areaOf(m_Scintillas[0])));
|
||||
ui->docking->addToolWindow(editor,
|
||||
ToolWindowManager::AreaReference(ToolWindowManager::AddTo,
|
||||
ui->docking->areaOf(m_Editors[0])));
|
||||
}
|
||||
|
||||
m_Scintillas.push_back(editor);
|
||||
m_Editors.push_back(editor);
|
||||
m_Scintillas.push_back(sc);
|
||||
|
||||
updateEditorCloseButton();
|
||||
|
||||
return editor;
|
||||
sc->setText(text.c_str());
|
||||
sc->emptyUndoBuffer();
|
||||
editor->markModified(false);
|
||||
}
|
||||
|
||||
void PythonShell::updateEditorCloseButton()
|
||||
{
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
{
|
||||
ToolWindowManager::ToolWindowProperty props =
|
||||
ToolWindowManager::DisallowUserDocking | ToolWindowManager::AlwaysDisplayFullTabs;
|
||||
|
||||
// disallow closing last scintilla
|
||||
if(m_Scintillas.size() == 1)
|
||||
if(m_Editors.size() == 1)
|
||||
props = props | ToolWindowManager::HideCloseButton;
|
||||
|
||||
ui->docking->setToolWindowProperties(edit, props);
|
||||
@@ -1018,12 +1024,18 @@ void PythonShell::setPersistData(const QVariant &persistData)
|
||||
expansion.insert(x.toUInt());
|
||||
ui->projectExplorer->applyExpansion(expansion, 0);
|
||||
|
||||
if(ui->docking->areaOf(m_Editors[0]) == NULL)
|
||||
ui->docking->addToolWindow(m_Editors[0], ToolWindowManager::AreaReference(
|
||||
ToolWindowManager::RightOf,
|
||||
ui->docking->areaOf(ui->projectExplorer), 0.8f));
|
||||
|
||||
setupTabs();
|
||||
}
|
||||
|
||||
void PythonShell::setupTabs()
|
||||
{
|
||||
ToolWindowManagerArea *editorTabs = ui->docking->areaOf(m_Scintillas[0]);
|
||||
ToolWindowManagerArea *editorTabs = ui->docking->areaOf(m_Editors[0]);
|
||||
|
||||
QObject::connect(editorTabs, &QTabWidget::currentChanged, this, &PythonShell::editorTab_Changed);
|
||||
|
||||
editorTabs->tabBar()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
@@ -1049,10 +1061,7 @@ bool PythonShell::LoadScriptFromFilename(rdcstr filename)
|
||||
QFile f(filename);
|
||||
if(f.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
ScintillaEdit *editor = makeEditor(filename);
|
||||
|
||||
editor->setText(f.readAll().data());
|
||||
editor->emptyUndoBuffer();
|
||||
makeEditor(filename, f.readAll().data());
|
||||
|
||||
ui->saveScript->setEnabled(true);
|
||||
|
||||
@@ -1062,8 +1071,6 @@ bool PythonShell::LoadScriptFromFilename(rdcstr filename)
|
||||
|
||||
m_Watcher->addPath(filename);
|
||||
|
||||
setEditorFilename(editor, QString(filename));
|
||||
markEditorModified(editor, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1073,25 +1080,21 @@ bool PythonShell::LoadScriptFromFilename(rdcstr filename)
|
||||
|
||||
void PythonShell::CreateNewScriptEditor(rdcstr name, rdcstr text)
|
||||
{
|
||||
ScintillaEdit *editor = makeEditor("");
|
||||
|
||||
editor->setText(text.c_str());
|
||||
editor->emptyUndoBuffer();
|
||||
makeEditor(name, text);
|
||||
|
||||
ui->saveScript->setEnabled(true);
|
||||
|
||||
setEditorFilename(editor, QString(name));
|
||||
markEditorModified(editor, false);
|
||||
}
|
||||
|
||||
rdcstr PythonShell::GetScriptText()
|
||||
{
|
||||
ScintillaEdit *editor = curEditor();
|
||||
EditorWrapper *editor = curEditor();
|
||||
|
||||
if(!editor)
|
||||
return rdcstr();
|
||||
|
||||
return editor->getText(editor->textLength() + 1).data();
|
||||
ScintillaEdit *sc = editor->scintilla();
|
||||
|
||||
return sc->getText(sc->textLength() + 1).data();
|
||||
}
|
||||
|
||||
void PythonShell::SetExtensionOutputFilter(const rdcstr &extensionName)
|
||||
@@ -1133,7 +1136,7 @@ void PythonShell::ShowHelp()
|
||||
|
||||
void PythonShell::runScript(bool debugging)
|
||||
{
|
||||
ScintillaEdit *editor = curEditor();
|
||||
EditorWrapper *editor = curEditor();
|
||||
|
||||
if(!editor)
|
||||
return;
|
||||
@@ -1148,7 +1151,7 @@ void PythonShell::runScript(bool debugging)
|
||||
|
||||
updateScriptOutput(true);
|
||||
|
||||
QString script = QString::fromUtf8(editor->getText(editor->textLength() + 1));
|
||||
QString script = GetScriptText();
|
||||
|
||||
enableButtons(false);
|
||||
|
||||
@@ -1161,7 +1164,7 @@ void PythonShell::runScript(bool debugging)
|
||||
PythonContext::AddDebuggableThread();
|
||||
|
||||
scriptContext = context;
|
||||
runningScriptEditor = editor;
|
||||
runningScriptEditor = editor->scintilla();
|
||||
context->executeString(lit("script.py"), script, debugging);
|
||||
scriptContext = NULL;
|
||||
|
||||
@@ -1248,13 +1251,9 @@ void PythonShell::on_newScript_clicked()
|
||||
|
||||
minidocHeader = QFormatStr("# %1\n\n").arg(minidocHeader);
|
||||
|
||||
ScintillaEdit *editor = makeEditor("");
|
||||
makeEditor("", minidocHeader);
|
||||
|
||||
ui->saveScript->setEnabled(false);
|
||||
|
||||
editor->setText(minidocHeader.toUtf8().data());
|
||||
editor->emptyUndoBuffer();
|
||||
markEditorModified(editor, false);
|
||||
}
|
||||
|
||||
void PythonShell::on_openScript_clicked()
|
||||
@@ -1270,29 +1269,29 @@ void PythonShell::on_openScript_clicked()
|
||||
|
||||
void PythonShell::on_saveScript_clicked()
|
||||
{
|
||||
ScintillaEdit *editor = curEditor();
|
||||
EditorWrapper *editor = curEditor();
|
||||
|
||||
if(!editor)
|
||||
return;
|
||||
|
||||
QString filename = getEditorFilename(editor);
|
||||
QString filename = editor->filename();
|
||||
|
||||
if(!QFileInfo(filename).isAbsolute())
|
||||
return on_saveAsScript_clicked();
|
||||
|
||||
if(saveEditor(editor, filename))
|
||||
markEditorModified(editor, false);
|
||||
editor->markModified(false);
|
||||
}
|
||||
|
||||
void PythonShell::on_saveAsScript_clicked()
|
||||
{
|
||||
ScintillaEdit *editor = curEditor();
|
||||
EditorWrapper *editor = curEditor();
|
||||
|
||||
if(!editor)
|
||||
return;
|
||||
|
||||
if(saveEditorAs(editor))
|
||||
markEditorModified(editor, false);
|
||||
editor->markModified(false);
|
||||
}
|
||||
|
||||
void PythonShell::on_runScript_clicked()
|
||||
@@ -1379,9 +1378,9 @@ void PythonShell::on_projectExplorer_itemActivated(RDTreeWidgetItem *item, int c
|
||||
QString filename = tr("Example: ") + item->text(0);
|
||||
QString text = item->data(0, Qt::UserRole).toString();
|
||||
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
{
|
||||
if(getEditorFilename(edit) == filename)
|
||||
if(edit->filename() == filename)
|
||||
{
|
||||
ToolWindowManager::raiseToolWindow(edit);
|
||||
return;
|
||||
@@ -1399,9 +1398,9 @@ void PythonShell::on_projectExplorer_itemActivated(RDTreeWidgetItem *item, int c
|
||||
if(filename.isEmpty())
|
||||
return;
|
||||
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
{
|
||||
if(getEditorFilename(edit) == filename)
|
||||
if(edit->filename() == filename)
|
||||
{
|
||||
ToolWindowManager::raiseToolWindow(edit);
|
||||
return;
|
||||
@@ -1440,11 +1439,9 @@ void PythonShell::on_projectExplorer_itemActivated(RDTreeWidgetItem *item, int c
|
||||
|
||||
bool PythonShell::checkAllowClose()
|
||||
{
|
||||
for(ScintillaEdit *edit : m_Scintillas)
|
||||
for(EditorWrapper *edit : m_Editors)
|
||||
{
|
||||
EditorWrapper *wrap = (EditorWrapper *)edit;
|
||||
|
||||
if(!wrap->checkAllowClose())
|
||||
if(!edit->checkAllowClose())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1482,7 +1479,7 @@ void PythonShell::updateScriptOutput(bool fullRefresh)
|
||||
lastDisplayedLine = scriptOutputLines.size();
|
||||
}
|
||||
|
||||
bool PythonShell::saveEditorAs(ScintillaEdit *editor)
|
||||
bool PythonShell::saveEditorAs(EditorWrapper *editor)
|
||||
{
|
||||
QString filename = RDDialog::getSaveFileName(this, tr("Save Python Script"), QString(),
|
||||
tr("Python scripts (*.py)"));
|
||||
@@ -1491,9 +1488,9 @@ bool PythonShell::saveEditorAs(ScintillaEdit *editor)
|
||||
return saveEditor(editor, filename);
|
||||
}
|
||||
|
||||
bool PythonShell::saveEditor(ScintillaEdit *editor, QString filename)
|
||||
bool PythonShell::saveEditor(EditorWrapper *editor, QString filename)
|
||||
{
|
||||
QString oldFilename = getEditorFilename(editor);
|
||||
QString oldFilename = editor->filename();
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
QDir dirinfo = QFileInfo(filename).dir();
|
||||
@@ -1505,7 +1502,9 @@ bool PythonShell::saveEditor(ScintillaEdit *editor, QString filename)
|
||||
// remove the path from watching first so we don't get a notification from the write itself
|
||||
m_Watcher->removePath(oldFilename);
|
||||
|
||||
QString text = QString::fromUtf8(editor->getText(editor->textLength() + 1));
|
||||
ScintillaEdit *sc = editor->scintilla();
|
||||
|
||||
QString text = QString::fromUtf8(sc->getText(sc->textLength() + 1));
|
||||
text.remove(QLatin1Char('\r'));
|
||||
f.write(text.toUtf8());
|
||||
|
||||
@@ -1516,7 +1515,7 @@ bool PythonShell::saveEditor(ScintillaEdit *editor, QString filename)
|
||||
// from identifying our own writes as an external modification.
|
||||
QTimer::singleShot(200, [this, filename]() { m_Watcher->addPath(filename); });
|
||||
|
||||
setEditorFilename(editor, filename);
|
||||
editor->setFilename(filename);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -1535,6 +1534,15 @@ bool PythonShell::saveEditor(ScintillaEdit *editor, QString filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
void PythonShell::removeEditor(EditorWrapper *editor)
|
||||
{
|
||||
hideFunccompleteTooltip();
|
||||
m_Watcher->removePath(editor->filename());
|
||||
m_Editors.removeOne(editor);
|
||||
m_Scintillas.removeOne(editor->scintilla());
|
||||
updateEditorCloseButton();
|
||||
}
|
||||
|
||||
void PythonShell::extensionLoaded(const QString &extension)
|
||||
{
|
||||
ui->outputContext->addItem(tr("Extension %1").arg(extension));
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
class PythonContext;
|
||||
class QTextEdit;
|
||||
class RDToolTip;
|
||||
class RDLabel;
|
||||
class QTimer;
|
||||
class QCompleter;
|
||||
class FindReplace;
|
||||
@@ -48,14 +49,33 @@ struct CaptureContextInvoker;
|
||||
|
||||
class PythonShell;
|
||||
|
||||
class EditorWrapper : public ScintillaEdit
|
||||
class EditorWrapper : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
PythonShell *m_PyShell;
|
||||
|
||||
ScintillaEdit *m_Scintilla;
|
||||
RDLabel *m_Warning;
|
||||
|
||||
QString m_Filename;
|
||||
bool m_Modified = false;
|
||||
|
||||
void updateTitle();
|
||||
|
||||
public:
|
||||
EditorWrapper(PythonShell *parent);
|
||||
virtual ~EditorWrapper();
|
||||
|
||||
ScintillaEdit *scintilla() { return m_Scintilla; }
|
||||
|
||||
QString filename() { return m_Filename; }
|
||||
void setFilename(QString filename);
|
||||
|
||||
void setWarning(QString text);
|
||||
|
||||
bool isModified() { return m_Modified; }
|
||||
void markModified(bool modified);
|
||||
|
||||
public slots:
|
||||
bool checkAllowClose();
|
||||
@@ -94,8 +114,10 @@ public:
|
||||
QVariant persistData();
|
||||
void setPersistData(const QVariant &persistData);
|
||||
|
||||
bool saveEditorAs(ScintillaEdit *editor);
|
||||
bool saveEditor(ScintillaEdit *editor, QString filename);
|
||||
bool saveEditorAs(EditorWrapper *editor);
|
||||
bool saveEditor(EditorWrapper *editor, QString filename);
|
||||
|
||||
void removeEditor(EditorWrapper *editor);
|
||||
|
||||
private slots:
|
||||
// automatic slots
|
||||
@@ -183,14 +205,15 @@ private:
|
||||
size_t lastDisplayedLine = 0;
|
||||
|
||||
QList<ScintillaEdit *> m_Scintillas;
|
||||
QList<EditorWrapper *> m_Editors;
|
||||
|
||||
FindReplace *m_FindReplace;
|
||||
ScintillaEdit *m_FindResults = NULL;
|
||||
|
||||
void setupTabs();
|
||||
|
||||
ScintillaEdit *curEditor();
|
||||
ScintillaEdit *makeEditor(rdcstr filename);
|
||||
EditorWrapper *curEditor();
|
||||
void makeEditor(rdcstr filename, rdcstr text);
|
||||
|
||||
void updateEditorCloseButton();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user