Browse Source

Added key commands to ModuleWidget, removed CPU usage meter (misleads

way too many people, should not have added in the first place)
tags/v0.3.2
Andrew Belt 7 years ago
parent
commit
728afc763a
9 changed files with 111 additions and 61 deletions
  1. +8
    -1
      include/app.hpp
  2. +1
    -8
      include/gui.hpp
  3. +6
    -4
      include/widgets.hpp
  4. +33
    -11
      src/app/ModuleWidget.cpp
  5. +29
    -9
      src/app/RackWidget.cpp
  6. +2
    -0
      src/app/Toolbar.cpp
  7. +16
    -26
      src/gui.cpp
  8. +2
    -2
      src/widgets/TextField.cpp
  9. +14
    -0
      src/widgets/Widget.cpp

+ 8
- 1
include/app.hpp View File

@@ -57,6 +57,8 @@ struct ModuleWidget : OpaqueWidget {
bool requested = false; bool requested = false;
Vec requestedPos; Vec requestedPos;
Vec dragPos; Vec dragPos;
Widget *onMouseMove(Vec pos, Vec mouseRel);
Widget *onHoverKey(Vec pos, int key);
void onDragStart(); void onDragStart();
void onDragMove(Vec mouseRel); void onDragMove(Vec mouseRel);
void onDragEnd(); void onDragEnd();
@@ -97,7 +99,12 @@ struct RackWidget : OpaqueWidget {
json_t *toJson(); json_t *toJson();
void fromJson(json_t *root); void fromJson(json_t *root);


void repositionModule(ModuleWidget *module);
void addModule(ModuleWidget *m);
/** Transfers ownership to the caller so they must `delete` it if that is the intension */
void deleteModule(ModuleWidget *m);
void cloneModule(ModuleWidget *m);
/** Moves a module to the closest non-colliding position */
void repositionModule(ModuleWidget *m);
void step(); void step();
void draw(NVGcontext *vg); void draw(NVGcontext *vg);




+ 1
- 8
include/gui.hpp View File

@@ -18,13 +18,6 @@ void guiDestroy();
void guiRun(); void guiRun();
void guiCursorLock(); void guiCursorLock();
void guiCursorUnlock(); void guiCursorUnlock();

inline bool guiIsModPressed() {
#ifdef ARCH_MAC
return glfwGetKey(gWindow, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS;
#else
return glfwGetKey(gWindow, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
#endif
}
bool guiIsModPressed();


} // namespace rack } // namespace rack

+ 6
- 4
include/widgets.hpp View File

@@ -91,15 +91,17 @@ struct Widget {
*/ */
virtual Widget *onMouseDown(Vec pos, int button); virtual Widget *onMouseDown(Vec pos, int button);
virtual Widget *onMouseUp(Vec pos, int button); virtual Widget *onMouseUp(Vec pos, int button);
/** Called on every frame, even if mouseRel = Vec(0, 0) */
virtual Widget *onMouseMove(Vec pos, Vec mouseRel); virtual Widget *onMouseMove(Vec pos, Vec mouseRel);
virtual Widget *onHoverKey(Vec pos, int key);
/** Called when this widget begins responding to `onMouseMove` events */ /** Called when this widget begins responding to `onMouseMove` events */
virtual void onMouseEnter() {} virtual void onMouseEnter() {}
/** Called when another widget begins responding to `onMouseMove` events */ /** Called when another widget begins responding to `onMouseMove` events */
virtual void onMouseLeave() {} virtual void onMouseLeave() {}
virtual void onSelect() {} virtual void onSelect() {}
virtual void onDeselect() {} virtual void onDeselect() {}
virtual void onText(int codepoint) {}
virtual void onKey(int key) {}
virtual bool onText(int codepoint) {return false;}
virtual bool onKey(int key) {return false;}
virtual Widget *onScroll(Vec pos, Vec scrollRel); virtual Widget *onScroll(Vec pos, Vec scrollRel);


/** Called when a widget responds to `onMouseDown` for a left button press */ /** Called when a widget responds to `onMouseDown` for a left button press */
@@ -364,8 +366,8 @@ struct TextField : OpaqueWidget {
} }
void draw(NVGcontext *vg); void draw(NVGcontext *vg);
Widget *onMouseDown(Vec pos, int button); Widget *onMouseDown(Vec pos, int button);
void onText(int codepoint);
void onKey(int scancode);
bool onText(int codepoint);
bool onKey(int scancode);
void onSelect(); void onSelect();
void insertText(std::string newText); void insertText(std::string newText);
}; };


+ 33
- 11
src/app/ModuleWidget.cpp View File

@@ -1,6 +1,7 @@
#include "app.hpp" #include "app.hpp"
#include "engine.hpp" #include "engine.hpp"
#include "plugin.hpp" #include "plugin.hpp"
#include "gui.hpp"




namespace rack { namespace rack {
@@ -125,6 +126,7 @@ void ModuleWidget::draw(NVGcontext *vg) {


Widget::draw(vg); Widget::draw(vg);


/*
// CPU usage text // CPU usage text
if (dynamic_cast<RackScene*>(gScene)->toolbar->cpuUsageButton->value > 0.0) { if (dynamic_cast<RackScene*>(gScene)->toolbar->cpuUsageButton->value > 0.0) {
float cpuTime = module ? module->cpuTime : 0.0; float cpuTime = module ? module->cpuTime : 0.0;
@@ -145,10 +147,38 @@ void ModuleWidget::draw(NVGcontext *vg) {
bndMenuItem(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT, BND_DEFAULT, -1, text.c_str()); bndMenuItem(vg, 0.0, 0.0, box.size.x, BND_WIDGET_HEIGHT, BND_DEFAULT, -1, text.c_str());
nvgRestore(vg); nvgRestore(vg);
} }
*/


nvgResetScissor(vg); nvgResetScissor(vg);
} }


Widget *ModuleWidget::onMouseMove(Vec pos, Vec mouseRel) {
return OpaqueWidget::onMouseMove(pos, mouseRel);
}

Widget *ModuleWidget::onHoverKey(Vec pos, int key) {
switch (key) {
case GLFW_KEY_DELETE:
case GLFW_KEY_BACKSPACE:
gRackWidget->deleteModule(this);
delete this;
break;
case GLFW_KEY_I:
if (guiIsModPressed())
initialize();
break;
case GLFW_KEY_R:
if (guiIsModPressed())
randomize();
break;
case GLFW_KEY_D:
if (guiIsModPressed())
gRackWidget->cloneModule(this);
break;
}
return NULL;
}

void ModuleWidget::onDragStart() { void ModuleWidget::onDragStart() {
dragPos = gMousePos.minus(getAbsolutePos()); dragPos = gMousePos.minus(getAbsolutePos());
} }
@@ -185,22 +215,14 @@ struct RandomizeMenuItem : MenuItem {
struct CloneMenuItem : MenuItem { struct CloneMenuItem : MenuItem {
ModuleWidget *moduleWidget; ModuleWidget *moduleWidget;
void onAction() { void onAction() {
// Create new module from model
ModuleWidget *clonedModuleWidget = moduleWidget->model->createModuleWidget();
// JSON serialization is the most straightforward way to do this
json_t *moduleJ = moduleWidget->toJson();
clonedModuleWidget->fromJson(moduleJ);
json_decref(moduleJ);
clonedModuleWidget->requestedPos = moduleWidget->box.pos;
clonedModuleWidget->requested = true;
gRackWidget->moduleContainer->addChild(clonedModuleWidget);
gRackWidget->cloneModule(moduleWidget);
} }
}; };


struct DeleteMenuItem : MenuItem { struct DeleteMenuItem : MenuItem {
ModuleWidget *moduleWidget; ModuleWidget *moduleWidget;
void onAction() { void onAction() {
gRackWidget->moduleContainer->removeChild(moduleWidget);
gRackWidget->deleteModule(moduleWidget);
delete moduleWidget; delete moduleWidget;
} }
}; };
@@ -229,7 +251,7 @@ void ModuleWidget::onMouseDown(int button) {
menu->pushChild(disconnectItem); menu->pushChild(disconnectItem);


CloneMenuItem *cloneItem = new CloneMenuItem(); CloneMenuItem *cloneItem = new CloneMenuItem();
cloneItem->text = "Clone";
cloneItem->text = "Duplicate";
cloneItem->moduleWidget = this; cloneItem->moduleWidget = this;
menu->pushChild(cloneItem); menu->pushChild(cloneItem);




+ 29
- 9
src/app/RackWidget.cpp View File

@@ -226,29 +226,49 @@ void RackWidget::fromJson(json_t *rootJ) {
} }
} }


void RackWidget::repositionModule(ModuleWidget *module) {
void RackWidget::addModule(ModuleWidget *m) {
moduleContainer->addChild(m);
}

void RackWidget::deleteModule(ModuleWidget *m) {
moduleContainer->removeChild(m);
}

void RackWidget::cloneModule(ModuleWidget *m) {
// Create new module from model
ModuleWidget *clonedModuleWidget = m->model->createModuleWidget();
// JSON serialization is the most straightforward way to do this
json_t *moduleJ = m->toJson();
clonedModuleWidget->fromJson(moduleJ);
json_decref(moduleJ);
clonedModuleWidget->requestedPos = m->box.pos;
clonedModuleWidget->requested = true;
addModule(clonedModuleWidget);
}

void RackWidget::repositionModule(ModuleWidget *m) {
// Create possible positions // Create possible positions
int x0 = roundf(module->requestedPos.x / RACK_GRID_WIDTH);
int y0 = roundf(module->requestedPos.y / RACK_GRID_HEIGHT);
int x0 = roundf(m->requestedPos.x / RACK_GRID_WIDTH);
int y0 = roundf(m->requestedPos.y / RACK_GRID_HEIGHT);
std::vector<Vec> positions; std::vector<Vec> positions;
for (int y = maxi(0, y0 - 2); y < y0 + 2; y++) {
for (int x = maxi(0, x0 - 40); x < x0 + 40; x++) {
for (int y = maxi(0, y0 - 4); y < y0 + 4; y++) {
for (int x = maxi(0, x0 - 200); x < x0 + 200; x++) {
positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT)); positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
} }
} }


// Sort possible positions by distance to the requested position // Sort possible positions by distance to the requested position
Vec requestedPos = module->requestedPos;
Vec requestedPos = m->requestedPos;
std::sort(positions.begin(), positions.end(), [requestedPos](Vec a, Vec b) { std::sort(positions.begin(), positions.end(), [requestedPos](Vec a, Vec b) {
return a.minus(requestedPos).norm() < b.minus(requestedPos).norm(); return a.minus(requestedPos).norm() < b.minus(requestedPos).norm();
}); });


// Find a position that does not collide // Find a position that does not collide
for (Vec pos : positions) { for (Vec pos : positions) {
Rect newBox = Rect(pos, module->box.size);
Rect newBox = Rect(pos, m->box.size);
bool collides = false; bool collides = false;
for (Widget *child2 : moduleContainer->children) { for (Widget *child2 : moduleContainer->children) {
if (module == child2) continue;
if (m == child2) continue;
if (newBox.intersects(child2->box)) { if (newBox.intersects(child2->box)) {
collides = true; collides = true;
break; break;
@@ -256,7 +276,7 @@ void RackWidget::repositionModule(ModuleWidget *module) {
} }
if (collides) continue; if (collides) continue;


module->box.pos = pos;
m->box.pos = pos;
break; break;
} }
} }


+ 2
- 0
src/app/Toolbar.cpp View File

@@ -139,6 +139,7 @@ Toolbar::Toolbar() {
xPos += wireTensionSlider->box.size.x; xPos += wireTensionSlider->box.size.x;
} }


/*
xPos += margin; xPos += margin;
{ {
cpuUsageButton = new RadioButton(); cpuUsageButton = new RadioButton();
@@ -148,6 +149,7 @@ Toolbar::Toolbar() {
addChild(cpuUsageButton); addChild(cpuUsageButton);
xPos += cpuUsageButton->box.size.x; xPos += cpuUsageButton->box.size.x;
} }
*/


xPos += margin; xPos += margin;
{ {


+ 16
- 26
src/gui.cpp View File

@@ -157,34 +157,13 @@ void charCallback(GLFWwindow *window, unsigned int codepoint) {
} }
} }


