Make text editor a bit more useful, and resizable
Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
268c31c029
commit
6f9013da16
4 changed files with 326 additions and 73 deletions
|
|
@ -80,7 +80,7 @@
|
||||||
"slug": "TextEditor",
|
"slug": "TextEditor",
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"name": "Text Editor",
|
"name": "Text Editor",
|
||||||
"description": "A embed text editor inside Cardinal",
|
"description": "An embed text editor inside Cardinal",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Utility"
|
"Utility"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -25,40 +25,20 @@
|
||||||
#include "ImGuiTextEditor.hpp"
|
#include "ImGuiTextEditor.hpp"
|
||||||
#include "DearImGuiColorTextEditor/TextEditor.h"
|
#include "DearImGuiColorTextEditor/TextEditor.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
struct ImGuiTextEditor::PrivateData {
|
struct ImGuiTextEditor::PrivateData {
|
||||||
ImGuiTextEditor* const self;
|
|
||||||
TextEditor editor;
|
TextEditor editor;
|
||||||
std::string file;
|
std::string file;
|
||||||
|
|
||||||
explicit PrivateData(ImGuiTextEditor* const s)
|
|
||||||
: self(s)
|
|
||||||
{
|
|
||||||
// https://github.com/BalazsJako/ColorTextEditorDemo/blob/master/main.cpp
|
|
||||||
|
|
||||||
editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
|
|
||||||
editor.SetText(""
|
|
||||||
"// Welcome to a real text editor inside Cardinal\n"
|
|
||||||
"\n"
|
|
||||||
"#define I_AM_A_MACRO\n"
|
|
||||||
"\n"
|
|
||||||
"int and_i_am_a_variable;\n"
|
|
||||||
"\n"
|
|
||||||
"/* look ma, a comment! */\n"
|
|
||||||
"int such_highlight_much_wow() { return 1337; }\n"
|
|
||||||
);
|
|
||||||
editor.SetCursorPosition(TextEditor::Coordinates(8, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE(PrivateData)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
ImGuiTextEditor::ImGuiTextEditor()
|
ImGuiTextEditor::ImGuiTextEditor()
|
||||||
: ImGuiWidget(),
|
: ImGuiWidget(),
|
||||||
pData(new PrivateData(this)) {}
|
pData(new PrivateData) {}
|
||||||
|
|
||||||
ImGuiTextEditor::~ImGuiTextEditor()
|
ImGuiTextEditor::~ImGuiTextEditor()
|
||||||
{
|
{
|
||||||
|
|
@ -67,8 +47,35 @@ ImGuiTextEditor::~ImGuiTextEditor()
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool ImGuiTextEditor::setFile(const std::string& file)
|
||||||
|
{
|
||||||
|
std::ifstream f(file);
|
||||||
|
|
||||||
|
if (! f.good())
|
||||||
|
{
|
||||||
|
pData->file.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pData->file = file;
|
||||||
|
pData->editor.SetText(std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiTextEditor::setFileWithKnownText(const std::string& file, const std::string& text)
|
||||||
|
{
|
||||||
|
pData->file = file;
|
||||||
|
pData->editor.SetText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ImGuiTextEditor::getFile() const
|
||||||
|
{
|
||||||
|
return pData->file;
|
||||||
|
}
|
||||||
|
|
||||||
void ImGuiTextEditor::setText(const std::string& text)
|
void ImGuiTextEditor::setText(const std::string& text)
|
||||||
{
|
{
|
||||||
|
pData->file.clear();
|
||||||
pData->editor.SetText(text);
|
pData->editor.SetText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,6 +86,7 @@ std::string ImGuiTextEditor::getText() const
|
||||||
|
|
||||||
void ImGuiTextEditor::setTextLines(const std::vector<std::string>& lines)
|
void ImGuiTextEditor::setTextLines(const std::vector<std::string>& lines)
|
||||||
{
|
{
|
||||||
|
pData->file.clear();
|
||||||
pData->editor.SetTextLines(lines);
|
pData->editor.SetTextLines(lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ struct ImGuiTextEditor : ImGuiWidget
|
||||||
ImGuiTextEditor();
|
ImGuiTextEditor();
|
||||||
~ImGuiTextEditor() override;
|
~ImGuiTextEditor() override;
|
||||||
|
|
||||||
|
bool setFile(const std::string& file);
|
||||||
|
void setFileWithKnownText(const std::string& file, const std::string& text);
|
||||||
|
std::string getFile() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Methods from internal TextEdit.
|
Methods from internal TextEdit.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -26,66 +26,198 @@
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
#define DEFAULT_LANG "C++"
|
||||||
|
#define DEFAULT_TEXT "" \
|
||||||
|
"// Welcome to a real text editor inside Cardinal\n\n" \
|
||||||
|
"#define I_AM_A_MACRO\n\n" \
|
||||||
|
"int and_i_am_a_variable;\n\n" \
|
||||||
|
"/* look ma, a comment! */\n" \
|
||||||
|
"int such_highlight_much_wow() { return 1337; }\n"
|
||||||
|
#define DEFAULT_WIDTH 30
|
||||||
|
|
||||||
|
// utils
|
||||||
|
static const TextEditor::LanguageDefinition& getLangFromString(const std::string& lang)
|
||||||
|
{
|
||||||
|
if (lang == "AngelScript")
|
||||||
|
return TextEditor::LanguageDefinition::AngelScript();
|
||||||
|
if (lang == "C")
|
||||||
|
return TextEditor::LanguageDefinition::C();
|
||||||
|
if (lang == "C++")
|
||||||
|
return TextEditor::LanguageDefinition::CPlusPlus();
|
||||||
|
if (lang == "GLSL")
|
||||||
|
return TextEditor::LanguageDefinition::GLSL();
|
||||||
|
if (lang == "HLSL")
|
||||||
|
return TextEditor::LanguageDefinition::HLSL();
|
||||||
|
if (lang == "Lua")
|
||||||
|
return TextEditor::LanguageDefinition::Lua();
|
||||||
|
if (lang == "SQL")
|
||||||
|
return TextEditor::LanguageDefinition::SQL();
|
||||||
|
|
||||||
|
static const TextEditor::LanguageDefinition none;
|
||||||
|
return none;
|
||||||
|
}
|
||||||
|
|
||||||
struct TextEditorModule : Module {
|
struct TextEditorModule : Module {
|
||||||
enum ParamIds {
|
std::string file;
|
||||||
NUM_PARAMS
|
std::string lang = DEFAULT_LANG;
|
||||||
};
|
std::string text = DEFAULT_TEXT;
|
||||||
enum InputIds {
|
int width = DEFAULT_WIDTH;
|
||||||
NUM_INPUTS
|
#ifndef HEADLESS
|
||||||
};
|
WeakPtr<ImGuiTextEditor> widgetPtr;
|
||||||
enum OutputIds {
|
#endif
|
||||||
NUM_OUTPUTS
|
|
||||||
};
|
|
||||||
enum LightIds {
|
|
||||||
NUM_LIGHTS
|
|
||||||
};
|
|
||||||
|
|
||||||
TextEditorModule()
|
json_t* dataToJson() override
|
||||||
{
|
{
|
||||||
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
|
json_t* rootJ = json_object();
|
||||||
|
json_object_set_new(rootJ, "filepath", json_string(file.c_str()));
|
||||||
|
json_object_set_new(rootJ, "lang", json_string(lang.c_str()));
|
||||||
|
json_object_set_new(rootJ, "text", json_string(text.c_str()));
|
||||||
|
json_object_set_new(rootJ, "width", json_integer(width));
|
||||||
|
return rootJ;
|
||||||
}
|
}
|
||||||
|
|
||||||
~TextEditorModule() override
|
void dataFromJson(json_t* const rootJ) override
|
||||||
{
|
{
|
||||||
|
if (json_t* const widthJ = json_object_get(rootJ, "width"))
|
||||||
|
width = json_integer_value(widthJ);
|
||||||
|
|
||||||
|
if (json_t* const langJ = json_object_get(rootJ, "lang"))
|
||||||
|
{
|
||||||
|
lang = json_string_value(langJ);
|
||||||
|
#ifndef HEADLESS
|
||||||
|
// if (ImGuiTextEditor* const widget = widgetPtr)
|
||||||
|
// widget->SetLanguageDefinition(getLangFromString(lang));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void process(const ProcessArgs&) override
|
if (json_t* const filepathJ = json_object_get(rootJ, "filepath"))
|
||||||
{
|
{
|
||||||
|
const char* const filepath = json_string_value(filepathJ);
|
||||||
|
|
||||||
|
if (filepath[0] != '\0')
|
||||||
|
{
|
||||||
|
std::ifstream f(filepath);
|
||||||
|
|
||||||
|
if (f.good())
|
||||||
|
{
|
||||||
|
file = filepath;
|
||||||
|
text = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||||
|
#ifndef HEADLESS
|
||||||
|
if (ImGuiTextEditor* const widget = widgetPtr)
|
||||||
|
widget->setFileWithKnownText(file, text);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TextEditorModule)
|
if (json_t* const textJ = json_object_get(rootJ, "text"))
|
||||||
|
{
|
||||||
|
text = json_string_value(textJ);
|
||||||
|
#ifndef HEADLESS
|
||||||
|
if (ImGuiTextEditor* const widget = widgetPtr)
|
||||||
|
widget->setText(text);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadFileFromMenuAction(const char* const filepath)
|
||||||
|
{
|
||||||
|
std::ifstream f(filepath);
|
||||||
|
|
||||||
|
if (f.good())
|
||||||
|
{
|
||||||
|
file = filepath;
|
||||||
|
text = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef HEADLESS
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef HEADLESS
|
struct TextEditorLangSelectItem : MenuItem {
|
||||||
struct TextEditorWidget : ImGuiTextEditor
|
TextEditorModule* const module;
|
||||||
{
|
ImGuiTextEditor* const widget;
|
||||||
TextEditorWidget() : ImGuiTextEditor() {}
|
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TextEditorWidget)
|
TextEditorLangSelectItem(TextEditorModule* const textEditorModule,
|
||||||
|
ImGuiTextEditor* const textEditorWidget,
|
||||||
|
const char* const textToUse)
|
||||||
|
: module(textEditorModule),
|
||||||
|
widget(textEditorWidget)
|
||||||
|
{
|
||||||
|
text = textToUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAction(const event::Action &e) override
|
||||||
|
{
|
||||||
|
module->lang = text;
|
||||||
|
// widget->SetLanguageDefinition(getLangFromString(text));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextEditorLangSelectMenu : Menu {
|
||||||
|
TextEditorLangSelectMenu(TextEditorModule* const module, ImGuiTextEditor* const widget)
|
||||||
|
{
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "None"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "AngelScript"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "C"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "C++"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "GLSL"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "HLSL"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "Lua"));
|
||||||
|
addChild(new TextEditorLangSelectItem(module, widget, "SQL"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextEditorLangSelectMenuItem : MenuItem {
|
||||||
|
TextEditorModule* const module;
|
||||||
|
ImGuiTextEditor* const widget;
|
||||||
|
|
||||||
|
TextEditorLangSelectMenuItem(TextEditorModule* const textEditorModule, ImGuiTextEditor* const textEditorWidget)
|
||||||
|
: module(textEditorModule),
|
||||||
|
widget(textEditorWidget)
|
||||||
|
{
|
||||||
|
text = "Syntax Highlight";
|
||||||
|
}
|
||||||
|
|
||||||
|
void onAction(const event::Action &e) override
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// new TextEditorLangSelectMenu(module, widget);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
struct TextEditorLoadFileItem : MenuItem {
|
struct TextEditorLoadFileItem : MenuItem {
|
||||||
TextEditorWidget* widget = nullptr;
|
TextEditorModule* const module;
|
||||||
|
ImGuiTextEditor* const widget;
|
||||||
|
|
||||||
|
TextEditorLoadFileItem(TextEditorModule* const textEditorModule, ImGuiTextEditor* const textEditorWidget)
|
||||||
|
: module(textEditorModule),
|
||||||
|
widget(textEditorWidget)
|
||||||
|
{
|
||||||
|
text = "Load File";
|
||||||
|
}
|
||||||
|
|
||||||
void onAction(const event::Action &e) override
|
void onAction(const event::Action &e) override
|
||||||
{
|
{
|
||||||
WeakPtr<TextEditorWidget> widget = this->widget;
|
TextEditorModule* const module = this->module;;
|
||||||
async_dialog_filebrowser(false, nullptr, "Load File", [widget](char* path)
|
WeakPtr<ImGuiTextEditor> widget = this->widget;
|
||||||
|
|
||||||
|
async_dialog_filebrowser(false, nullptr, text.c_str(), [module, widget](char* path)
|
||||||
{
|
{
|
||||||
if (path)
|
if (path)
|
||||||
|
{
|
||||||
|
if (module->loadFileFromMenuAction(path))
|
||||||
{
|
{
|
||||||
if (widget)
|
if (widget)
|
||||||
{
|
widget->setFileWithKnownText(module->file, module->text);
|
||||||
std::ifstream f(path);
|
|
||||||
if (f.good())
|
|
||||||
{
|
|
||||||
const std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
|
||||||
widget->setText(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
@ -95,35 +227,144 @@ struct TextEditorLoadFileItem : MenuItem {
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code adapted from VCVRack's Blank.cpp
|
||||||
|
* Copyright (C) 2016-2021 VCV.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ModuleResizeHandle : OpaqueWidget {
|
||||||
|
TextEditorModule* const module;
|
||||||
|
ModuleWidget* const widget;
|
||||||
|
const bool right;
|
||||||
|
Vec dragPos;
|
||||||
|
Rect originalBox;
|
||||||
|
|
||||||
|
ModuleResizeHandle(TextEditorModule* const textEditorModule, ModuleWidget* const moduleWidget, const bool r)
|
||||||
|
: module(textEditorModule),
|
||||||
|
widget(moduleWidget),
|
||||||
|
right(r)
|
||||||
|
{
|
||||||
|
box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDragStart(const DragStartEvent& e) override
|
||||||
|
{
|
||||||
|
if (e.button != GLFW_MOUSE_BUTTON_LEFT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dragPos = APP->scene->rack->getMousePos();
|
||||||
|
originalBox = widget->box;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDragMove(const DragMoveEvent& e) override
|
||||||
|
{
|
||||||
|
static const float kMinWidth = 10 * RACK_GRID_WIDTH;
|
||||||
|
|
||||||
|
Vec newDragPos = APP->scene->rack->getMousePos();
|
||||||
|
float deltaX = newDragPos.x - dragPos.x;
|
||||||
|
|
||||||
|
Rect newBox = originalBox;
|
||||||
|
Rect oldBox = widget->box;
|
||||||
|
if (right) {
|
||||||
|
newBox.size.x += deltaX;
|
||||||
|
newBox.size.x = std::fmax(newBox.size.x, kMinWidth);
|
||||||
|
newBox.size.x = std::round(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newBox.size.x -= deltaX;
|
||||||
|
newBox.size.x = std::fmax(newBox.size.x, kMinWidth);
|
||||||
|
newBox.size.x = std::round(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
|
||||||
|
newBox.pos.x = originalBox.pos.x + originalBox.size.x - newBox.size.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set box and test whether it's valid
|
||||||
|
widget->box = newBox;
|
||||||
|
if (!APP->scene->rack->requestModulePos(widget, newBox.pos)) {
|
||||||
|
widget->box = oldBox;
|
||||||
|
}
|
||||||
|
module->width = std::round(widget->box.size.x / RACK_GRID_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(const DrawArgs& args) override
|
||||||
|
{
|
||||||
|
for (float x = 5.0; x <= 10.0; x += 5.0)
|
||||||
|
{
|
||||||
|
nvgBeginPath(args.vg);
|
||||||
|
const float margin = 5.0;
|
||||||
|
nvgMoveTo(args.vg, x + 0.5, margin + 0.5);
|
||||||
|
nvgLineTo(args.vg, x + 0.5, box.size.y - margin + 0.5);
|
||||||
|
nvgStrokeWidth(args.vg, 1.0);
|
||||||
|
nvgStrokeColor(args.vg, nvgRGBAf(0.5, 0.5, 0.5, 0.5));
|
||||||
|
nvgStroke(args.vg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
struct TextEditorModuleWidget : ModuleWidget {
|
struct TextEditorModuleWidget : ModuleWidget {
|
||||||
TextEditorWidget* textEditorWidget = nullptr;
|
TextEditorModule* textEditorModule = nullptr;
|
||||||
|
ImGuiTextEditor* textEditorWidget = nullptr;
|
||||||
|
Widget* panelBorder;
|
||||||
|
ModuleResizeHandle* rightHandle;
|
||||||
|
|
||||||
TextEditorModuleWidget(TextEditorModule* const module)
|
TextEditorModuleWidget(TextEditorModule* const module)
|
||||||
{
|
{
|
||||||
setModule(module);
|
setModule(module);
|
||||||
setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Ildaeil.svg")));
|
addChild(panelBorder = new PanelBorder);
|
||||||
|
addChild(rightHandle = new ModuleResizeHandle(module, this, true));
|
||||||
|
addChild(new ModuleResizeHandle(module, this, false));
|
||||||
|
|
||||||
if (module != nullptr)
|
if (module != nullptr)
|
||||||
{
|
{
|
||||||
textEditorWidget = new TextEditorWidget();
|
box.size = Vec(RACK_GRID_WIDTH * module->width, RACK_GRID_HEIGHT);
|
||||||
textEditorWidget->box.pos = Vec(2 * RACK_GRID_WIDTH, 0);
|
textEditorModule = module;
|
||||||
textEditorWidget->box.size = Vec(box.size.x - 2 * RACK_GRID_WIDTH, box.size.y);
|
textEditorWidget = new ImGuiTextEditor();
|
||||||
|
textEditorWidget->setFileWithKnownText(module->file, module->text);
|
||||||
|
textEditorWidget->box.pos = Vec(RACK_GRID_WIDTH, 0);
|
||||||
|
textEditorWidget->box.size = Vec((module->width - 2) * RACK_GRID_WIDTH, box.size.y);
|
||||||
addChild(textEditorWidget);
|
addChild(textEditorWidget);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
addChild(createWidget<ScrewBlack>(Vec(0, 0)));
|
{
|
||||||
addChild(createWidget<ScrewBlack>(Vec(0, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
box.size = Vec(RACK_GRID_WIDTH * DEFAULT_WIDTH, RACK_GRID_HEIGHT);
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, 0)));
|
}
|
||||||
addChild(createWidget<ScrewBlack>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendContextMenu(Menu *menu) override {
|
void appendContextMenu(Menu *menu) override
|
||||||
menu->addChild(new MenuEntry);
|
{
|
||||||
|
menu->addChild(new MenuSeparator);
|
||||||
|
menu->addChild(new TextEditorLoadFileItem(textEditorModule, textEditorWidget));
|
||||||
|
// TODO
|
||||||
|
// menu->addChild(new TextEditorLangSelectMenuItem(textEditorModule, textEditorWidget));
|
||||||
|
}
|
||||||
|
|
||||||
TextEditorLoadFileItem* loadFileItem = new TextEditorLoadFileItem;
|
void step() override
|
||||||
loadFileItem->text = "Load File";
|
{
|
||||||
loadFileItem->widget = textEditorWidget;
|
if (textEditorModule)
|
||||||
menu->addChild(loadFileItem);
|
{
|
||||||
|
box.size.x = textEditorModule->width * RACK_GRID_WIDTH;
|
||||||
|
textEditorWidget->box.size.x = (textEditorModule->width - 2) * RACK_GRID_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
panelBorder->box.size = box.size;
|
||||||
|
rightHandle->box.pos.x = box.size.x - rightHandle->box.size.x;
|
||||||
|
|
||||||
|
ModuleWidget::step();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(const DrawArgs& args) override
|
||||||
|
{
|
||||||
|
nvgBeginPath(args.vg);
|
||||||
|
nvgRect(args.vg, 0.0, 0.0, box.size.x, box.size.y);
|
||||||
|
nvgFillColor(args.vg, nvgRGB(0x20, 0x20, 0x20));
|
||||||
|
nvgFill(args.vg);
|
||||||
|
ModuleWidget::draw(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TextEditorModuleWidget)
|
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TextEditorModuleWidget)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue