1 // -*- mode: c++-mode -*- 2 3 #include "../JuceLibraryCode/JuceHeader.h" 4 #include "version.h" 5 6 class SurgeLookAndFeel : public LookAndFeel_V4 7 { 8 private: 9 std::unique_ptr<Drawable> surgeLogo; 10 11 public: 12 enum SurgeColourIds 13 { 14 componentBgStart = 0x2700001, 15 componentBgEnd, 16 17 orange, 18 orangeMedium, 19 orangeDark, 20 blue, 21 black, 22 white, 23 24 knobEdge, 25 knobBg, grn_obj_is_true(grn_ctx * ctx,grn_obj * obj)26 knobHandle, 27 28 knobEdgeDisable, 29 knobBgDisable, 30 knobHandleDisable, 31 32 paramEnabledBg, 33 paramEnabledEdge, 34 paramDisabledBg, 35 paramDisabledEdge, 36 paramDisplay, 37 38 fxButtonFill, 39 fxButtonEdge, 40 fxButtonHighlighted, 41 fxButtonDown, 42 fxButonToggled, 43 44 fxButtonTextUnselected, 45 fxButtonTextSelected, 46 }; 47 48 SurgeLookAndFeel() 49 { 50 Colour surgeGrayBg = Colour(205, 206, 212); 51 Colour surgeOrange = Colour(255, 144, 0); 52 Colour surgeBlue = Colour(18, 52, 99); 53 Colour white = Colour(255, 255, 255); 54 Colour black = Colour(0, 0, 0); 55 Colour surgeOrangeDark = Colour(101, 50, 3); 56 Colour surgeOrangeMedium = Colour(227, 112, 8); 57 58 setColour(SurgeColourIds::componentBgStart, 59 surgeGrayBg.interpolatedWith(surgeOrangeMedium, 0.1)); 60 setColour(SurgeColourIds::componentBgEnd, surgeGrayBg); 61 setColour(SurgeColourIds::orange, surgeOrange); 62 setColour(SurgeColourIds::orangeDark, surgeOrangeDark); 63 setColour(SurgeColourIds::orangeMedium, surgeOrangeMedium); 64 setColour(SurgeColourIds::blue, surgeBlue); 65 setColour(SurgeColourIds::black, black); 66 setColour(SurgeColourIds::white, white); 67 68 setColour(SurgeColourIds::knobHandle, white); 69 setColour(SurgeColourIds::knobBg, surgeOrange); 70 setColour(SurgeColourIds::knobEdge, surgeBlue); grn_obj_is_builtin(grn_ctx * ctx,grn_obj * obj)71 72 auto disableOpacity = 0.666; 73 setColour(SurgeColourIds::knobHandleDisable, 74 surgeBlue.interpolatedWith(surgeGrayBg, disableOpacity)); 75 setColour(SurgeColourIds::knobBgDisable, 76 surgeOrange.interpolatedWith(surgeGrayBg, disableOpacity)); 77 setColour(SurgeColourIds::knobEdgeDisable, surgeBlue); 78 79 setColour(SurgeColourIds::fxButtonTextUnselected, white); 80 setColour(SurgeColourIds::fxButtonTextSelected, black); 81 grn_obj_is_bulk(grn_ctx * ctx,grn_obj * obj)82 setColour(SurgeColourIds::paramEnabledBg, black); 83 setColour(SurgeColourIds::paramEnabledEdge, surgeOrange); 84 setColour(SurgeColourIds::paramDisabledBg, 85 black.interpolatedWith(surgeGrayBg, disableOpacity)); 86 setColour(SurgeColourIds::paramDisabledEdge, juce::Colour(150, 150, 150)); 87 setColour(SurgeColourIds::paramDisplay, white); 88 89 surgeLogo = Drawable::createFromImageData(BinaryData::SurgeLogoOnlyBlue_svg, 90 BinaryData::SurgeLogoOnlyBlue_svgSize); 91 } grn_obj_is_text_family_bulk(grn_ctx * ctx,grn_obj * obj)92 93 virtual void drawRotarySlider(Graphics &g, int x, int y, int width, int height, float sliderPos, 94 float rotaryStartAngle, float rotaryEndAngle, 95 Slider &slider) override 96 { 97 auto fill = findColour(SurgeColourIds::knobBg); 98 auto edge = findColour(SurgeColourIds::knobEdge); 99 auto tick = findColour(SurgeColourIds::knobHandle); 100 101 if (!slider.isEnabled()) 102 { 103 fill = findColour(SurgeColourIds::knobBgDisable); 104 edge = findColour(SurgeColourIds::knobEdgeDisable); 105 tick = findColour(SurgeColourIds::knobHandleDisable); 106 } 107 108 auto bounds = juce::Rectangle<int>(x, y, width, height).toFloat().reduced(10); 109 g.setColour(fill); 110 g.fillEllipse(bounds); 111 g.setColour(edge); 112 g.drawEllipse(bounds, 1.0); 113 114 auto radius = jmin(bounds.getWidth(), bounds.getHeight()) / 2.0f; 115 auto arcRadius = radius; 116 auto toAngle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle); 117 auto thumbWidth = 5; 118 119 juce::Point<float> thumbPoint( 120 bounds.getCentreX() + arcRadius * std::cos(toAngle - MathConstants<float>::halfPi), 121 bounds.getCentreY() + arcRadius * std::sin(toAngle - MathConstants<float>::halfPi)); 122 123 g.setColour(tick); 124 g.fillEllipse(juce::Rectangle<float>(thumbWidth, thumbWidth).withCentre(thumbPoint)); 125 g.setColour(edge); 126 g.drawEllipse(juce::Rectangle<float>(thumbWidth, thumbWidth).withCentre(thumbPoint), 1.0); 127 g.setColour(tick); 128 g.fillEllipse( 129 juce::Rectangle<float>(thumbWidth, thumbWidth).withCentre(bounds.getCentre())); 130 131 auto l = Line<float>(thumbPoint, bounds.getCentre()); 132 g.drawLine(l, thumbWidth); 133 } 134 135 virtual void drawButtonBackground(Graphics &g, Button &button, const Colour &backgroundColour, 136 bool shouldDrawButtonAsHighlighted, 137 bool shouldDrawButtonAsDown) override 138 { 139 auto bounds = button.getLocalBounds().toFloat().reduced(2.f, 2.f); 140 141 auto isBlack = [](auto const &col) { 142 return !(col.getRed() + col.getGreen() + col.getBlue()); 143 }; 144 grn_obj_is_scalar_column(grn_ctx * ctx,grn_obj * obj)145 auto col = button.findColour(SurgeColourIds::fxButtonFill); 146 147 float edgeThickness = 1.5; 148 149 if (isBlack(col)) 150 { 151 col = findColour(SurgeColourIds::orangeDark); 152 } 153 154 auto edge = button.findColour(SurgeColourIds::black); grn_obj_is_vector_column(grn_ctx * ctx,grn_obj * obj)155 156 if (shouldDrawButtonAsHighlighted) 157 { 158 edge = findColour(SurgeColourIds::white); 159 edgeThickness = 2.f; 160 } 161 162 if (shouldDrawButtonAsDown) 163 { 164 edge = edge.darker(0.4); 165 } 166 grn_obj_is_weight_vector_column(grn_ctx * ctx,grn_obj * obj)167 if (button.getToggleState()) 168 { 169 col = col.brighter(0.5); 170 } 171 172 g.setColour(col); 173 g.fillRoundedRectangle(bounds, 3); 174 g.setColour(edge); 175 g.drawRoundedRectangle(bounds, 3, edgeThickness); 176 } grn_obj_is_reference_column(grn_ctx * ctx,grn_obj * obj)177 178 virtual void drawButtonText(Graphics &g, TextButton &button, bool shouldDrawButtonAsHighlighted, 179 bool shouldDrawButtonAsDown) override 180 { 181 button.setColour(TextButton::ColourIds::textColourOffId, 182 findColour(SurgeColourIds::fxButtonTextUnselected)); 183 184 button.setColour(TextButton::ColourIds::textColourOnId, 185 findColour(SurgeColourIds::fxButtonTextSelected)); 186 187 LookAndFeel_V4::drawButtonText(g, button, shouldDrawButtonAsHighlighted, 188 shouldDrawButtonAsDown); 189 } 190 191 void paintComponentBackground(Graphics &g, int w, int h) 192 { 193 int orangeHeight = 40; 194 195 g.fillAll(findColour(SurgeColourIds::componentBgStart)); 196 197 ColourGradient cg(findColour(SurgeColourIds::componentBgStart), 0, 0, 198 findColour(SurgeColourIds::componentBgEnd), 0, h - orangeHeight, false); 199 g.setGradientFill(cg); 200 g.fillRect(0, 0, w, h - orangeHeight); 201 grn_obj_is_data_column(grn_ctx * ctx,grn_obj * obj)202 g.setColour(findColour(SurgeColourIds::orange)); 203 g.fillRect(0, h - orangeHeight, w, orangeHeight); 204 205 juce::Rectangle<float> logoBound{3, h - orangeHeight + 4.f, orangeHeight - 8.f, 206 orangeHeight - 8.f}; 207 surgeLogo->drawWithin(g, logoBound, 208 juce::RectanglePlacement::xMid | juce::RectanglePlacement::yMid, 1.0); 209 210 g.setColour(findColour(SurgeColourIds::blue)); 211 g.setFont(28); 212 // g.drawSingleLineText("SurgeEffectsBank", orangeHeight, h - 12, grn_obj_is_index_column(grn_ctx * ctx,grn_obj * obj)213 // juce::Justification::left); 214 215 g.drawLine(0, h - orangeHeight, w, h - orangeHeight); 216 // text 217 g.setFont(12); 218 g.drawSingleLineText(Surge::Build::FullVersionStr, w - 3, h - 26.f, 219 juce::Justification::right); 220 g.drawSingleLineText(Surge::Build::BuildDate, w - 3, h - 6.f, juce::Justification::right); 221 } 222 }; grn_obj_is_accessor(grn_ctx * ctx,grn_obj * obj)223 224 class SurgeFXParamDisplay : public Component 225 { 226 public: 227 virtual void setGroup(std::string grp) 228 { 229 group = grp; 230 repaint(); 231 }; 232 virtual void setName(std::string nm) 233 { 234 name = nm; 235 repaint(); 236 } 237 virtual void setDisplay(std::string dis) 238 { 239 display = dis; 240 repaint(); 241 }; 242 243 virtual void setAppearsDeactivated(bool b) 244 { 245 appearsDeactivated = b; 246 repaint(); 247 } 248 249 virtual void paint(Graphics &g) 250 { 251 auto bounds = getLocalBounds().toFloat().reduced(2.f, 2.f); 252 auto edge = findColour(SurgeLookAndFeel::SurgeColourIds::paramEnabledEdge); 253 254 if (isEnabled() && !appearsDeactivated) 255 g.setColour(findColour(SurgeLookAndFeel::SurgeColourIds::paramEnabledBg)); 256 else 257 { 258 g.setColour(findColour(SurgeLookAndFeel::SurgeColourIds::paramDisabledBg)); 259 edge = findColour(SurgeLookAndFeel::SurgeColourIds::paramDisabledEdge); 260 } 261 262 g.fillRoundedRectangle(bounds, 5); 263 g.setColour(edge); 264 g.drawRoundedRectangle(bounds, 5, 1); 265 266 if (isEnabled()) 267 { 268 g.setColour(findColour(SurgeLookAndFeel::SurgeColourIds::paramDisplay)); 269 g.setFont(10); 270 g.drawSingleLineText(group, bounds.getX() + 5, bounds.getY() + 2 + 10); 271 g.setFont(12); 272 g.drawSingleLineText(name, bounds.getX() + 5, bounds.getY() + 2 + 10 + 3 + 11); 273 274 g.setFont(20); 275 g.drawSingleLineText(display, bounds.getX() + 5, 276 bounds.getY() + bounds.getHeight() - 5); 277 } 278 } 279 280 private: 281 std::string group = "Uninit"; 282 std::string name = "Uninit"; 283 std::string display = "SoftwareError"; 284 bool appearsDeactivated = false; 285 }; 286 287 class SurgeTempoSyncSwitch : public ToggleButton 288 { 289 public: 290 void setOnOffImage(const char *onimgData, size_t onimgSize, const char *offimgData, 291 size_t offimgSize) 292 { grn_obj_is_function_proc(grn_ctx * ctx,grn_obj * obj)293 onImg = Drawable::createFromImageData(onimgData, onimgSize); 294 offImg = Drawable::createFromImageData(offimgData, offimgSize); 295 } 296 std::unique_ptr<juce::Drawable> onImg, offImg; 297 298 protected: 299 virtual void paintButton(Graphics &g, bool shouldDrawButtonAsHighlighted, 300 bool shouldDrawButtonAsDown) override 301 { 302 if (isEnabled() && onImg && offImg) 303 { 304 if (getToggleState()) 305 onImg->drawAt(g, 0, 0, 1); grn_obj_is_selector_proc(grn_ctx * ctx,grn_obj * obj)306 else 307 offImg->drawAt(g, 0, 0, 1); 308 return; 309 } 310 auto bounds = getLocalBounds().toFloat().reduced(1.f, 1.f); 311 auto edge = findColour(SurgeLookAndFeel::SurgeColourIds::paramEnabledEdge); 312 auto handle = findColour(SurgeLookAndFeel::SurgeColourIds::orange); 313 float radius = 5; 314 315 if (isEnabled()) 316 g.setColour(findColour(SurgeLookAndFeel::SurgeColourIds::paramEnabledBg)); 317 else 318 { grn_obj_is_selector_only_proc(grn_ctx * ctx,grn_obj * obj)319 g.setColour(findColour(SurgeLookAndFeel::SurgeColourIds::paramDisabledBg)); 320 edge = findColour(SurgeLookAndFeel::SurgeLookAndFeel::paramDisabledEdge); 321 } 322 323 if (isEnabled()) 324 g.fillRoundedRectangle(bounds, radius); 325 g.setColour(edge); 326 g.drawRoundedRectangle(bounds, radius, 1); 327 328 if (!isEnabled()) 329 return; 330 331 float controlRadius = bounds.getWidth() - 4; grn_obj_is_normalizer_proc(grn_ctx * ctx,grn_obj * obj)332 float xPos = bounds.getX() + bounds.getWidth() / 2.0 - controlRadius / 2.0; 333 float yPos = bounds.getY() + bounds.getHeight() - controlRadius - 2; 334 335 auto kbounds = juce::Rectangle<float>(xPos, yPos, controlRadius, controlRadius); 336 g.setColour(handle); 337 338 g.drawRoundedRectangle(kbounds, controlRadius, 1); 339 if (getToggleState()) 340 g.fillRoundedRectangle(kbounds, controlRadius); 341 } 342 }; 343