#include #include #include #include namespace rack { namespace app { struct ModuleLightWidget::Internal { ui::Tooltip* tooltip = NULL; }; struct LightTooltip : ui::Tooltip { ModuleLightWidget* lightWidget; void step() override { if (lightWidget->module) { engine::LightInfo* lightInfo = lightWidget->getLightInfo(); if (!lightInfo) return; // Label std::string name = lightInfo->getName(); text = string::f(string::translate("ModuleLightWidget.light"), name); // 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() { internal = new Internal; } ModuleLightWidget::~ModuleLightWidget() { destroyTooltip(); delete internal; } engine::Light* ModuleLightWidget::getLight(int colorId) { if (!module) return NULL; if (firstLightId < 0) return NULL; return &module->lights[firstLightId + colorId]; } engine::LightInfo* ModuleLightWidget::getLightInfo() { if (!module) return NULL; if (firstLightId < 0) return NULL; return module->lightInfos[firstLightId]; } void ModuleLightWidget::createTooltip() { if (!settings::tooltips) return; if (internal->tooltip) 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); internal->tooltip = tooltip; } void ModuleLightWidget::destroyTooltip() { if (!internal->tooltip) return; APP->scene->removeChild(internal->tooltip); delete internal->tooltip; internal->tooltip = NULL; } void ModuleLightWidget::step() { std::vector brightnesses(baseColors.size()); int lastLightId = firstLightId + (int) baseColors.size(); if (module) { if (module->isBypassed()) { // Leave lights off } else if (0 <= firstLightId && lastLightId <= (int) module->lights.size()) { for (size_t i = 0; i < baseColors.size(); i++) { float b = module->lights[firstLightId + i].getBrightness(); if (!std::isfinite(b)) b = 0.f; b = math::clamp(b, 0.f, 1.f); // Because LEDs are nonlinear, this seems to look more natural. b = std::sqrt(b); brightnesses[i] = b; } } } else { // Turn all lights on for (size_t i = 0; i < baseColors.size(); i++) { brightnesses[i] = 1.f; } } setBrightnesses(brightnesses); MultiLightWidget::step(); } void ModuleLightWidget::onHover(const HoverEvent& e) { // Adapted from OpaqueWidget::onHover() Widget::onHover(e); // If the LightInfo is null, don't consume Hover event if (!getLightInfo()) return; e.stopPropagating(); // Consume if not consumed by child if (!e.isConsumed()) e.consume(this); } void ModuleLightWidget::onEnter(const EnterEvent& e) { createTooltip(); } void ModuleLightWidget::onLeave(const LeaveEvent& e) { destroyTooltip(); } } // namespace app } // namespace rack