Add a find/replace tool for use with Scintilla

This commit is contained in:
baldurk
2017-02-16 17:10:07 +00:00
parent e336cab5ae
commit fa04d5a72e
8 changed files with 1181 additions and 32 deletions
+194
View File
@@ -0,0 +1,194 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "FindReplace.h"
#include <QKeyEvent>
#include <QLineEdit>
#include "ui_FindReplace.h"
FindReplace::FindReplace(QWidget *parent) : QFrame(parent), ui(new Ui::FindReplace)
{
ui->setupUi(this);
ui->searchContext->setCurrentIndex(FindReplace::File);
// default to just find
setReplaceMode(false);
setDirection(FindReplace::Down);
QObject::connect(ui->findText->lineEdit(), &QLineEdit::returnPressed, this,
&FindReplace::on_find_clicked);
QObject::connect(ui->replaceText->lineEdit(), &QLineEdit::returnPressed, this,
&FindReplace::on_replace_clicked);
}
FindReplace::~FindReplace()
{
delete ui;
}
bool FindReplace::replaceMode()
{
return ui->replaceMode->isChecked();
}
FindReplace::SearchContext FindReplace::context()
{
return (FindReplace::SearchContext)ui->searchContext->currentIndex();
}
FindReplace::SearchDirection FindReplace::direction()
{
return ui->searchUp->isChecked() ? FindReplace::Up : FindReplace::Down;
}
bool FindReplace::matchCase()
{
return ui->matchCase->isChecked();
}
bool FindReplace::matchWord()
{
return ui->matchWord->isChecked();
}
bool FindReplace::regexp()
{
return ui->regexp->isChecked();
}
QString FindReplace::findText()
{
return ui->findText->currentText();
}
QString FindReplace::replaceText()
{
return ui->replaceText->currentText();
}
void FindReplace::allowUserModeChange(bool allow)
{
ui->modeChangeFrame->setVisible(allow);
}
void FindReplace::setReplaceMode(bool replacing)
{
ui->replaceLabel->setVisible(replacing);
ui->replaceText->setVisible(replacing);
ui->replace->setVisible(replacing);
ui->replaceAll->setVisible(replacing);
ui->findMode->setChecked(!replacing);
ui->replaceMode->setChecked(replacing);
setWindowTitle(replacing ? tr("Find && Replace") : tr("Find"));
}
void FindReplace::setDirection(SearchDirection dir)
{
if(dir == FindReplace::Up)
ui->searchUp->setChecked(true);
else
ui->searchDown->setChecked(true);
}
void FindReplace::takeFocus()
{
ui->findText->setFocus();
}
void FindReplace::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_F3)
{
SearchDirection dir = direction();
if(event->modifiers() & Qt::ShiftModifier)
ui->searchUp->setChecked(true);
else
ui->searchDown->setChecked(true);
emit performFind();
if(dir == FindReplace::Up)
ui->searchUp->setChecked(true);
else
ui->searchDown->setChecked(true);
}
}
void FindReplace::addHistory(QComboBox *combo)
{
QString text = combo->currentText();
for(int i = 0; i < combo->count(); i++)
{
if(combo->itemText(i) == text)
{
// remove the item so we can bump it up to the top of the list
combo->removeItem(i);
break;
}
}
combo->insertItem(0, text);
combo->setCurrentText(text);
}
void FindReplace::on_find_clicked()
{
addHistory(ui->findText);
emit performFind();
}
void FindReplace::on_findAll_clicked()
{
addHistory(ui->findText);
emit performFindAll();
}
void FindReplace::on_replace_clicked()
{
addHistory(ui->findText);
addHistory(ui->replaceText);
emit performReplace();
}
void FindReplace::on_replaceAll_clicked()
{
addHistory(ui->findText);
addHistory(ui->replaceText);
emit performReplaceAll();
}
void FindReplace::on_findMode_clicked()
{
setReplaceMode(false);
}
void FindReplace::on_replaceMode_clicked()
{
setReplaceMode(true);
}
+94
View File
@@ -0,0 +1,94 @@
/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2017 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#pragma once
#include <QFrame>
namespace Ui
{
class FindReplace;
}
class QComboBox;
class FindReplace : public QFrame
{
Q_OBJECT
public:
explicit FindReplace(QWidget *parent = 0);
~FindReplace();
enum SearchContext
{
File,
AllFiles,
};
enum SearchDirection
{
Up,
Down,
};
bool replaceMode();
SearchContext context();
SearchDirection direction();
bool matchCase();
bool matchWord();
bool regexp();
QString findText();
QString replaceText();
public slots:
void allowUserModeChange(bool allow);
void setReplaceMode(bool replacing);
void setDirection(SearchDirection dir);
void takeFocus();
signals:
void performFind();
void performFindAll();
void performReplace();
void performReplaceAll();
private slots:
// automatic slots
void on_find_clicked();
void on_findAll_clicked();
void on_replace_clicked();
void on_replaceAll_clicked();
void on_findMode_clicked();
void on_replaceMode_clicked();
private:
void keyPressEvent(QKeyEvent *event) override;
Ui::FindReplace *ui;
void addHistory(QComboBox *combo);
};
+335
View File
@@ -0,0 +1,335 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FindReplace</class>
<widget class="QFrame" name="FindReplace">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>321</width>
<height>352</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Context</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="2">
<widget class="QLabel" name="searchContextLabel">
<property name="text">
<string>Search in:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="matchCase">
<property name="text">
<string>Match case</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="searchContext">
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Current File</string>
</property>
</item>
<item>
<property name="text">
<string>All Files</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="regexp">
<property name="text">
<string>Use Regular Expressions</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="matchWord">
<property name="text">
<string>Match whole word</string>
</property>
</widget>
</item>
<item row="1" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="6" column="1">
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<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 row="2" column="1">
<widget class="QPushButton" name="replaceAll">
<property name="text">
<string>Replace All</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="replace">
<property name="text">
<string>Replace</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="find">
<property name="text">
<string>Find Next</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="findAll">
<property name="text">
<string>Find All</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QFrame" name="modeChangeFrame">
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QToolButton" name="findMode">
<property name="text">
<string>Find</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="replaceMode">
<property name="text">
<string>Replace</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="8" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Direction</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="searchUp">
<property name="text">
<string>Up</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="searchDown">
<property name="text">
<string>Down</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QFrame" name="frame_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="findLabel">
<property name="text">
<string>Find</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="replaceLabel">
<property name="text">
<string>Replace with</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="findText">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="replaceText">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAtTop</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+486 -28
View File
@@ -29,7 +29,9 @@
#include "3rdparty/scintilla/include/SciLexer.h"
#include "3rdparty/scintilla/include/qt/ScintillaEdit.h"
#include "3rdparty/toolwindowmanager/ToolWindowManager.h"
#include "3rdparty/toolwindowmanager/ToolWindowManagerArea.h"
#include "Code/ScintillaSyntax.h"
#include "Widgets/FindReplace.h"
#include "Windows/PipelineState/PipelineStateViewer.h"
#include "ui_ShaderViewer.h"
@@ -57,9 +59,34 @@ ShaderViewer::ShaderViewer(CaptureContext &ctx, QWidget *parent)
{
ui->setupUi(this);
// we create this up front so its state stays persistent as much as possible.
m_FindReplace = new FindReplace(this);
m_FindResults = MakeEditor("findresults", "", SCLEX_NULL);
m_FindResults->setReadOnly(true);
m_FindResults->setWindowTitle("Find Results");
// remove margins
m_FindResults->setMarginWidthN(0, 0);
m_FindResults->setMarginWidthN(1, 0);
m_FindResults->setMarginWidthN(2, 0);
QObject::connect(m_FindReplace, &FindReplace::performFind, this, &ShaderViewer::performFind);
QObject::connect(m_FindReplace, &FindReplace::performFindAll, this, &ShaderViewer::performFindAll);
QObject::connect(m_FindReplace, &FindReplace::performReplace, this, &ShaderViewer::performReplace);
QObject::connect(m_FindReplace, &FindReplace::performReplaceAll, this,
&ShaderViewer::performReplaceAll);
ui->docking->addToolWindow(m_FindReplace, ToolWindowManager::NoArea);
ui->docking->setToolWindowProperties(m_FindReplace, ToolWindowManager::HideOnClose);
ui->docking->addToolWindow(m_FindResults, ToolWindowManager::NoArea);
ui->docking->setToolWindowProperties(m_FindResults, ToolWindowManager::HideOnClose);
{
m_DisassemblyView =
MakeEditor("scintillaDisassem", "", m_Ctx.APIProps().pipelineType == eGraphicsAPI_Vulkan);
MakeEditor("scintillaDisassem", "",
m_Ctx.APIProps().pipelineType == eGraphicsAPI_Vulkan ? SCLEX_GLSL : SCLEX_HLSL);
m_DisassemblyView->setReadOnly(true);
m_DisassemblyView->setWindowTitle(tr("Disassembly"));
@@ -89,10 +116,11 @@ ShaderViewer::ShaderViewer(CaptureContext &ctx, QWidget *parent)
m_Scintillas.push_back(m_DisassemblyView);
ui->docking->addToolWindow(m_DisassemblyView, ToolWindowManager::EmptySpace);
ui->docking->setToolWindowProperties(m_DisassemblyView, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
m_DisassemblyView,
ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
}
ui->docking->setAllowFloatingWindow(false);
ui->docking->setRubberBandLineWidth(50);
QVBoxLayout *layout = new QVBoxLayout(this);
@@ -139,8 +167,13 @@ void ShaderViewer::editShader(bool customShader, const QString &entryPoint, cons
ScintillaEdit *scintilla = AddFileScintilla(name, text);
scintilla->setReadOnly(false);
QObject::connect(m_DisassemblyView, &ScintillaEdit::keyPressed, this,
&ShaderViewer::editable_keyPressed);
QObject::connect(scintilla, &ScintillaEdit::keyPressed, this, &ShaderViewer::editable_keyPressed);
QObject::connect(scintilla, &ScintillaEdit::modified, [this](int type, int, int, int,
const QByteArray &, int, int, int) {
if(type & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT | SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE))
m_FindState = FindState();
});
// TODO - shortcuts
QObject::connect(new QShortcut(QKeySequence(Qt::Key_S | Qt::ControlModifier), scintilla),
@@ -164,7 +197,7 @@ void ShaderViewer::editShader(bool customShader, const QString &entryPoint, cons
if(files.count() > 2)
addFileList();
m_Errors = MakeEditor("errors", "", false);
m_Errors = MakeEditor("errors", "", SCLEX_NULL);
m_Errors->setReadOnly(true);
m_Errors->setWindowTitle("Errors");
@@ -178,7 +211,8 @@ void ShaderViewer::editShader(bool customShader, const QString &entryPoint, cons
ui->docking->addToolWindow(
m_Errors, ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
ui->docking->areaOf(m_Scintillas.front()), 0.2f));
ui->docking->setToolWindowProperties(m_Errors, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
m_Errors, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
}
void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderReflection *shader,
@@ -190,6 +224,9 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
m_Trace = trace;
m_Stage = stage;
// no replacing allowed, stay in find mode
m_FindReplace->allowUserModeChange(false);
if(!shader || !bind)
m_Trace = NULL;
@@ -272,19 +309,22 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ui->docking->addToolWindow(
ui->watch, ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
ui->docking->areaOf(m_DisassemblyView), 0.25f));
ui->docking->setToolWindowProperties(ui->watch, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
ui->watch, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
ui->variables->setWindowTitle(tr("Variables"));
ui->docking->addToolWindow(
ui->variables,
ToolWindowManager::AreaReference(ToolWindowManager::AddTo, ui->docking->areaOf(ui->watch)));
ui->docking->setToolWindowProperties(ui->variables, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
ui->variables, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
ui->constants->setWindowTitle(tr("Constants && Resources"));
ui->docking->addToolWindow(
ui->constants, ToolWindowManager::AreaReference(ToolWindowManager::LeftOf,
ui->docking->areaOf(ui->variables), 0.5f));
ui->docking->setToolWindowProperties(ui->constants, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
ui->constants, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
m_DisassemblyView->setMarginWidthN(1, 20);
@@ -390,13 +430,15 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR
ui->docking->addToolWindow(ui->inputSig, ToolWindowManager::AreaReference(
ToolWindowManager::BottomOf,
ui->docking->areaOf(m_DisassemblyView), 0.2f));
ui->docking->setToolWindowProperties(ui->inputSig, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
ui->inputSig, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
ui->outputSig->setWindowTitle(tr("Output Signature"));
ui->docking->addToolWindow(
ui->outputSig, ToolWindowManager::AreaReference(ToolWindowManager::RightOf,
ui->docking->areaOf(ui->inputSig), 0.5f));
ui->docking->setToolWindowProperties(ui->outputSig, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
ui->outputSig, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
}
}
@@ -426,7 +468,9 @@ void ShaderViewer::OnEventChanged(uint32_t eventID)
ScintillaEdit *ShaderViewer::AddFileScintilla(const QString &name, const QString &text)
{
ScintillaEdit *scintilla = MakeEditor("scintilla" + name, text, true);
ScintillaEdit *scintilla =
MakeEditor("scintilla" + name, text,
m_Ctx.APIProps().localRenderer == eGraphicsAPI_OpenGL ? SCLEX_GLSL : SCLEX_HLSL);
scintilla->setReadOnly(true);
scintilla->setWindowTitle(name);
((QWidget *)scintilla)->setProperty("name", name);
@@ -440,14 +484,15 @@ ScintillaEdit *ShaderViewer::AddFileScintilla(const QString &name, const QString
ui->docking->areaOf(m_Scintillas[0]));
ui->docking->addToolWindow(scintilla, ref);
ui->docking->setToolWindowProperties(scintilla, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
scintilla, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
m_Scintillas.push_back(scintilla);
return scintilla;
}
ScintillaEdit *ShaderViewer::MakeEditor(const QString &name, const QString &text, bool src)
ScintillaEdit *ShaderViewer::MakeEditor(const QString &name, const QString &text, int lang)
{
ScintillaEdit *ret = new ScintillaEdit(this);
@@ -468,11 +513,16 @@ ScintillaEdit *ShaderViewer::MakeEditor(const QString &name, const QString &text
ret->setObjectName(name);
// C# DarkGreen
ret->indicSetFore(4, SCINTILLA_COLOUR(0, 100, 0));
ret->indicSetStyle(4, INDIC_ROUNDBOX);
ret->indicSetFore(INDICATOR_REGHIGHLIGHT, SCINTILLA_COLOUR(0, 100, 0));
ret->indicSetStyle(INDICATOR_REGHIGHLIGHT, INDIC_ROUNDBOX);
ConfigureSyntax(ret,
m_Ctx.APIProps().localRenderer == eGraphicsAPI_OpenGL ? SCLEX_GLSL : SCLEX_HLSL);
// set up find result highlight style
ret->indicSetFore(INDICATOR_FINDRESULT, SCINTILLA_COLOUR(200, 200, 127));
ret->indicSetStyle(INDICATOR_FINDRESULT, INDIC_FULLBOX);
ret->indicSetAlpha(INDICATOR_FINDRESULT, 50);
ret->indicSetOutlineAlpha(INDICATOR_FINDRESULT, 80);
ConfigureSyntax(ret, lang);
ret->setTabWidth(4);
@@ -488,12 +538,25 @@ ScintillaEdit *ShaderViewer::MakeEditor(const QString &name, const QString &text
void ShaderViewer::readonly_keyPressed(QKeyEvent *event)
{
// TODO find
if(event->key() == Qt::Key_F && (event->modifiers() & Qt::ControlModifier))
{
m_FindReplace->setReplaceMode(false);
on_findReplace_clicked();
}
if(event->key() == Qt::Key_F3)
{
find((event->modifiers() & Qt::ShiftModifier) == 0);
}
}
void ShaderViewer::editable_keyPressed(QKeyEvent *event)
{
// TODO replace
if(event->key() == Qt::Key_H && (event->modifiers() & Qt::ControlModifier))
{
m_FindReplace->setReplaceMode(true);
on_findReplace_clicked();
}
}
void ShaderViewer::disassembly_buttonReleased(QMouseEvent *event)
@@ -697,7 +760,8 @@ void ShaderViewer::addFileList()
ui->docking->addToolWindow(
list, ToolWindowManager::AreaReference(ToolWindowManager::LeftOf,
ui->docking->areaOf(m_Scintillas.front()), 0.2f));
ui->docking->setToolWindowProperties(list, ToolWindowManager::HideCloseButton);
ui->docking->setToolWindowProperties(
list, ToolWindowManager::HideCloseButton | ToolWindowManager::DisallowFloatWindow);
}
void ShaderViewer::updateDebugging()
@@ -733,12 +797,7 @@ void ShaderViewer::updateDebugging()
int pos = m_DisassemblyView->positionFromLine(i);
m_DisassemblyView->setSelection(pos, pos);
int firstLine = m_DisassemblyView->firstVisibleLine();
int linesVisible = m_DisassemblyView->linesOnScreen();
if(m_DisassemblyView->isVisible() && (i < firstLine || i > (firstLine + linesVisible)))
m_DisassemblyView->scrollCaret();
ensureLineScrolled(m_DisassemblyView, i);
break;
}
}
@@ -907,6 +966,15 @@ void ShaderViewer::updateDebugging()
// TODO watch registers
}
void ShaderViewer::ensureLineScrolled(ScintillaEdit *s, int line)
{
int firstLine = s->firstVisibleLine();
int linesVisible = s->linesOnScreen();
if(s->isVisible() && (line < firstLine || line > (firstLine + linesVisible)))
s->scrollCaret();
}
int ShaderViewer::currentStep()
{
return m_CurrentStep;
@@ -990,6 +1058,18 @@ void ShaderViewer::showErrors(const QString &errors)
void ShaderViewer::on_findReplace_clicked()
{
if(m_FindReplace->isVisible())
{
ToolWindowManager::raiseToolWindow(m_FindReplace);
}
else
{
ui->docking->moveToolWindow(
m_FindReplace, ToolWindowManager::AreaReference(ToolWindowManager::NewFloatingArea));
ui->docking->setToolWindowProperties(m_FindReplace, ToolWindowManager::HideOnClose);
}
ui->docking->areaOf(m_FindReplace)->parentWidget()->activateWindow();
m_FindReplace->takeFocus();
}
void ShaderViewer::on_save_clicked()
@@ -1027,3 +1107,381 @@ void ShaderViewer::on_floatView_clicked()
updateDebugging();
}
ScintillaEdit *ShaderViewer::currentScintilla()
{
ScintillaEdit *cur = qobject_cast<ScintillaEdit *>(QApplication::focusWidget());
if(cur == NULL)
{
for(ScintillaEdit *s : m_Scintillas)
{
if(s->isVisible())
{
cur = s;
break;
}
}
}
return cur;
}
ScintillaEdit *ShaderViewer::nextScintilla(ScintillaEdit *cur)
{
for(int i = 0; i < m_Scintillas.count(); i++)
{
if(m_Scintillas[i] == cur)
{
if(i + 1 < m_Scintillas.count())
return m_Scintillas[i + 1];
return m_Scintillas[0];
}
}
if(!m_Scintillas.isEmpty())
return m_Scintillas[0];
return NULL;
}
void ShaderViewer::find(bool down)
{
ScintillaEdit *cur = currentScintilla();
if(!cur)
return;
QString find = m_FindReplace->findText();
sptr_t flags = 0;
if(m_FindReplace->matchCase())
flags |= SCFIND_MATCHCASE;
if(m_FindReplace->matchWord())
flags |= SCFIND_WHOLEWORD;
if(m_FindReplace->regexp())
flags |= SCFIND_REGEXP | SCFIND_POSIX;
FindReplace::SearchContext context = m_FindReplace->context();
QString findHash = QString("%1%2%3").arg(find).arg(flags).arg((int)context);
if(findHash != m_FindState.hash)
{
m_FindState.hash = findHash;
m_FindState.start = 0;
m_FindState.end = cur->length();
m_FindState.offset = cur->currentPos();
}
int start = m_FindState.start + m_FindState.offset;
int end = m_FindState.end;
if(!down)
end = m_FindState.start;
QPair<int, int> result = cur->findText(flags, find.toUtf8().data(), start, end);
m_FindState.prevResult = result;
if(result.first == -1)
{
sptr_t maxOffset = down ? 0 : m_FindState.end;
// if we're at offset 0 searching down, there are no results. Same for offset max and searching
// up
if(m_FindState.offset == maxOffset)
return;
// otherwise, we can wrap the search around
if(context == FindReplace::AllFiles)
{
cur = nextScintilla(cur);
ToolWindowManager::raiseToolWindow(cur);
cur->activateWindow();
cur->QWidget::setFocus();
}
m_FindState.offset = maxOffset;
start = m_FindState.start + m_FindState.offset;
end = m_FindState.end;
if(!down)
end = m_FindState.start;
result = cur->findText(flags, find.toUtf8().data(), start, end);
m_FindState.prevResult = result;
if(result.first == -1)
return;
}
cur->setSelection(result.first, result.second);
ensureLineScrolled(cur, cur->lineFromPosition(result.first));
if(down)
m_FindState.offset = result.second - m_FindState.start;
else
m_FindState.offset = result.first - m_FindState.start;
}
void ShaderViewer::performFind()
{
find(m_FindReplace->direction() == FindReplace::Down);
}
void ShaderViewer::performFindAll()
{
ScintillaEdit *cur = currentScintilla();
if(!cur)
return;
QString find = m_FindReplace->findText();
sptr_t flags = 0;
QString results = tr("Find all \"%1\"").arg(find);
if(m_FindReplace->matchCase())
{
flags |= SCFIND_MATCHCASE;
results += tr(", Match case");
}
if(m_FindReplace->matchWord())
{
flags |= SCFIND_WHOLEWORD;
results += tr(", Match whole word");
}
if(m_FindReplace->regexp())
{
flags |= SCFIND_REGEXP | SCFIND_POSIX;
results += tr(", with Regular Expressions");
}
FindReplace::SearchContext context = m_FindReplace->context();
if(context == FindReplace::File)
results += tr(", in current file\n");
else
results += tr(", in all files\n");
// trash the find state for any incremental finds
m_FindState = FindState();
QList<ScintillaEdit *> scintillas = m_Scintillas;
if(context == FindReplace::File)
scintillas = {cur};
QList<QPair<int, int>> resultList;
QByteArray findUtf8 = find.toUtf8();
for(ScintillaEdit *s : scintillas)
{
sptr_t start = 0;
sptr_t end = s->length();
s->setIndicatorCurrent(INDICATOR_FINDRESULT);
s->indicatorClearRange(start, end);
if(findUtf8.isEmpty())
continue;
QPair<int, int> result;
do
{
result = s->findText(flags, findUtf8.data(), start, end);
if(result.first >= 0)
{
int line = s->lineFromPosition(result.first);
sptr_t lineStart = s->positionFromLine(line);
sptr_t lineEnd = s->lineEndPosition(line);
s->indicatorFillRange(result.first, result.second - result.first);
QString lineText = QString::fromUtf8(s->textRange(lineStart, lineEnd));
results += QString(" %1(%2): ").arg(s->windowTitle()).arg(line, 4);
int startPos = results.length();
results += lineText;
results += "\n";
resultList.push_back(
qMakePair(result.first - lineStart + startPos, result.second - lineStart + startPos));
}
start = result.second;
} while(result.first >= 0);
}
if(findUtf8.isEmpty())
return;
results += tr("Matching lines: %1").arg(resultList.count());
m_FindResults->setReadOnly(false);
m_FindResults->setText(results.toUtf8().data());
m_FindResults->setIndicatorCurrent(INDICATOR_FINDRESULT);
for(QPair<int, int> r : resultList)
m_FindResults->indicatorFillRange(r.first, r.second - r.first);
m_FindResults->setReadOnly(true);
if(m_FindResults->isVisible())
{
ToolWindowManager::raiseToolWindow(m_FindResults);
}
else
{
ui->docking->moveToolWindow(m_FindResults,
ToolWindowManager::AreaReference(ToolWindowManager::BottomOf,
ui->docking->areaOf(cur), 0.2f));
ui->docking->setToolWindowProperties(m_FindResults, ToolWindowManager::HideOnClose);
}
}
void ShaderViewer::performReplace()
{
ScintillaEdit *cur = currentScintilla();
if(!cur)
return;
QString find = m_FindReplace->findText();
if(find.isEmpty())
return;
sptr_t flags = 0;
if(m_FindReplace->matchCase())
flags |= SCFIND_MATCHCASE;
if(m_FindReplace->matchWord())
flags |= SCFIND_WHOLEWORD;
if(m_FindReplace->regexp())
flags |= SCFIND_REGEXP | SCFIND_POSIX;
FindReplace::SearchContext context = m_FindReplace->context();
QString findHash = QString("%1%2%3").arg(find).arg(flags).arg((int)context);
// if we didn't have a valid previous find, just do a find and bail
if(findHash != m_FindState.hash)
{
performFind();
return;
}
if(m_FindState.prevResult.first == -1)
return;
cur->setTargetRange(m_FindState.prevResult.first, m_FindState.prevResult.second);
FindState save = m_FindState;
QString replaceText = m_FindReplace->replaceText();
// otherwise we have a valid previous find. Do the replace now
// note this will invalidate the find state (as most user operations would), so we save/restore
// the state
if(m_FindReplace->regexp())
cur->replaceTargetRE(-1, replaceText.toUtf8().data());
else
cur->replaceTarget(-1, replaceText.toUtf8().data());
m_FindState = save;
// adjust the offset if we replaced text and it went up or down in size
m_FindState.offset += (replaceText.count() - find.count());
// move to the next result
performFind();
}
void ShaderViewer::performReplaceAll()
{
ScintillaEdit *cur = currentScintilla();
if(!cur)
return;
QString find = m_FindReplace->findText();
QString replace = m_FindReplace->replaceText();
if(find.isEmpty())
return;
sptr_t flags = 0;
if(m_FindReplace->matchCase())
flags |= SCFIND_MATCHCASE;
if(m_FindReplace->matchWord())
flags |= SCFIND_WHOLEWORD;
if(m_FindReplace->regexp())
flags |= SCFIND_REGEXP | SCFIND_POSIX;
FindReplace::SearchContext context = m_FindReplace->context();
(void)context;
// trash the find state for any incremental finds
m_FindState = FindState();
QList<ScintillaEdit *> scintillas = m_Scintillas;
if(context == FindReplace::File)
scintillas = {cur};
int numReplacements = 1;
for(ScintillaEdit *s : scintillas)
{
sptr_t start = 0;
sptr_t end = s->length();
QPair<int, int> result;
QByteArray findUtf8 = find.toUtf8();
QByteArray replaceUtf8 = replace.toUtf8();
do
{
result = s->findText(flags, findUtf8.data(), start, end);
if(result.first >= 0)
{
s->setTargetRange(result.first, result.second);
if(m_FindReplace->regexp())
s->replaceTargetRE(-1, replaceUtf8.data());
else
s->replaceTarget(-1, replaceUtf8.data());
numReplacements++;
}
start = result.second + (replaceUtf8.count() - findUtf8.count());
} while(result.first >= 0);
}
RDDialog::information(
this, tr("Replace all"),
tr("%1 replacements made in %2 files").arg(numReplacements).arg(scintillas.count()));
}
+36 -1
View File
@@ -36,6 +36,7 @@ class ShaderViewer;
struct ShaderDebugTrace;
struct ShaderReflection;
class ScintillaEdit;
class FindReplace;
// from Scintilla
typedef intptr_t sptr_t;
@@ -101,6 +102,10 @@ private slots:
void readonly_keyPressed(QKeyEvent *event);
void editable_keyPressed(QKeyEvent *event);
void disassembly_buttonReleased(QMouseEvent *event);
void performFind();
void performFindAll();
void performReplace();
void performReplaceAll();
public slots:
bool stepBack();
@@ -124,8 +129,27 @@ private:
ShaderStageType m_Stage;
ScintillaEdit *m_DisassemblyView = NULL;
ScintillaEdit *m_Errors = NULL;
ScintillaEdit *m_FindResults = NULL;
QList<ScintillaEdit *> m_Scintillas;
FindReplace *m_FindReplace;
struct FindState
{
// hash identifies when the search has changed
QString hash;
// the range identified when the search first occurred (for incremental find/replace)
sptr_t start = 0;
sptr_t end = 0;
// the current offset where to search from next time, relative to above range
sptr_t offset = 0;
// the last result
QPair<int, int> prevResult;
} m_FindState;
SaveMethod m_SaveCallback;
CloseMethod m_CloseCallback;
@@ -137,14 +161,25 @@ private:
static const int BREAKPOINT_MARKER = 2;
static const int FINISHED_MARKER = 4;
static const int INDICATOR_FINDRESULT = 0;
static const int INDICATOR_REGHIGHLIGHT = 1;
void addFileList();
ScintillaEdit *MakeEditor(const QString &name, const QString &text, bool src);
ScintillaEdit *MakeEditor(const QString &name, const QString &text, int lang);
ScintillaEdit *AddFileScintilla(const QString &name, const QString &text);
ScintillaEdit *currentScintilla();
ScintillaEdit *nextScintilla(ScintillaEdit *cur);
int instructionForLine(sptr_t line);
void updateDebugging();
void ensureLineScrolled(ScintillaEdit *s, int i);
void find(bool down);
void runTo(int runToInstruction, bool forward, ShaderDebugStateFlags condition = eShaderDbg_None);
QString stringRep(const ShaderVariable &var, bool useType);
+6 -3
View File
@@ -147,7 +147,8 @@ SOURCES += Code/qrenderdoc.cpp \
Windows/Dialogs/RemoteManager.cpp \
Windows/PixelHistoryView.cpp \
Widgets/PipelineFlowChart.cpp \
Windows/Dialogs/EnvironmentEditor.cpp
Windows/Dialogs/EnvironmentEditor.cpp \
Widgets/FindReplace.cpp
HEADERS += Code/CaptureContext.h \
Code/qprocessinfo.h \
@@ -197,7 +198,8 @@ HEADERS += Code/CaptureContext.h \
Windows/Dialogs/RemoteManager.h \
Windows/PixelHistoryView.h \
Widgets/PipelineFlowChart.h \
Windows/Dialogs/EnvironmentEditor.h
Windows/Dialogs/EnvironmentEditor.h \
Widgets/FindReplace.h
FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/MainWindow.ui \
@@ -226,7 +228,8 @@ FORMS += Windows/Dialogs/AboutDialog.ui \
Windows/Dialogs/VirtualFileDialog.ui \
Windows/Dialogs/RemoteManager.ui \
Windows/PixelHistoryView.ui \
Windows/Dialogs/EnvironmentEditor.ui
Windows/Dialogs/EnvironmentEditor.ui \
Widgets/FindReplace.ui
RESOURCES += Resources/resources.qrc
+15
View File
@@ -631,6 +631,7 @@
<ClCompile Include="$(IntDir)generated\moc_AboutDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_APIInspector.cpp" />
<ClCompile Include="$(IntDir)generated\moc_BufferFormatSpecifier.cpp" />
<ClCompile Include="$(IntDir)generated\moc_FindReplace.cpp" />
<ClCompile Include="$(IntDir)generated\moc_BufferViewer.cpp" />
<ClCompile Include="$(IntDir)generated\moc_CaptureDialog.cpp" />
<ClCompile Include="$(IntDir)generated\moc_ConstantBufferPreviewer.cpp" />
@@ -687,6 +688,7 @@
<ClCompile Include="$(IntDir)generated\moc_VulkanPipelineStateViewer.cpp" />
<ClCompile Include="$(IntDir)generated\qrc_resources.cpp" />
<ClCompile Include="Widgets\BufferFormatSpecifier.cpp" />
<ClCompile Include="Widgets\FindReplace.cpp" />
<ClCompile Include="Widgets\Extended\RDListWidget.cpp" />
<ClCompile Include="Widgets\Extended\RDTableView.cpp" />
<ClCompile Include="Widgets\Extended\RDTableWidget.cpp" />
@@ -850,6 +852,7 @@
<ClInclude Include="$(IntDir)generated\ui_AboutDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_APIInspector.h" />
<ClInclude Include="$(IntDir)generated\ui_BufferFormatSpecifier.h" />
<ClInclude Include="$(IntDir)generated\ui_FindReplace.h" />
<ClInclude Include="$(IntDir)generated\ui_BufferViewer.h" />
<ClInclude Include="$(IntDir)generated\ui_CaptureDialog.h" />
<ClInclude Include="$(IntDir)generated\ui_ConstantBufferPreviewer.h" />
@@ -895,6 +898,12 @@
<Message>MOC %(Filename).h</Message>
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
</CustomBuild>
<CustomBuild Include="Widgets\FindReplace.h">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I$(ProjectDir) -I$(SolutionDir)\renderdoc\api\replay -I$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015 -I$(ProjectDir)3rdparty\qt\$(Platform)\include -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore %(Fullpath) -o $(IntDir)generated\moc_%(Filename).cpp</Command>
<Message>MOC %(Filename).h</Message>
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
</CustomBuild>
<CustomBuild Include="Widgets\CustomPaintWidget.h">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I$(ProjectDir) -I$(SolutionDir)\renderdoc\api\replay -I$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015 -I$(ProjectDir)3rdparty\qt\$(Platform)\include -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtWidgets -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtGui -I$(ProjectDir)3rdparty\qt\$(Platform)\include\QtCore %(Fullpath) -o $(IntDir)generated\moc_%(Filename).cpp</Command>
@@ -1143,6 +1152,12 @@
<Message>UIC %(Filename).ui</Message>
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Widgets\FindReplace.ui">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe %(Fullpath) -o $(IntDir)generated\ui_%(Filename).h</Command>
<Message>UIC %(Filename).ui</Message>
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
</CustomBuild>
<CustomBuild Include="Widgets\ResourcePreview.ui">
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
<Command>$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe %(Fullpath) -o $(IntDir)generated\ui_%(Filename).h</Command>
@@ -537,6 +537,12 @@
<ClCompile Include="Windows\Dialogs\EnvironmentEditor.cpp">
<Filter>Windows\Dialogs</Filter>
</ClCompile>
<ClCompile Include="Widgets\FindReplace.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)generated\moc_FindReplace.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
@@ -830,6 +836,9 @@
<ClInclude Include="$(IntDir)generated\ui_VulkanPipelineStateViewer.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="$(IntDir)generated\ui_FindReplace.h">
<Filter>Generated Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Resources\128.png">
@@ -1247,5 +1256,11 @@
<CustomBuild Include="Windows\Dialogs\EnvironmentEditor.h">
<Filter>Windows\Dialogs</Filter>
</CustomBuild>
<CustomBuild Include="Widgets\FindReplace.ui">
<Filter>Widgets</Filter>
</CustomBuild>
<CustomBuild Include="Widgets\FindReplace.h">
<Filter>Widgets</Filter>
</CustomBuild>
</ItemGroup>
</Project>