// static int lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight;

void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if (action == GLFW_PRESS || action == GLFW_REPEAT) { if (action == GLFW_PRESS || action == GLFW_REPEAT) {
if (key == GLFW_KEY_F11 || key == GLFW_KEY_ESCAPE) {
/*
// Toggle fullscreen
GLFWmonitor *monitor = glfwGetWindowMonitor(gWindow);
if (monitor) {
// Window mode
glfwSetWindowMonitor(gWindow, NULL, lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight, 0);
}
else {
// Fullscreen
glfwGetWindowPos(gWindow, &lastWindowX, &lastWindowY);
glfwGetWindowSize(gWindow, &lastWindowWidth, &lastWindowHeight);
monitor = glfwGetPrimaryMonitor();
assert(monitor);
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
glfwSetWindowMonitor(gWindow, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
}
*/
}
else {
if (gSelectedWidget) {
gSelectedWidget->onKey(key);
}
}
// onKey
if (gSelectedWidget && gSelectedWidget->onKey(key))
return;
// onHoverKey
gScene->onHoverKey(gMousePos, key);
} }
} }


@@ -228,6 +207,9 @@ void guiInit() {
err = glfwInit(); err = glfwInit();
assert(err); assert(err);


const char *glVersion = (const char *)glGetString(GL_VERSION);
printf("OpenGL version %s\n", glVersion);

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
// glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@@ -329,6 +311,14 @@ void guiCursorUnlock() {
glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
} }


