Browse Source

Added zoom slider, zoom to settings, finished Framebuffer scaling

tags/v0.5.0
Andrew Belt 7 years ago
parent
commit
a22aac6493
17 changed files with 100 additions and 35 deletions
  1. +1
    -0
      include/app.hpp
  2. +2
    -0
      include/gui.hpp
  3. +6
    -0
      include/math.hpp
  4. +1
    -6
      include/widgets.hpp
  5. +3
    -1
      src/app/RackScene.cpp
  6. +1
    -0
      src/app/RackScrollWidget.cpp
  7. +3
    -3
      src/app/RackWidget.cpp
  8. +14
    -1
      src/app/Toolbar.cpp
  9. +1
    -0
      src/app/WireWidget.cpp
  10. +2
    -0
      src/gui.cpp
  11. +10
    -0
      src/settings.cpp
  12. +0
    -2
      src/widgets.cpp
  13. +44
    -22
      src/widgets/FramebufferWidget.cpp
  14. +1
    -0
      src/widgets/Scene.cpp
  15. +6
    -0
      src/widgets/Slider.cpp
  16. +4
    -0
      src/widgets/TextField.cpp
  17. +1
    -0
      src/widgets/Tooltip.cpp

+ 1
- 0
include/app.hpp View File

@@ -312,6 +312,7 @@ struct SVGScrew : FramebufferWidget {
struct Toolbar : OpaqueWidget { struct Toolbar : OpaqueWidget {
Slider *wireOpacitySlider; Slider *wireOpacitySlider;
Slider *wireTensionSlider; Slider *wireTensionSlider;
Slider *zoomSlider;
RadioButton *cpuUsageButton; RadioButton *cpuUsageButton;
RadioButton *plugLightButton; RadioButton *plugLightButton;




+ 2
- 0
include/gui.hpp View File

@@ -21,6 +21,8 @@ extern NVGcontext *gFramebufferVg;
extern std::shared_ptr<Font> gGuiFont; extern std::shared_ptr<Font> gGuiFont;
extern float gPixelRatio; extern float gPixelRatio;
extern bool gAllowCursorLock; extern bool gAllowCursorLock;
extern int gGuiFrame;
extern Vec gMousePos;




void guiInit(); void guiInit();


+ 6
- 0
include/math.hpp View File

@@ -191,6 +191,12 @@ struct Vec {
Vec round() { Vec round() {
return Vec(roundf(x), roundf(y)); return Vec(roundf(x), roundf(y));
} }
Vec floor() {
return Vec(floorf(x), floorf(y));
}
Vec ceil() {
return Vec(ceilf(x), ceilf(y));
}
bool isZero() { bool isZero() {
return x == 0.0 && y == 0.0; return x == 0.0 && y == 0.0;
} }


+ 1
- 6
include/widgets.hpp View File

@@ -216,10 +216,6 @@ Events are not passed to the underlying scene.
struct FramebufferWidget : virtual Widget { struct FramebufferWidget : virtual Widget {
/** Set this to true to re-render the children to the framebuffer in the next step() override */ /** Set this to true to re-render the children to the framebuffer in the next step() override */
bool dirty = true; bool dirty = true;
/** A margin in pixels around the children in the framebuffer
This prevents cutting the rendered SVG off on the box edges.
*/
float oversample = 2.0;
/** The root object in the framebuffer scene /** The root object in the framebuffer scene
The FramebufferWidget owns the pointer The FramebufferWidget owns the pointer
*/ */
@@ -353,6 +349,7 @@ struct Slider : OpaqueWidget, QuantityWidget {
void onDragStart() override; void onDragStart() override;
void onDragMove(Vec mouseRel) override; void onDragMove(Vec mouseRel) override;
void onDragEnd() override; void onDragEnd() override;
void onMouseDownOpaque(int button) override;
}; };


/** Parent must be a ScrollWidget */ /** Parent must be a ScrollWidget */
@@ -438,12 +435,10 @@ struct Scene : OpaqueWidget {
// globals // globals
//////////////////// ////////////////////


extern Vec gMousePos;
extern Widget *gHoveredWidget; extern Widget *gHoveredWidget;
extern Widget *gDraggedWidget; extern Widget *gDraggedWidget;
extern Widget *gDragHoveredWidget; extern Widget *gDragHoveredWidget;
extern Widget *gFocusedWidget; extern Widget *gFocusedWidget;
extern int gGuiFrame;


extern Scene *gScene; extern Scene *gScene;




+ 3
- 1
src/app/RackScene.cpp View File

@@ -31,7 +31,6 @@ RackScene::RackScene() {
scrollWidget = new RackScrollWidget(); scrollWidget = new RackScrollWidget();
{ {
zoomWidget = new ZoomWidget(); zoomWidget = new ZoomWidget();
zoomWidget->zoom = 0.5;
{ {
assert(!gRackWidget); assert(!gRackWidget);
gRackWidget = new RackWidget(); gRackWidget = new RackWidget();
@@ -63,6 +62,9 @@ void RackScene::step() {
.plus(Vec(500, 500)) .plus(Vec(500, 500))
.div(zoomWidget->zoom); .div(zoomWidget->zoom);


// Set zoom from the toolbar's zoom slider
zoomWidget->zoom = gToolbar->zoomSlider->value / 100.0;

Scene::step(); Scene::step();


zoomWidget->box.size = gRackWidget->box.size.mult(zoomWidget->zoom); zoomWidget->box.size = gRackWidget->box.size.mult(zoomWidget->zoom);


+ 1
- 0
src/app/RackScrollWidget.cpp View File

@@ -1,4 +1,5 @@
#include "app.hpp" #include "app.hpp"
#include "gui.hpp"




namespace rack { namespace rack {


+ 3
- 3
src/app/RackWidget.cpp View File

@@ -189,9 +189,9 @@ void RackWidget::fromJson(json_t *rootJ) {
// version // version
json_t *versionJ = json_object_get(rootJ, "version"); json_t *versionJ = json_object_get(rootJ, "version");
if (versionJ) { if (versionJ) {
const char *version = json_string_value(versionJ);
if (gApplicationVersion != version)
message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version, gApplicationVersion.c_str());
std::string version = json_string_value(versionJ);
if (!version.empty() && gApplicationVersion != version)
message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version.c_str(), gApplicationVersion.empty() ? "dev" : gApplicationVersion.c_str());
} }


// modules // modules


+ 14
- 1
src/app/Toolbar.cpp View File

@@ -139,13 +139,26 @@ Toolbar::Toolbar() {
wireTensionSlider->box.pos = Vec(xPos, margin); wireTensionSlider->box.pos = Vec(xPos, margin);
wireTensionSlider->box.size.x = 150; wireTensionSlider->box.size.x = 150;
wireTensionSlider->label = "Cable tension"; wireTensionSlider->label = "Cable tension";
// wireTensionSlider->unit = "";
wireTensionSlider->unit = "";
wireTensionSlider->setLimits(0.0, 1.0); wireTensionSlider->setLimits(0.0, 1.0);
wireTensionSlider->setDefaultValue(0.5); wireTensionSlider->setDefaultValue(0.5);
addChild(wireTensionSlider); addChild(wireTensionSlider);
xPos += wireTensionSlider->box.size.x; xPos += wireTensionSlider->box.size.x;
} }


xPos += margin;
{
zoomSlider = new Slider();
zoomSlider->box.pos = Vec(xPos, margin);
zoomSlider->box.size.x = 150;
zoomSlider->label = "Zoom";
zoomSlider->unit = "%";
zoomSlider->setLimits(50.0, 200.0);
zoomSlider->setDefaultValue(100.0);
addChild(zoomSlider);
xPos += zoomSlider->box.size.x;
}

xPos += margin; xPos += margin;
{ {
plugLightButton = new RadioButton(); plugLightButton = new RadioButton();


+ 1
- 0
src/app/WireWidget.cpp View File

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




namespace rack { namespace rack {


+ 2
- 0
src/gui.cpp View File

@@ -33,6 +33,8 @@ NVGcontext *gFramebufferVg = NULL;
std::shared_ptr<Font> gGuiFont; std::shared_ptr<Font> gGuiFont;
float gPixelRatio = 0.0; float gPixelRatio = 0.0;
bool gAllowCursorLock = true; bool gAllowCursorLock = true;
int gGuiFrame;
Vec gMousePos;




void windowSizeCallback(GLFWwindow* window, int width, int height) { void windowSizeCallback(GLFWwindow* window, int width, int height) {


+ 10
- 0
src/settings.cpp View File

@@ -27,6 +27,11 @@ static json_t *settingsToJson() {
json_t *tensionJ = json_real(tension); json_t *tensionJ = json_real(tension);
json_object_set_new(rootJ, "wireTension", tensionJ); json_object_set_new(rootJ, "wireTension", tensionJ);


// zoom
float zoom = gToolbar->zoomSlider->value;
json_t *zoomJ = json_real(zoom);
json_object_set_new(rootJ, "zoom", zoomJ);

// allowCursorLock // allowCursorLock
json_t *allowCursorLockJ = json_boolean(gAllowCursorLock); json_t *allowCursorLockJ = json_boolean(gAllowCursorLock);
json_object_set_new(rootJ, "allowCursorLock", allowCursorLockJ); json_object_set_new(rootJ, "allowCursorLock", allowCursorLockJ);
@@ -62,6 +67,11 @@ static void settingsFromJson(json_t *rootJ) {
if (tensionJ) if (tensionJ)
gToolbar->wireTensionSlider->value = json_number_value(tensionJ); gToolbar->wireTensionSlider->value = json_number_value(tensionJ);


// zoom
json_t *zoomJ = json_object_get(rootJ, "zoom");
if (zoomJ)
gToolbar->zoomSlider->value = json_number_value(zoomJ);

// allowCursorLock // allowCursorLock
json_t *allowCursorLockJ = json_object_get(rootJ, "allowCursorLock"); json_t *allowCursorLockJ = json_object_get(rootJ, "allowCursorLock");
if (allowCursorLockJ) if (allowCursorLockJ)


+ 0
- 2
src/widgets.cpp View File

@@ -2,12 +2,10 @@


namespace rack { namespace rack {


Vec gMousePos;
Widget *gHoveredWidget = NULL; Widget *gHoveredWidget = NULL;
Widget *gDraggedWidget = NULL; Widget *gDraggedWidget = NULL;
Widget *gDragHoveredWidget = NULL; Widget *gDragHoveredWidget = NULL;
Widget *gFocusedWidget = NULL; Widget *gFocusedWidget = NULL;
int gGuiFrame;


Scene *gScene = NULL; Scene *gScene = NULL;




+ 44
- 22
src/widgets/FramebufferWidget.cpp View File

@@ -9,9 +9,16 @@
namespace rack { namespace rack {




/** A margin in pixels around the children in the framebuffer
This prevents cutting the rendered SVG off on the box edges.
*/
static const float oversample = 2.0;


struct FramebufferWidget::Internal { struct FramebufferWidget::Internal {
NVGLUframebuffer *fb = NULL; NVGLUframebuffer *fb = NULL;
Rect box; Rect box;
Vec lastS;


~Internal() { ~Internal() {
setFramebuffer(NULL); setFramebuffer(NULL);
@@ -33,10 +40,31 @@ FramebufferWidget::~FramebufferWidget() {
} }


void FramebufferWidget::draw(NVGcontext *vg) { void FramebufferWidget::draw(NVGcontext *vg) {
// Bypass framebuffer rendering entirely
// Widget::draw(vg);
// return;

// Get world transform
float xform[6];
nvgCurrentTransform(vg, xform);
// Skew is not supported
assert(fabsf(xform[1]) < 1e-6);
assert(fabsf(xform[2]) < 1e-6);
Vec s = Vec(xform[0], xform[3]);
Vec b = Vec(xform[4], xform[5]);

if (gGuiFrame % 10 == 0) {
// Check if scale has changed
if (s.x != internal->lastS.x || s.y != internal->lastS.y) {
dirty = true;
}
internal->lastS = s;
}

// Render to framebuffer
if (dirty) { if (dirty) {
internal->box.pos = Vec(0, 0); internal->box.pos = Vec(0, 0);
internal->box.size = box.size;
internal->box.size = Vec(ceilf(internal->box.size.x), ceilf(internal->box.size.y));
internal->box.size = box.size.mult(s).ceil();
Vec fbSize = internal->box.size.mult(gPixelRatio * oversample); Vec fbSize = internal->box.size.mult(gPixelRatio * oversample);


// assert(fbSize.isFinite()); // assert(fbSize.isFinite());
@@ -60,6 +88,8 @@ void FramebufferWidget::draw(NVGcontext *vg) {
nvgBeginFrame(gFramebufferVg, fbSize.x, fbSize.y, gPixelRatio * oversample); nvgBeginFrame(gFramebufferVg, fbSize.x, fbSize.y, gPixelRatio * oversample);


nvgScale(gFramebufferVg, gPixelRatio * oversample, gPixelRatio * oversample); nvgScale(gFramebufferVg, gPixelRatio * oversample, gPixelRatio * oversample);
// Use local scaling
nvgScale(gFramebufferVg, s.x, s.y);
Widget::draw(gFramebufferVg); Widget::draw(gFramebufferVg);


nvgEndFrame(gFramebufferVg); nvgEndFrame(gFramebufferVg);
@@ -72,32 +102,24 @@ void FramebufferWidget::draw(NVGcontext *vg) {
return; return;
} }


// Draw framebuffer image
// Draw framebuffer image, using world coordinates
b = b.round();
nvgSave(vg);
nvgResetTransform(vg);
nvgTranslate(vg, b.x, b.y);

nvgBeginPath(vg); nvgBeginPath(vg);
nvgRect(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y); nvgRect(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y);
NVGpaint paint = nvgImagePattern(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y, 0.0, internal->fb->image, 1.0); NVGpaint paint = nvgImagePattern(vg, internal->box.pos.x, internal->box.pos.y, internal->box.size.x, internal->box.size.y, 0.0, internal->fb->image, 1.0);
nvgFillPaint(vg, paint); nvgFillPaint(vg, paint);
nvgFill(vg); nvgFill(vg);


// For debugging bounding box of framebuffer image
// nvgFillColor(vg, nvgRGBA(255, 0, 0, 64));
// nvgFill(vg);

{
float xform[6];
nvgCurrentTransform(vg, xform);
// printf("%f %f %f %f; %f %f\n", xform[0], xform[1], xform[2], xform[3], xform[4], xform[5]);
nvgSave(vg);
nvgResetTransform(vg);
nvgTranslate(vg, xform[4], xform[5]);
nvgScale(vg, xform[0], xform[3]);
nvgBeginPath(vg);
nvgRect(vg, 0, 0, internal->box.size.x, internal->box.size.y);
nvgStrokeWidth(vg, 2.0);
nvgStrokeColor(vg, nvgRGBf(1.0, 0.0, 0.0));
nvgStroke(vg);
nvgRestore(vg);
}
// For debugging the bounding box of the framebuffer
// nvgStrokeWidth(vg, 2.0);
// nvgStrokeColor(vg, nvgRGBA(255, 0, 0, 128));
// nvgStroke(vg);

nvgRestore(vg);
} }


int FramebufferWidget::getImageHandle() { int FramebufferWidget::getImageHandle() {


+ 1
- 0
src/widgets/Scene.cpp View File

@@ -1,4 +1,5 @@
#include "widgets.hpp" #include "widgets.hpp"
#include "gui.hpp"




namespace rack { namespace rack {


+ 6
- 0
src/widgets/Slider.cpp View File

@@ -25,5 +25,11 @@ void Slider::onDragEnd() {
guiCursorUnlock(); guiCursorUnlock();
} }


void Slider::onMouseDownOpaque(int button) {
if (button == 1) {
setValue(defaultValue);
}
}



} // namespace rack } // namespace rack

+ 4
- 0
src/widgets/TextField.cpp View File

@@ -18,6 +18,10 @@ void TextField::draw(NVGcontext *vg) {
state = BND_DEFAULT; state = BND_DEFAULT;


bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end); bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end);
// Draw placeholder text
if (text.empty() && state != BND_ACTIVE) {
bndIconLabelCaret(vg, 0.0, 0.0, box.size.x, box.size.y, -1, bndGetTheme()->textFieldTheme.itemColor, 13, placeholder.c_str(), bndGetTheme()->textFieldTheme.itemColor, 0, -1);
}
} }


Widget *TextField::onMouseDown(Vec pos, int button) { Widget *TextField::onMouseDown(Vec pos, int button) {


+ 1
- 0
src/widgets/Tooltip.cpp View File

@@ -1,4 +1,5 @@
#include "widgets.hpp" #include "widgets.hpp"
#include "gui.hpp"




namespace rack { namespace rack {


Loading…
Cancel
Save