Browse Source

Add engine::LightInfo and Module::configLight() helper for configuring the LightInfo. Add LightTooltip for LightWidgets.

tags/v2.0.0
Andrew Belt 4 years ago
parent
commit
6e35afb053
15 changed files with 270 additions and 55 deletions
  1. +12
    -0
      include/app/ModuleLightWidget.hpp
  2. +1
    -0
      include/app/MultiLightWidget.hpp
  3. +0
    -1
      include/app/PortWidget.hpp
  4. +34
    -0
      include/engine/LightInfo.hpp
  5. +39
    -14
      include/engine/Module.hpp
  6. +1
    -1
      include/settings.hpp
  7. +6
    -4
      src/app/CableWidget.cpp
  8. +6
    -6
      src/app/MenuBar.cpp
  9. +106
    -0
      src/app/ModuleLightWidget.cpp
  10. +5
    -0
      src/app/MultiLightWidget.cpp
  11. +15
    -11
      src/app/ParamWidget.cpp
  12. +15
    -13
      src/app/PortWidget.cpp
  13. +19
    -0
      src/engine/LightInfo.cpp
  14. +6
    -0
      src/engine/Module.cpp
  15. +5
    -5
      src/settings.cpp

+ 12
- 0
include/app/ModuleLightWidget.hpp View File

@@ -1,6 +1,7 @@
#pragma once
#include <app/common.hpp>
#include <app/MultiLightWidget.hpp>
#include <ui/Tooltip.hpp>
#include <engine/Module.hpp>


@@ -15,7 +16,18 @@ struct ModuleLightWidget : MultiLightWidget {
engine::Module* module = NULL;
int firstLightId;

ui::Tooltip* tooltip = NULL;

~ModuleLightWidget();
engine::Light* getLight(int colorId);
engine::LightInfo* getLightInfo();
void createTooltip();
void destroyTooltip();

void step() override;
void onHover(const event::Hover& e) override;
void onEnter(const event::Enter& e) override;
void onLeave(const event::Leave& e) override;
};




+ 1
- 0
include/app/MultiLightWidget.hpp View File

