The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

272 lines
8.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. ColourGradient::ColourGradient() noexcept : isRadial (false)
  22. {
  23. #if JUCE_DEBUG
  24. point1.setX (987654.0f);
  25. #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED jassert (point1.x != 987654.0f);
  26. #else
  27. #define JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED
  28. #endif
  29. }
  30. ColourGradient::ColourGradient (const ColourGradient& other)
  31. : point1 (other.point1), point2 (other.point2), isRadial (other.isRadial), colours (other.colours)
  32. {}
  33. ColourGradient::ColourGradient (ColourGradient&& other) noexcept
  34. : point1 (other.point1), point2 (other.point2), isRadial (other.isRadial),
  35. colours (std::move (other.colours))
  36. {}
  37. ColourGradient& ColourGradient::operator= (const ColourGradient& other)
  38. {
  39. point1 = other.point1;
  40. point2 = other.point2;
  41. isRadial = other.isRadial;
  42. colours = other.colours;
  43. return *this;
  44. }
  45. ColourGradient& ColourGradient::operator= (ColourGradient&& other) noexcept
  46. {
  47. point1 = other.point1;
  48. point2 = other.point2;
  49. isRadial = other.isRadial;
  50. colours = std::move (other.colours);
  51. return *this;
  52. }
  53. ColourGradient::ColourGradient (Colour colour1, float x1, float y1,
  54. Colour colour2, float x2, float y2, bool radial)
  55. : ColourGradient (colour1, Point<float> (x1, y1),
  56. colour2, Point<float> (x2, y2), radial)
  57. {
  58. }
  59. ColourGradient::ColourGradient (Colour colour1, Point<float> p1,
  60. Colour colour2, Point<float> p2, bool radial)
  61. : point1 (p1),
  62. point2 (p2),
  63. isRadial (radial)
  64. {
  65. colours.add (ColourPoint { 0.0, colour1 },
  66. ColourPoint { 1.0, colour2 });
  67. }
  68. ColourGradient::~ColourGradient() {}
  69. ColourGradient ColourGradient::vertical (Colour c1, float y1, Colour c2, float y2)
  70. {
  71. return { c1, 0, y1, c2, 0, y2, false };
  72. }
  73. ColourGradient ColourGradient::horizontal (Colour c1, float x1, Colour c2, float x2)
  74. {
  75. return { c1, x1, 0, c2, x2, 0, false };
  76. }
  77. bool ColourGradient::operator== (const ColourGradient& other) const noexcept
  78. {
  79. return point1 == other.point1 && point2 == other.point2
  80. && isRadial == other.isRadial
  81. && colours == other.colours;
  82. }
  83. bool ColourGradient::operator!= (const ColourGradient& other) const noexcept
  84. {
  85. return ! operator== (other);
  86. }
  87. //==============================================================================
  88. void ColourGradient::clearColours()
  89. {
  90. colours.clear();
  91. }
  92. int ColourGradient::addColour (const double proportionAlongGradient, Colour colour)
  93. {
  94. // must be within the two end-points
  95. jassert (proportionAlongGradient >= 0 && proportionAlongGradient <= 1.0);
  96. if (proportionAlongGradient <= 0)
  97. {
  98. colours.set (0, { 0.0, colour });
  99. return 0;
  100. }
  101. auto pos = jmin (1.0, proportionAlongGradient);
  102. int i;
  103. for (i = 0; i < colours.size(); ++i)
  104. if (colours.getReference(i).position > pos)
  105. break;
  106. colours.insert (i, { pos, colour });
  107. return i;
  108. }
  109. void ColourGradient::removeColour (int index)
  110. {
  111. jassert (index > 0 && index < colours.size() - 1);
  112. colours.remove (index);
  113. }
  114. void ColourGradient::multiplyOpacity (const float multiplier) noexcept
  115. {
  116. for (auto& c : colours)
  117. c.colour = c.colour.withMultipliedAlpha (multiplier);
  118. }
  119. //==============================================================================
  120. int ColourGradient::getNumColours() const noexcept
  121. {
  122. return colours.size();
  123. }
  124. double ColourGradient::getColourPosition (int index) const noexcept
  125. {
  126. if (isPositiveAndBelow (index, colours.size()))
  127. return colours.getReference (index).position;
  128. return 0;
  129. }
  130. Colour ColourGradient::getColour (int index) const noexcept
  131. {
  132. if (isPositiveAndBelow (index, colours.size()))
  133. return colours.getReference (index).colour;
  134. return {};
  135. }
  136. void ColourGradient::setColour (int index, Colour newColour) noexcept
  137. {
  138. if (isPositiveAndBelow (index, colours.size()))
  139. colours.getReference (index).colour = newColour;
  140. }
  141. Colour ColourGradient::getColourAtPosition (double position) const noexcept
  142. {
  143. jassert (colours.getReference(0).position == 0.0); // the first colour specified has to go at position 0
  144. if (position <= 0 || colours.size() <= 1)
  145. return colours.getReference(0).colour;
  146. int i = colours.size() - 1;
  147. while (position < colours.getReference(i).position)
  148. --i;
  149. auto& p1 = colours.getReference (i);
  150. if (i >= colours.size() - 1)
  151. return p1.colour;
  152. auto& p2 = colours.getReference (i + 1);
  153. return p1.colour.interpolatedWith (p2.colour, (float) ((position - p1.position) / (p2.position - p1.position)));
  154. }
  155. //==============================================================================
  156. void ColourGradient::createLookupTable (PixelARGB* const lookupTable, const int numEntries) const noexcept
  157. {
  158. JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED // Trying to use this object without setting its coordinates?
  159. jassert (colours.size() >= 2);
  160. jassert (numEntries > 0);
  161. jassert (colours.getReference(0).position == 0.0); // The first colour specified has to go at position 0
  162. auto pix1 = colours.getReference (0).colour.getPixelARGB();
  163. int index = 0;
  164. for (int j = 1; j < colours.size(); ++j)
  165. {
  166. auto& p = colours.getReference (j);
  167. auto numToDo = roundToInt (p.position * (numEntries - 1)) - index;
  168. auto pix2 = p.colour.getPixelARGB();
  169. for (int i = 0; i < numToDo; ++i)
  170. {
  171. jassert (index >= 0 && index < numEntries);
  172. lookupTable[index] = pix1;
  173. lookupTable[index].tween (pix2, (uint32) ((i << 8) / numToDo));
  174. ++index;
  175. }
  176. pix1 = pix2;
  177. }
  178. while (index < numEntries)
  179. lookupTable [index++] = pix1;
  180. }
  181. int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock<PixelARGB>& lookupTable) const
  182. {
  183. JUCE_COLOURGRADIENT_CHECK_COORDS_INITIALISED // Trying to use this object without setting its coordinates?
  184. jassert (colours.size() >= 2);
  185. auto numEntries = jlimit (1, jmax (1, (colours.size() - 1) << 8),
  186. 3 * (int) point1.transformedBy (transform)
  187. .getDistanceFrom (point2.transformedBy (transform)));
  188. lookupTable.malloc (numEntries);
  189. createLookupTable (lookupTable, numEntries);
  190. return numEntries;
  191. }
  192. bool ColourGradient::isOpaque() const noexcept
  193. {
  194. for (auto& c : colours)
  195. if (! c.colour.isOpaque())
  196. return false;
  197. return true;
  198. }
  199. bool ColourGradient::isInvisible() const noexcept
  200. {
  201. for (auto& c : colours)
  202. if (! c.colour.isTransparent())
  203. return false;
  204. return true;
  205. }
  206. bool ColourGradient::ColourPoint::operator== (ColourPoint other) const noexcept
  207. {
  208. return position == other.position && colour == other.colour;
  209. }
  210. bool ColourGradient::ColourPoint::operator!= (ColourPoint other) const noexcept
  211. {
  212. return position != other.position || colour != other.colour;
  213. }
  214. } // namespace juce