You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
5.1KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "componentlibrary.hpp"
  4. #include "window.hpp"
  5. #include "event.hpp"
  6. namespace rack {
  7. static void drawPlug(NVGcontext *vg, Vec pos, NVGcolor color) {
  8. NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);
  9. // Plug solid
  10. nvgBeginPath(vg);
  11. nvgCircle(vg, pos.x, pos.y, 9);
  12. nvgFillColor(vg, color);
  13. nvgFill(vg);
  14. // Border
  15. nvgStrokeWidth(vg, 1.0);
  16. nvgStrokeColor(vg, colorOutline);
  17. nvgStroke(vg);
  18. // Hole
  19. nvgBeginPath(vg);
  20. nvgCircle(vg, pos.x, pos.y, 5);
  21. nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
  22. nvgFill(vg);
  23. }
  24. static void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, NVGcolor color, float tension, float opacity) {
  25. NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10);
  26. NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);
  27. // Wire
  28. if (opacity > 0.0) {
  29. nvgSave(vg);
  30. nvgGlobalAlpha(vg, powf(opacity, 1.5));
  31. float dist = pos1.minus(pos2).norm();
  32. Vec slump;
  33. slump.y = (1.0 - tension) * (150.0 + 1.0*dist);
  34. Vec pos3 = pos1.plus(pos2).div(2).plus(slump);
  35. nvgLineJoin(vg, NVG_ROUND);
  36. // Shadow
  37. Vec pos4 = pos3.plus(slump.mult(0.08));
  38. nvgBeginPath(vg);
  39. nvgMoveTo(vg, pos1.x, pos1.y);
  40. nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y);
  41. nvgStrokeColor(vg, colorShadow);
  42. nvgStrokeWidth(vg, 5);
  43. nvgStroke(vg);
  44. // Wire outline
  45. nvgBeginPath(vg);
  46. nvgMoveTo(vg, pos1.x, pos1.y);
  47. nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y);
  48. nvgStrokeColor(vg, colorOutline);
  49. nvgStrokeWidth(vg, 5);
  50. nvgStroke(vg);
  51. // Wire solid
  52. nvgStrokeColor(vg, color);
  53. nvgStrokeWidth(vg, 3);
  54. nvgStroke(vg);
  55. nvgRestore(vg);
  56. }
  57. }
  58. static const NVGcolor wireColors[] = {
  59. nvgRGB(0xc9, 0xb7, 0x0e), // yellow
  60. nvgRGB(0xc9, 0x18, 0x47), // red
  61. nvgRGB(0x0c, 0x8e, 0x15), // green
  62. nvgRGB(0x09, 0x86, 0xad), // blue
  63. // nvgRGB(0x44, 0x44, 0x44), // black
  64. // nvgRGB(0x66, 0x66, 0x66), // gray
  65. // nvgRGB(0x88, 0x88, 0x88), // light gray
  66. // nvgRGB(0xaa, 0xaa, 0xaa), // white
  67. };
  68. static int lastWireColorId = -1;
  69. WireWidget::WireWidget() {
  70. lastWireColorId = (lastWireColorId + 1) % LENGTHOF(wireColors);
  71. color = wireColors[lastWireColorId];
  72. }
  73. WireWidget::~WireWidget() {
  74. outputPort = NULL;
  75. inputPort = NULL;
  76. updateWire();
  77. }
  78. void WireWidget::updateWire() {
  79. if (inputPort && outputPort) {
  80. // Check correct types
  81. assert(inputPort->type == Port::INPUT);
  82. assert(outputPort->type == Port::OUTPUT);
  83. if (!wire) {
  84. wire = new Wire;
  85. wire->outputModule = outputPort->module;
  86. wire->outputId = outputPort->portId;
  87. wire->inputModule = inputPort->module;
  88. wire->inputId = inputPort->portId;
  89. engineAddWire(wire);
  90. }
  91. }
  92. else {
  93. if (wire) {
  94. engineRemoveWire(wire);
  95. delete wire;
  96. wire = NULL;
  97. }
  98. }
  99. }
  100. Vec WireWidget::getOutputPos() {
  101. if (outputPort) {
  102. return outputPort->getRelativeOffset(outputPort->box.zeroPos().getCenter(), gRackWidget);
  103. }
  104. else if (hoveredOutputPort) {
  105. return hoveredOutputPort->getRelativeOffset(hoveredOutputPort->box.zeroPos().getCenter(), gRackWidget);
  106. }
  107. else {
  108. return gRackWidget->lastMousePos;
  109. }
  110. }
  111. Vec WireWidget::getInputPos() {
  112. if (inputPort) {
  113. return inputPort->getRelativeOffset(inputPort->box.zeroPos().getCenter(), gRackWidget);
  114. }
  115. else if (hoveredInputPort) {
  116. return hoveredInputPort->getRelativeOffset(hoveredInputPort->box.zeroPos().getCenter(), gRackWidget);
  117. }
  118. else {
  119. return gRackWidget->lastMousePos;
  120. }
  121. }
  122. json_t *WireWidget::toJson() {
  123. json_t *rootJ = json_object();
  124. std::string s = color::toHexString(color);
  125. json_object_set_new(rootJ, "color", json_string(s.c_str()));
  126. return rootJ;
  127. }
  128. void WireWidget::fromJson(json_t *rootJ) {
  129. json_t *colorJ = json_object_get(rootJ, "color");
  130. if (colorJ) {
  131. // Legacy v0.6.0 and earlier
  132. if (json_is_object(colorJ))
  133. color = jsonToColor(colorJ);
  134. else
  135. color = color::fromHexString(json_string_value(colorJ));
  136. }
  137. }
  138. void WireWidget::draw(NVGcontext *vg) {
  139. float opacity = gToolbar->wireOpacitySlider->value / 100.0;
  140. float tension = gToolbar->wireTensionSlider->value;
  141. WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
  142. if (activeWire) {
  143. // Draw as opaque if the wire is active
  144. if (activeWire == this)
  145. opacity = 1.0;
  146. }
  147. else {
  148. Port *hoveredPort = dynamic_cast<Port*>(event::gContext->hoveredWidget);
  149. if (hoveredPort && (hoveredPort == outputPort || hoveredPort == inputPort))
  150. opacity = 1.0;
  151. }
  152. Vec outputPos = getOutputPos();
  153. Vec inputPos = getInputPos();
  154. drawWire(vg, outputPos, inputPos, color, tension, opacity);
  155. }
  156. void WireWidget::drawPlugs(NVGcontext *vg) {
  157. // TODO Figure out a way to draw plugs first and wires last, and cut the plug portion of the wire off.
  158. Vec outputPos = getOutputPos();
  159. Vec inputPos = getInputPos();
  160. drawPlug(vg, outputPos, color);
  161. drawPlug(vg, inputPos, color);
  162. // Draw plug light
  163. // TODO
  164. // Only draw this when light is on top of the plug stack
  165. if (outputPort) {
  166. nvgSave(vg);
  167. nvgTranslate(vg, outputPos.x - 4, outputPos.y - 4);
  168. outputPort->plugLight->draw(vg);
  169. nvgRestore(vg);
  170. }
  171. if (inputPort) {
  172. nvgSave(vg);
  173. nvgTranslate(vg, inputPos.x - 4, inputPos.y - 4);
  174. inputPort->plugLight->draw(vg);
  175. nvgRestore(vg);
  176. }
  177. }
  178. } // namespace rack