bool guiIsModPressed() {
#ifdef ARCH_MAC
return glfwGetKey(gWindow, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS;
#else
return glfwGetKey(gWindow, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
#endif
}



//////////////////// ////////////////////
// resources // resources


+ 2
- 2
src/widgets/TextField.cpp View File

@@ -29,13 +29,13 @@ Widget *TextField::onMouseDown(Vec pos, int button) {
} }




void TextField::onText(int codepoint) {
bool TextField::onText(int codepoint) {
char c = codepoint; char c = codepoint;
std::string newText(1, c); std::string newText(1, c);
insertText(newText); insertText(newText);
} }


void TextField::onKey(int key) {
bool TextField::onKey(int key) {
switch (key) { switch (key) {
case GLFW_KEY_BACKSPACE: case GLFW_KEY_BACKSPACE:
if (begin < end) { if (begin < end) {


+ 14
- 0
src/widgets/Widget.cpp View File

@@ -121,6 +121,20 @@ Widget *Widget::onMouseMove(Vec pos, Vec mouseRel) {
return NULL; return NULL;
} }


Widget *Widget::onHoverKey(Vec pos, int key) {
for (auto it = children.rbegin(); it != children.rend(); it++) {
Widget *child = *it;
if (!child->visible)
continue;
if (child->box.contains(pos)) {
Widget *w = child->onHoverKey(pos.minus(child->box.pos), key);
if (w)
return w;
}
}
return NULL;
}

Widget *Widget::onScroll(Vec pos, Vec scrollRel) { Widget *Widget::onScroll(Vec pos, Vec scrollRel) {
for (auto it = children.rbegin(); it != children.rend(); it++) { for (auto it = children.rbegin(); it != children.rend(); it++) {
Widget *child = *it; Widget *child = *it;


Loading…
Cancel
Save