@@ -12,6 +12,7 @@ struct MultiLightWidget : LightWidget {
/** Colors of each value state */
std::vector<NVGcolor> baseColors;

int getNumColors();
void addBaseColor(NVGcolor baseColor);
/** Sets the color to a linear combination of the baseColors with the given weights */
void setBrightnesses(const std::vector<float>& brightnesses);


+ 0
- 1
include/app/PortWidget.hpp View File

@@ -18,7 +18,6 @@ struct PortWidget : widget::OpaqueWidget {
int portId;

ui::Tooltip* tooltip = NULL;
bool hovered = false;

MultiLightWidget* plugLight;



+ 34
- 0
include/engine/LightInfo.hpp View File

@@ -0,0 +1,34 @@
#pragma once
#include <common.hpp>


namespace rack {
namespace engine {


struct Module;


struct LightInfo {
Module* module = NULL;
int lightId;

/** The name of the light, using sentence capitalization.
e.g. "Level", "Pitch light", "Mode CV".

Don't use the word "light" or "LED" in the name.
Since this text is often prepended or appended to the name, the name will appear as e.g. "Level light light", "Light: Level light".
*/
std::string name;

/** An optional one-sentence description of the light. */
std::string description;

virtual ~LightInfo() {}
virtual std::string getName();
virtual std::string getDescription();
};


} // namespace engine
} // namespace rack

+ 39
- 14
include/engine/Module.hpp View File

@@ -11,6 +11,7 @@
#include <engine/Light.hpp>
#include <engine/ParamQuantity.hpp>
#include <engine/PortInfo.hpp>
#include <engine/LightInfo.hpp>


namespace rack {
@@ -43,9 +44,15 @@ struct Module {
std::vector<Input> inputs;
std::vector<Output> outputs;
std::vector<Light> lights;

/** Arrays of components.
Initialized with configParam(), configInput(), configOutput(), and configLight().
LightInfos are initialized to null unless configLight() is called.
*/
std::vector<ParamQuantity*> paramQuantities;
std::vector<PortInfo*> inputInfos;
std::vector<PortInfo*> outputInfos;
std::vector<LightInfo*> lightInfos;

/** Represents a message-passing channel for an adjacent module. */
struct Expander {
@@ -150,13 +157,13 @@ struct Module {
if (inputInfos[portId])
delete inputInfos[portId];

TPortInfo* p = new TPortInfo;
p->module = this;
p->type = Port::INPUT;
p->portId = portId;
p->name = name;
inputInfos[portId] = p;
return p;
TPortInfo* info = new TPortInfo;
info->module = this;
info->type = Port::INPUT;
info->portId = portId;
info->name = name;
inputInfos[portId] = info;
return info;
}

/** Helper for creating a PortInfo for an output port and setting its properties.
@@ -168,13 +175,31 @@ struct Module {
if (outputInfos[portId])
delete outputInfos[portId];

TPortInfo* p = new TPortInfo;
p->module = this;
p->type = Port::OUTPUT;
p->portId = portId;
p->name = name;
outputInfos[portId] = p;
return p;
TPortInfo* info = new TPortInfo;
info->module = this;
info->type = Port::OUTPUT;
info->portId = portId;
info->name = name;
outputInfos[portId] = info;
return info;
}

/** Helper for creating a LightInfo and setting its properties.
For multi-colored lights, use the first lightId.
See LightInfo for documentation of arguments.
*/
template <class TLightInfo = LightInfo>
TLightInfo* configLight(int lightId, std::string name = "") {
assert(lightId < (int) lights.size() && lightId < (int) lightInfos.size());
if (lightInfos[lightId])
delete lightInfos[lightId];

TLightInfo* info = new TLightInfo;
info->module = this;
info->lightId = lightId;
info->name = name;
lightInfos[lightId] = info;
return info;
}

/** Adds a direct route from an input to an output when the module is bypassed.


+ 1
- 1
include/settings.hpp View File

@@ -42,7 +42,7 @@ extern KnobMode knobMode;
extern float knobLinearSensitivity;
extern float sampleRate;
extern int threadCount;
extern bool paramTooltip;
extern bool tooltips;
extern bool cpuMeter;
extern bool lockModules;
extern int frameSwapInterval;


+ 6
- 4
src/app/CableWidget.cpp View File

@@ -5,6 +5,7 @@
#include <context.hpp>
#include <patch.hpp>
#include <settings.hpp>
#include <event.hpp>
#include <engine/Engine.hpp>
#include <engine/Port.hpp>

@@ -189,17 +190,18 @@ void CableWidget::draw(const DrawArgs& args) {

if (isComplete()) {
engine::Output* output = &cable->outputModule->outputs[cable->outputId];
// Draw opaque if mouse is hovering over a connected port
// Increase thickness if output port is polyphonic
if (output->channels > 1) {
// Increase thickness if output port is polyphonic
thickness = 9;
}

if (outputPort->hovered || inputPort->hovered) {
// Draw opaque if mouse is hovering over a connected port
Widget* hoveredWidget = APP->event->hoveredWidget;
if (outputPort == hoveredWidget || inputPort == hoveredWidget) {
opacity = 1.0;
}
// Draw translucent cable if not active (i.e. 0 channels)
else if (output->channels == 0) {
// Draw translucent cable if not active (i.e. 0 channels)
opacity *= 0.5;
}
}


+ 6
- 6
src/app/MenuBar.cpp View File

@@ -341,9 +341,9 @@ struct CableTensionSlider : ui::Slider {
}
};

struct ParamTooltipItem : ui::MenuItem {
struct TooltipsItem : ui::MenuItem {
void onAction(const event::Action& e) override {
settings::paramTooltip ^= true;
settings::tooltips ^= true;
}
};

@@ -423,10 +423,10 @@ struct ViewButton : MenuButton {
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
menu->box.size.x = box.size.x;

ParamTooltipItem* paramTooltipItem = new ParamTooltipItem;
paramTooltipItem->text = "Show tooltips";
paramTooltipItem->rightText = CHECKMARK(settings::paramTooltip);
menu->addChild(paramTooltipItem);
TooltipsItem* tooltipsItem = new TooltipsItem;
tooltipsItem->text = "Show tooltips";
tooltipsItem->rightText = CHECKMARK(settings::tooltips);
menu->addChild(tooltipsItem);

AllowCursorLockItem* allowCursorLockItem = new AllowCursorLockItem;
allowCursorLockItem->text = "Lock cursor when dragging parameters";


+ 106
- 0
src/app/ModuleLightWidget.cpp View File

@@ -1,10 +1,96 @@
#include <app/ModuleLightWidget.hpp>
#include <app/Scene.hpp>
#include <context.hpp>
#include <settings.hpp>


namespace rack {
namespace app {


struct LightTooltip : ui::Tooltip {
ModuleLightWidget* lightWidget;

void step() override {
if (lightWidget->module) {
engine::LightInfo* lightInfo = lightWidget->getLightInfo();
if (!lightInfo)
return;
// Label
text = lightInfo->getName();
text += " light";
// Description
std::string description = lightInfo->getDescription();
if (description != "") {
text += "\n";
text += description;
}
// Brightness for each color
text += "\n";
int numColors = lightWidget->getNumColors();
for (int colorId = 0; colorId < numColors; colorId++) {
if (colorId > 1)
text += " ";
engine::Light* light = lightWidget->getLight(colorId);
float brightness = math::clamp(light->getBrightness(), 0.f, 1.f);
text += string::f("% 3.0f%%", brightness * 100.f);
}
}
Tooltip::step();
// Position at bottom-right of parameter
box.pos = lightWidget->getAbsoluteOffset(lightWidget->box.size).round();
// Fit inside parent (copied from Tooltip.cpp)
assert(parent);
box = box.nudge(parent->box.zeroPos());
}
};


ModuleLightWidget::~ModuleLightWidget() {
destroyTooltip();
}


engine::Light* ModuleLightWidget::getLight(int colorId) {
if (!module)
return NULL;
return &module->lights[firstLightId + colorId];
}


engine::LightInfo* ModuleLightWidget::getLightInfo() {
if (!module)
return NULL;
return module->lightInfos[firstLightId];
}


void ModuleLightWidget::createTooltip() {
if (!settings::tooltips)
return;
if (this->tooltip)
return;
if (!module)
return;
// If the LightInfo is null, don't show a tooltip
if (!getLightInfo())
return;
LightTooltip* tooltip = new LightTooltip;
tooltip->lightWidget = this;
APP->scene->addChild(tooltip);
this->tooltip = tooltip;
}


void ModuleLightWidget::destroyTooltip() {
if (!tooltip)
return;
APP->scene->removeChild(tooltip);
delete tooltip;
tooltip = NULL;
}


void ModuleLightWidget::step() {
std::vector<float> brightnesses(baseColors.size());

@@ -32,5 +118,25 @@ void ModuleLightWidget::step() {
}


void ModuleLightWidget::onHover(const event::Hover& e) {
// Adapted from OpaqueWidget::onHover()
Widget::onHover(e);
e.stopPropagating();
// Consume if not consumed by child
if (!e.isConsumed())
e.consume(this);
}


void ModuleLightWidget::onEnter(const event::Enter& e) {
createTooltip();
}


void ModuleLightWidget::onLeave(const event::Leave& e) {
destroyTooltip();
}


} // namespace app
} // namespace rack

+ 5
- 0
src/app/MultiLightWidget.cpp View File

@@ -6,6 +6,11 @@ namespace rack {
namespace app {


int MultiLightWidget::getNumColors() {
return baseColors.size();
}


void MultiLightWidget::addBaseColor(NVGcolor baseColor) {
baseColors.push_back(baseColor);
}


+ 15
- 11
src/app/ParamWidget.cpp View File

@@ -152,20 +152,24 @@ engine::ParamQuantity* ParamWidget::getParamQuantity() {
}

void ParamWidget::createTooltip() {
if (settings::paramTooltip && !this->tooltip && module) {
ParamTooltip* tooltip = new ParamTooltip;
tooltip->paramWidget = this;
APP->scene->addChild(tooltip);
this->tooltip = tooltip;
}
if (!settings::tooltips)
return;
if (this->tooltip)
return;
if (!module)
return;
ParamTooltip* tooltip = new ParamTooltip;
tooltip->paramWidget = this;
APP->scene->addChild(tooltip);
this->tooltip = tooltip;
}

void ParamWidget::destroyTooltip() {
if (tooltip) {
APP->scene->removeChild(tooltip);
delete tooltip;
tooltip = NULL;
}
if (!tooltip)
return;
APP->scene->removeChild(tooltip);
delete tooltip;
tooltip = NULL;
}

void ParamWidget::step() {


+ 15
- 13
src/app/PortWidget.cpp View File

@@ -107,20 +107,24 @@ engine::PortInfo* PortWidget::getPortInfo() {
}

void PortWidget::createTooltip() {
if (settings::paramTooltip && !this->tooltip && module) {
PortTooltip* tooltip = new PortTooltip;
tooltip->portWidget = this;
APP->scene->addChild(tooltip);
this->tooltip = tooltip;
}
if (!settings::tooltips)
return;
if (this->tooltip)
return;
if (!module)
return;
PortTooltip* tooltip = new PortTooltip;
tooltip->portWidget = this;
APP->scene->addChild(tooltip);
this->tooltip = tooltip;
}

void PortWidget::destroyTooltip() {
if (tooltip) {
APP->scene->removeChild(tooltip);
delete tooltip;
tooltip = NULL;
}
if (!tooltip)
return;
APP->scene->removeChild(tooltip);
delete tooltip;
tooltip = NULL;
}

void PortWidget::step() {
@@ -169,12 +173,10 @@ void PortWidget::onButton(const event::Button& e) {
}

void PortWidget::onEnter(const event::Enter& e) {
hovered = true;
createTooltip();
}

void PortWidget::onLeave(const event::Leave& e) {
hovered = false;
destroyTooltip();
}



+ 19
- 0
src/engine/LightInfo.cpp View File

@@ -0,0 +1,19 @@
#include <engine/LightInfo.hpp>
#include <string.hpp>


namespace rack {
namespace engine {


std::string LightInfo::getName() {
return name;
}

std::string LightInfo::getDescription() {
return description;
}


} // namespace engine
} // namespace rack

+ 6
- 0
src/engine/Module.cpp View File

@@ -34,6 +34,10 @@ Module::~Module() {
if (outputInfo)
delete outputInfo;
}
for (LightInfo* lightInfo : lightInfos) {
if (lightInfo)
delete lightInfo;
}
delete internal;
}

@@ -59,6 +63,8 @@ void Module::config(int numParams, int numInputs, int numOutputs, int numLights)
for (int i = 0; i < numOutputs; i++) {
configOutput(i);
}
// Initialize LightInfos with null
lightInfos.resize(numLights);
}




+ 5
- 5
src/settings.cpp View File

@@ -28,7 +28,7 @@ KnobMode knobMode = KNOB_MODE_LINEAR;
float knobLinearSensitivity = 0.001f;
float sampleRate = 44100.0;
int threadCount = 1;
bool paramTooltip = true;
bool tooltips = true;
bool cpuMeter = false;
bool lockModules = false;
#if defined ARCH_MAC
@@ -82,7 +82,7 @@ json_t* toJson() {

json_object_set_new(rootJ, "threadCount", json_integer(threadCount));

json_object_set_new(rootJ, "paramTooltip", json_boolean(paramTooltip));
json_object_set_new(rootJ, "tooltips", json_boolean(tooltips));

json_object_set_new(rootJ, "cpuMeter", json_boolean(cpuMeter));

@@ -180,9 +180,9 @@ void fromJson(json_t* rootJ) {
if (threadCountJ)
threadCount = json_integer_value(threadCountJ);

json_t* paramTooltipJ = json_object_get(rootJ, "paramTooltip");
if (paramTooltipJ)
paramTooltip = json_boolean_value(paramTooltipJ);
json_t* tooltipsJ = json_object_get(rootJ, "tooltips");
if (tooltipsJ)
tooltips = json_boolean_value(tooltipsJ);

json_t* cpuMeterJ = json_object_get(rootJ, "cpuMeter");
if (cpuMeterJ)


Loading…
Cancel
Save