kopia lustrzana https://github.com/jameshball/osci-render
Refactor code editor visibility, add title to code editor, significantly improve performance when resizing interface
rodzic
35cf8d7942
commit
4c5852f9f0
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue