Refactor code editor visibility, add title to code editor, significantly improve performance when resizing interface

pull/229/head
James Ball 2024-03-13 23:07:40 +00:00 zatwierdzone przez James H Ball
rodzic 35cf8d7942
commit 4c5852f9f0
10 zmienionych plików z 93 dodań i 44 usunięć

Wyświetl plik

@ -44,6 +44,8 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
pluginEditor.fileUpdated(audioProcessor.getCurrentFileName());
};
closeFileButton.setTooltip("Close the currently open file.");
addAndMakeVisible(inputEnabled);
inputEnabled.onClick = [this] {
audioProcessor.inputEnabled->setBoolValueNotifyingHost(!audioProcessor.inputEnabled->getBoolValue());

Wyświetl plik

@ -146,16 +146,16 @@ void OscirenderAudioProcessorEditor::paint(juce::Graphics& g) {
}
for (int i = 0; i < codeEditors.size(); i++) {
if (codeEditors[i]->getBounds().getWidth() > 0 && codeEditors[i]->getBounds().getHeight() > 0) {
if (codeEditors[i]->isVisible()) {
ds.drawForRectangle(g, codeEditors[i]->getBounds());
}
}
if (lua.getBounds().getWidth() > 0 && lua.getBounds().getHeight() > 0) {
if (lua.isVisible()) {
ds.drawForRectangle(g, lua.getBounds());
}
if (console.getBounds().getWidth() > 0 && console.getBounds().getHeight() > 0) {
if (console.isVisible()) {
ds.drawForRectangle(g, console.getBounds());
}
}
@ -184,7 +184,12 @@ void OscirenderAudioProcessorEditor::resized() {
int originalIndex = audioProcessor.getCurrentFileIndex();
int index = editingCustomFunction ? 0 : audioProcessor.getCurrentFileIndex() + 1;
if (originalIndex != -1 || editingCustomFunction) {
bool ableToEditFile = originalIndex != -1 || editingCustomFunction;
bool fileOpen = false;
bool luaFileOpen = false;
if (ableToEditFile) {
if (codeEditors[index]->isVisible()) {
editorVisible = true;
@ -218,26 +223,25 @@ void OscirenderAudioProcessorEditor::resized() {
console.setBounds(dummy3Bounds.removeFromBottom(console.getConsoleOpen() ? 200 : 30));
dummy3Bounds.removeFromBottom(RESIZER_BAR_SIZE);
codeEditors[index]->setBounds(dummy3Bounds);
luaFileOpen = true;
} else {
codeEditors[index]->setBounds(dummy2Bounds);
console.setBounds(0, 0, 0, 0);
luaResizerBar.setBounds(0, 0, 0, 0);
lua.setBounds(0, 0, 0, 0);
}
fileOpen = true;
} else {
codeEditors[index]->setBounds(0, 0, 0, 0);
resizerBar.setBounds(0, 0, 0, 0);
luaResizerBar.setBounds(0, 0, 0, 0);
lua.setBounds(0, 0, 0, 0);
console.setBounds(0, 0, 0, 0);
collapseButton.setBounds(area.removeFromRight(20));
}
} else {
collapseButton.setBounds(0, 0, 0, 0);
luaResizerBar.setBounds(0, 0, 0, 0);
lua.setBounds(0, 0, 0, 0);
console.setBounds(0, 0, 0, 0);
}
collapseButton.setVisible(ableToEditFile);
codeEditors[index]->setVisible(fileOpen);
resizerBar.setVisible(fileOpen);
console.setVisible(luaFileOpen);
luaResizerBar.setVisible(luaFileOpen);
lua.setVisible(luaFileOpen);
}
if (editorVisible) {
@ -258,7 +262,7 @@ void OscirenderAudioProcessorEditor::addCodeEditor(int index) {
int originalIndex = index;
index++;
std::shared_ptr<juce::CodeDocument> codeDocument;
std::shared_ptr<ErrorCodeEditorComponent> editor;
std::shared_ptr<OscirenderCodeEditorComponent> editor;
if (index == 0) {
codeDocument = customFunctionCodeDocument;
@ -272,7 +276,7 @@ void OscirenderAudioProcessorEditor::addCodeEditor(int index) {
} else if (extension == ".svg") {
tokeniser = &xmlTokeniser;
}
editor = std::make_shared<ErrorCodeEditorComponent>(*codeDocument, tokeniser, audioProcessor, audioProcessor.getFileId(originalIndex));
editor = std::make_shared<OscirenderCodeEditorComponent>(*codeDocument, tokeniser, audioProcessor, audioProcessor.getFileId(originalIndex), audioProcessor.getFileName(originalIndex));
}
codeDocuments.insert(codeDocuments.begin() + index, codeDocument);
@ -282,7 +286,7 @@ void OscirenderAudioProcessorEditor::addCodeEditor(int index) {
editor->setAccessible(false);
// listen for changes to the code editor
codeDocument->addListener(this);
editor->setColourScheme(colourScheme);
editor->getEditor().setColourScheme(colourScheme);
}
void OscirenderAudioProcessorEditor::removeCodeEditor(int index) {
@ -315,9 +319,9 @@ void OscirenderAudioProcessorEditor::updateCodeEditor() {
// message thread, this is safe.
updatingDocumentsWithParserLock = true;
if (index == 0) {
codeEditors[index]->loadContent(audioProcessor.customEffect->getCode());
codeEditors[index]->getEditor().loadContent(audioProcessor.customEffect->getCode());
} else {
codeEditors[index]->loadContent(juce::MemoryInputStream(*audioProcessor.getFileBlock(originalIndex), false).readEntireStreamAsString());
codeEditors[index]->getEditor().loadContent(juce::MemoryInputStream(*audioProcessor.getFileBlock(originalIndex), false).readEntireStreamAsString());
}
updatingDocumentsWithParserLock = false;
}
@ -374,8 +378,8 @@ void OscirenderAudioProcessorEditor::editCustomFunction(bool enable) {
editingCustomFunction = enable;
juce::SpinLock::ScopedLockType lock1(audioProcessor.parsersLock);
juce::SpinLock::ScopedLockType lock2(audioProcessor.effectsLock);
codeEditors[0]->setVisible(enable);
updateCodeEditor();
codeEditors[0]->setVisible(enable);
}
// parsersLock AND effectsLock must be locked before calling this function

Wyświetl plik

@ -57,13 +57,13 @@ public:
LuaConsole console;
std::vector<std::shared_ptr<juce::CodeDocument>> codeDocuments;
std::vector<std::shared_ptr<ErrorCodeEditorComponent>> codeEditors;
std::vector<std::shared_ptr<OscirenderCodeEditorComponent>> codeEditors;
juce::CodeEditorComponent::ColourScheme colourScheme;
juce::LuaTokeniser luaTokeniser;
juce::XmlTokeniser xmlTokeniser;
juce::ShapeButton collapseButton;
std::shared_ptr<juce::CodeDocument> customFunctionCodeDocument = std::make_shared<juce::CodeDocument>();
std::shared_ptr<ErrorCodeEditorComponent> customFunctionCodeEditor = std::make_shared<ErrorCodeEditorComponent>(*customFunctionCodeDocument, &luaTokeniser, audioProcessor, CustomEffect::FILE_NAME);
std::shared_ptr<OscirenderCodeEditorComponent> customFunctionCodeEditor = std::make_shared<OscirenderCodeEditorComponent>(*customFunctionCodeDocument, &luaTokeniser, audioProcessor, CustomEffect::UNIQUE_ID, CustomEffect::FILE_NAME);
std::unique_ptr<juce::FileChooser> chooser;
MainMenuBarModel menuBarModel{*this};

Wyświetl plik

@ -488,10 +488,10 @@ void OscirenderAudioProcessor::changeSound(ShapeSound::Ptr sound) {
}
}
void OscirenderAudioProcessor::notifyErrorListeners(int lineNumber, juce::String fileName, juce::String error) {
void OscirenderAudioProcessor::notifyErrorListeners(int lineNumber, juce::String id, juce::String error) {
juce::SpinLock::ScopedLockType lock(errorListenersLock);
for (auto listener : errorListeners) {
if (listener->getFileName() == fileName) {
if (listener->getId() == id) {
listener->onError(lineNumber, error);
}
}

Wyświetl plik

@ -234,7 +234,7 @@ public:
void setObjectServerRendering(bool enabled);
void addErrorListener(ErrorListener* listener);
void removeErrorListener(ErrorListener* listener);
void notifyErrorListeners(int lineNumber, juce::String fileName, juce::String error);
void notifyErrorListeners(int lineNumber, juce::String id, juce::String error);
private:
std::atomic<double> volume = 1.0;
std::atomic<double> threshold = 1.0;

Wyświetl plik

@ -2,7 +2,8 @@
#include <numbers>
#include "../MathUtil.h"
const juce::String CustomEffect::FILE_NAME = "6a3580b0-c5fc-4b28-a33e-e26a487f052f";
const juce::String CustomEffect::UNIQUE_ID = "6a3580b0-c5fc-4b28-a33e-e26a487f052f";
const juce::String CustomEffect::FILE_NAME = "Custom Lua Effect";
CustomEffect::CustomEffect(std::function<void(int, juce::String, juce::String)> errorCallback, double (&luaValues)[26]) : errorCallback(errorCallback), luaValues(luaValues) {
vars.isEffect = true;

Wyświetl plik

@ -10,6 +10,7 @@ public:
~CustomEffect();
// arbitrary UUID
static const juce::String UNIQUE_ID;
static const juce::String FILE_NAME;
Point apply(int index, Point input, const std::vector<double>& values, double sampleRate) override;

Wyświetl plik

@ -5,13 +5,7 @@
class ErrorCodeEditorComponent : public juce::CodeEditorComponent, public ErrorListener, public juce::AsyncUpdater {
public:
ErrorCodeEditorComponent(juce::CodeDocument& document, juce::CodeTokeniser* codeTokeniser, OscirenderAudioProcessor& p, juce::String fileName) : juce::CodeEditorComponent(document, codeTokeniser), audioProcessor(p), document(document), fileName(fileName) {
audioProcessor.addErrorListener(this);
}
~ErrorCodeEditorComponent() override {
audioProcessor.removeErrorListener(this);
}
ErrorCodeEditorComponent(juce::CodeDocument& document, juce::CodeTokeniser* codeTokeniser, juce::String id) : juce::CodeEditorComponent(document, codeTokeniser), id(id) {}
void paint(juce::Graphics& g) override {
juce::CodeEditorComponent::paint(g);
@ -35,7 +29,7 @@ class ErrorCodeEditorComponent : public juce::CodeEditorComponent, public ErrorL
double lineIncrement = 2.5;
double squiggleHeight = 3;
juce::String line = document.getLine(errorLine - 1);
juce::String line = getDocument().getLine(errorLine - 1);
// get number of leading whitespace characters
int leadingWhitespace = line.length() - line.trimStart().length();
double start = getCharWidth() * leadingWhitespace;
@ -88,7 +82,6 @@ class ErrorCodeEditorComponent : public juce::CodeEditorComponent, public ErrorL
repaint();
}
private:
void onError(int lineNumber, juce::String error) override {
int oldErrorLine = errorLine;
errorLine = lineNumber;
@ -98,14 +91,45 @@ private:
}
}
juce::String getFileName() override {
return fileName;
private:
juce::String getId() override {
return id;
}
juce::CodeDocument& document;
juce::String fileName;
int errorLine = -1;
juce::String id;
juce::String errorText;
bool errorLineHovered = false;
};
class OscirenderCodeEditorComponent : public juce::GroupComponent {
public:
OscirenderCodeEditorComponent(juce::CodeDocument& document, juce::CodeTokeniser* codeTokeniser, OscirenderAudioProcessor& p, juce::String id, juce::String fileName) : editor(document, codeTokeniser, id), audioProcessor(p) {
setText(fileName);
setTextLabelPosition(juce::Justification::centred);
addAndMakeVisible(editor);
audioProcessor.addErrorListener(&editor);
}
~OscirenderCodeEditorComponent() override {
audioProcessor.removeErrorListener(&editor);
}
void resized() override {
auto bounds = getLocalBounds();
bounds.removeFromTop(30);
editor.setBounds(bounds);
}
ErrorCodeEditorComponent& getEditor() {
return editor;
}
private:
ErrorCodeEditorComponent editor;
OscirenderAudioProcessor& audioProcessor;
};

Wyświetl plik

@ -180,6 +180,16 @@ public:
return (row >= firstIndex && row < firstIndex + rows.size()) ? getComponentForRow (row) : nullptr;
}
void updateAllRows() {
// TODO: Refactor this class so that this function is called to
// update all rows, including those offscreen, so that we never
// need to recalculate the row components.
//
// This makes VListBoxes that don't have many components much
// faster, but it would be slower for VListBoxes with many
// components.
}
int getRowNumberOfComponent (Component* const rowComponent) const noexcept
{
const int index = getViewedComponent()->getIndexOfChildComponent (rowComponent);
@ -259,9 +269,15 @@ public:
if (auto* rowComp = getComponentForRow (row))
{
rowComp->setBounds (0, owner.getPositionForRow (row), w, owner.getRowHeight (row));
rowComp->update (row, owner.isRowSelected (row));
if (firstIndex != prevFirstIndex || lastRow != prevLastRow) {
// This is the slowest part of the UI code. Any other tricks to call this less often would help a lot.
rowComp->update(row, owner.isRowSelected(row));
}
}
}
prevFirstIndex = firstIndex;
prevLastRow = lastRow;
}
else
{
@ -347,6 +363,7 @@ public:
private:
ListBox& owner;
OwnedArray<RowComponent> rows;
int prevFirstIndex = -1, prevLastRow = -1;
int firstIndex = 0, firstWholeIndex = 0, lastWholeIndex = 0;
bool hasUpdated = false;

Wyświetl plik

@ -7,7 +7,7 @@
class ErrorListener {
public:
virtual void onError(int lineNumber, juce::String error) = 0;
virtual juce::String getFileName() = 0;
virtual juce::String getId() = 0;
};
const int NUM_SLIDERS = 26;