Add remaining files
[juce-lv2.git] / juce / source / src / gui / components / special / juce_ColourSelector.cpp
blobdcbfed5594fd48850c191495ad27078d086d0ca2
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_ColourSelector.h"
31 #include "../menus/juce_PopupMenu.h"
32 #include "../mouse/juce_MouseEvent.h"
33 #include "../../graphics/imaging/juce_Image.h"
34 #include "../../../text/juce_LocalisedStrings.h"
37 //==============================================================================
38 class ColourComponentSlider : public Slider
40 public:
41 ColourComponentSlider (const String& name)
42 : Slider (name)
44 setRange (0.0, 255.0, 1.0);
47 const String getTextFromValue (double value)
49 return String::toHexString ((int) value).toUpperCase().paddedLeft ('0', 2);
52 double getValueFromText (const String& text)
54 return (double) text.getHexValue32();
57 private:
58 JUCE_DECLARE_NON_COPYABLE (ColourComponentSlider);
61 //==============================================================================
62 class ColourSpaceMarker : public Component
64 public:
65 ColourSpaceMarker()
67 setInterceptsMouseClicks (false, false);
70 void paint (Graphics& g)
72 g.setColour (Colour::greyLevel (0.1f));
73 g.drawEllipse (1.0f, 1.0f, getWidth() - 2.0f, getHeight() - 2.0f, 1.0f);
74 g.setColour (Colour::greyLevel (0.9f));
75 g.drawEllipse (2.0f, 2.0f, getWidth() - 4.0f, getHeight() - 4.0f, 1.0f);
78 private:
79 JUCE_DECLARE_NON_COPYABLE (ColourSpaceMarker);
82 //==============================================================================
83 class ColourSelector::ColourSpaceView : public Component
85 public:
86 ColourSpaceView (ColourSelector& owner_,
87 float& h_, float& s_, float& v_,
88 const int edgeSize)
89 : owner (owner_),
90 h (h_), s (s_), v (v_),
91 lastHue (0.0f),
92 edge (edgeSize)
94 addAndMakeVisible (&marker);
95 setMouseCursor (MouseCursor::CrosshairCursor);
98 void paint (Graphics& g)
100 if (colours.isNull())
102 const int width = getWidth() / 2;
103 const int height = getHeight() / 2;
104 colours = Image (Image::RGB, width, height, false);
106 Image::BitmapData pixels (colours, Image::BitmapData::writeOnly);
108 for (int y = 0; y < height; ++y)
110 const float val = 1.0f - y / (float) height;
112 for (int x = 0; x < width; ++x)
114 const float sat = x / (float) width;
116 pixels.setPixelColour (x, y, Colour (h, sat, val, 1.0f));
121 g.setOpacity (1.0f);
122 g.drawImage (colours, edge, edge, getWidth() - edge * 2, getHeight() - edge * 2,
123 0, 0, colours.getWidth(), colours.getHeight());
126 void mouseDown (const MouseEvent& e)
128 mouseDrag (e);
131 void mouseDrag (const MouseEvent& e)
133 const float sat = (e.x - edge) / (float) (getWidth() - edge * 2);
134 const float val = 1.0f - (e.y - edge) / (float) (getHeight() - edge * 2);
136 owner.setSV (sat, val);
139 void updateIfNeeded()
141 if (lastHue != h)
143 lastHue = h;
144 colours = Image::null;
145 repaint();
148 updateMarker();
151 void resized()
153 colours = Image::null;
154 updateMarker();
157 private:
158 ColourSelector& owner;
159 float& h;
160 float& s;
161 float& v;
162 float lastHue;
163 ColourSpaceMarker marker;
164 const int edge;
165 Image colours;
167 void updateMarker()
169 marker.setBounds (roundToInt ((getWidth() - edge * 2) * s),
170 roundToInt ((getHeight() - edge * 2) * (1.0f - v)),
171 edge * 2, edge * 2);
174 JUCE_DECLARE_NON_COPYABLE (ColourSpaceView);
177 //==============================================================================
178 class HueSelectorMarker : public Component
180 public:
181 HueSelectorMarker()
183 setInterceptsMouseClicks (false, false);
186 void paint (Graphics& g)
188 Path p;
189 p.addTriangle (1.0f, 1.0f,
190 getWidth() * 0.3f, getHeight() * 0.5f,
191 1.0f, getHeight() - 1.0f);
193 p.addTriangle (getWidth() - 1.0f, 1.0f,
194 getWidth() * 0.7f, getHeight() * 0.5f,
195 getWidth() - 1.0f, getHeight() - 1.0f);
197 g.setColour (Colours::white.withAlpha (0.75f));
198 g.fillPath (p);
200 g.setColour (Colours::black.withAlpha (0.75f));
201 g.strokePath (p, PathStrokeType (1.2f));
204 private:
205 JUCE_DECLARE_NON_COPYABLE (HueSelectorMarker);
208 //==============================================================================
209 class ColourSelector::HueSelectorComp : public Component
211 public:
212 HueSelectorComp (ColourSelector& owner_,
213 float& h_, float& s_, float& v_,
214 const int edgeSize)
215 : owner (owner_),
216 h (h_), s (s_), v (v_),
217 lastHue (0.0f),
218 edge (edgeSize)
220 addAndMakeVisible (&marker);
223 void paint (Graphics& g)
225 const float yScale = 1.0f / (getHeight() - edge * 2);
227 const Rectangle<int> clip (g.getClipBounds());
229 for (int y = jmin (clip.getBottom(), getHeight() - edge); --y >= jmax (edge, clip.getY());)
231 g.setColour (Colour ((y - edge) * yScale, 1.0f, 1.0f, 1.0f));
232 g.fillRect (edge, y, getWidth() - edge * 2, 1);
236 void resized()
238 marker.setBounds (0, roundToInt ((getHeight() - edge * 2) * h),
239 getWidth(), edge * 2);
242 void mouseDown (const MouseEvent& e)
244 mouseDrag (e);
247 void mouseDrag (const MouseEvent& e)
249 owner.setHue ((e.y - edge) / (float) (getHeight() - edge * 2));
252 void updateIfNeeded()
254 resized();
257 private:
258 ColourSelector& owner;
259 float& h;
260 float& s;
261 float& v;
262 float lastHue;
263 HueSelectorMarker marker;
264 const int edge;
266 JUCE_DECLARE_NON_COPYABLE (HueSelectorComp);
269 //==============================================================================
270 class ColourSelector::SwatchComponent : public Component
272 public:
273 SwatchComponent (ColourSelector& owner_, int index_)
274 : owner (owner_), index (index_)
278 void paint (Graphics& g)
280 const Colour colour (owner.getSwatchColour (index));
282 g.fillCheckerBoard (getLocalBounds(), 6, 6,
283 Colour (0xffdddddd).overlaidWith (colour),
284 Colour (0xffffffff).overlaidWith (colour));
287 void mouseDown (const MouseEvent&)
289 PopupMenu m;
290 m.addItem (1, TRANS("Use this swatch as the current colour"));
291 m.addSeparator();
292 m.addItem (2, TRANS("Set this swatch to the current colour"));
294 m.showMenuAsync (PopupMenu::Options().withTargetComponent (this),
295 ModalCallbackFunction::forComponent (menuStaticCallback, this));
298 private:
299 ColourSelector& owner;
300 const int index;
302 static void menuStaticCallback (int result, SwatchComponent* comp)
304 if (comp != nullptr)
306 if (result == 1)
307 comp->setColourFromSwatch();
308 else if (result == 2)
309 comp->setSwatchFromColour();
313 void setColourFromSwatch()
315 owner.setCurrentColour (owner.getSwatchColour (index));
318 void setSwatchFromColour()
320 if (owner.getSwatchColour (index) != owner.getCurrentColour())
322 owner.setSwatchColour (index, owner.getCurrentColour());
323 repaint();
327 JUCE_DECLARE_NON_COPYABLE (SwatchComponent);
330 //==============================================================================
331 ColourSelector::ColourSelector (const int flags_,
332 const int edgeGap_,
333 const int gapAroundColourSpaceComponent)
334 : colour (Colours::white),
335 flags (flags_),
336 edgeGap (edgeGap_)
338 // not much point having a selector with no components in it!
339 jassert ((flags_ & (showColourAtTop | showSliders | showColourspace)) != 0);
341 updateHSV();
343 if ((flags & showSliders) != 0)
345 addAndMakeVisible (sliders[0] = new ColourComponentSlider (TRANS ("red")));
346 addAndMakeVisible (sliders[1] = new ColourComponentSlider (TRANS ("green")));
347 addAndMakeVisible (sliders[2] = new ColourComponentSlider (TRANS ("blue")));
348 addChildComponent (sliders[3] = new ColourComponentSlider (TRANS ("alpha")));
350 sliders[3]->setVisible ((flags & showAlphaChannel) != 0);
352 for (int i = 4; --i >= 0;)
353 sliders[i]->addListener (this);
356 if ((flags & showColourspace) != 0)
358 addAndMakeVisible (colourSpace = new ColourSpaceView (*this, h, s, v, gapAroundColourSpaceComponent));
359 addAndMakeVisible (hueSelector = new HueSelectorComp (*this, h, s, v, gapAroundColourSpaceComponent));
362 update();
365 ColourSelector::~ColourSelector()
367 dispatchPendingMessages();
368 swatchComponents.clear();
371 //==============================================================================
372 const Colour ColourSelector::getCurrentColour() const
374 return ((flags & showAlphaChannel) != 0) ? colour
375 : colour.withAlpha ((uint8) 0xff);
378 void ColourSelector::setCurrentColour (const Colour& c)
380 if (c != colour)
382 colour = ((flags & showAlphaChannel) != 0) ? c : c.withAlpha ((uint8) 0xff);
384 updateHSV();
385 update();
389 void ColourSelector::setHue (float newH)
391 newH = jlimit (0.0f, 1.0f, newH);
393 if (h != newH)
395 h = newH;
396 colour = Colour (h, s, v, colour.getFloatAlpha());
397 update();
401 void ColourSelector::setSV (float newS, float newV)
403 newS = jlimit (0.0f, 1.0f, newS);
404 newV = jlimit (0.0f, 1.0f, newV);
406 if (s != newS || v != newV)
408 s = newS;
409 v = newV;
410 colour = Colour (h, s, v, colour.getFloatAlpha());
411 update();
415 //==============================================================================
416 void ColourSelector::updateHSV()
418 colour.getHSB (h, s, v);
421 void ColourSelector::update()
423 if (sliders[0] != nullptr)
425 sliders[0]->setValue ((int) colour.getRed());
426 sliders[1]->setValue ((int) colour.getGreen());
427 sliders[2]->setValue ((int) colour.getBlue());
428 sliders[3]->setValue ((int) colour.getAlpha());
431 if (colourSpace != nullptr)
433 colourSpace->updateIfNeeded();
434 hueSelector->updateIfNeeded();
437 if ((flags & showColourAtTop) != 0)
438 repaint (previewArea);
440 sendChangeMessage();
443 //==============================================================================
444 void ColourSelector::paint (Graphics& g)
446 g.fillAll (findColour (backgroundColourId));
448 if ((flags & showColourAtTop) != 0)
450 const Colour currentColour (getCurrentColour());
452 g.fillCheckerBoard (previewArea, 10, 10,
453 Colour (0xffdddddd).overlaidWith (currentColour),
454 Colour (0xffffffff).overlaidWith (currentColour));
456 g.setColour (Colours::white.overlaidWith (currentColour).contrasting());
457 g.setFont (14.0f, true);
458 g.drawText (currentColour.toDisplayString ((flags & showAlphaChannel) != 0),
459 previewArea.getX(), previewArea.getY(), previewArea.getWidth(), previewArea.getHeight(),
460 Justification::centred, false);
463 if ((flags & showSliders) != 0)
465 g.setColour (findColour (labelTextColourId));
466 g.setFont (11.0f);
468 for (int i = 4; --i >= 0;)
470 if (sliders[i]->isVisible())
471 g.drawText (sliders[i]->getName() + ":",
472 0, sliders[i]->getY(),
473 sliders[i]->getX() - 8, sliders[i]->getHeight(),
474 Justification::centredRight, false);
479 void ColourSelector::resized()
481 const int swatchesPerRow = 8;
482 const int swatchHeight = 22;
484 const int numSliders = ((flags & showAlphaChannel) != 0) ? 4 : 3;
485 const int numSwatches = getNumSwatches();
487 const int swatchSpace = numSwatches > 0 ? edgeGap + swatchHeight * ((numSwatches + 7) / swatchesPerRow) : 0;
488 const int sliderSpace = ((flags & showSliders) != 0) ? jmin (22 * numSliders + edgeGap, proportionOfHeight (0.3f)) : 0;
489 const int topSpace = ((flags & showColourAtTop) != 0) ? jmin (30 + edgeGap * 2, proportionOfHeight (0.2f)) : edgeGap;
491 previewArea.setBounds (edgeGap, edgeGap, getWidth() - edgeGap * 2, topSpace - edgeGap * 2);
493 int y = topSpace;
495 if ((flags & showColourspace) != 0)
497 const int hueWidth = jmin (50, proportionOfWidth (0.15f));
499 colourSpace->setBounds (edgeGap, y,
500 getWidth() - hueWidth - edgeGap - 4,
501 getHeight() - topSpace - sliderSpace - swatchSpace - edgeGap);
503 hueSelector->setBounds (colourSpace->getRight() + 4, y,
504 getWidth() - edgeGap - (colourSpace->getRight() + 4),
505 colourSpace->getHeight());
507 y = getHeight() - sliderSpace - swatchSpace - edgeGap;
510 if ((flags & showSliders) != 0)
512 const int sliderHeight = jmax (4, sliderSpace / numSliders);
514 for (int i = 0; i < numSliders; ++i)
516 sliders[i]->setBounds (proportionOfWidth (0.2f), y,
517 proportionOfWidth (0.72f), sliderHeight - 2);
519 y += sliderHeight;
523 if (numSwatches > 0)
525 const int startX = 8;
526 const int xGap = 4;
527 const int yGap = 4;
528 const int swatchWidth = (getWidth() - startX * 2) / swatchesPerRow;
529 y += edgeGap;
531 if (swatchComponents.size() != numSwatches)
533 swatchComponents.clear();
535 for (int i = 0; i < numSwatches; ++i)
537 SwatchComponent* const sc = new SwatchComponent (*this, i);
538 swatchComponents.add (sc);
539 addAndMakeVisible (sc);
543 int x = startX;
545 for (int i = 0; i < swatchComponents.size(); ++i)
547 SwatchComponent* const sc = swatchComponents.getUnchecked(i);
549 sc->setBounds (x + xGap / 2,
550 y + yGap / 2,
551 swatchWidth - xGap,
552 swatchHeight - yGap);
554 if (((i + 1) % swatchesPerRow) == 0)
556 x = startX;
557 y += swatchHeight;
559 else
561 x += swatchWidth;
567 void ColourSelector::sliderValueChanged (Slider*)
569 if (sliders[0] != nullptr)
570 setCurrentColour (Colour ((uint8) sliders[0]->getValue(),
571 (uint8) sliders[1]->getValue(),
572 (uint8) sliders[2]->getValue(),
573 (uint8) sliders[3]->getValue()));
576 //==============================================================================
577 int ColourSelector::getNumSwatches() const
579 return 0;
582 const Colour ColourSelector::getSwatchColour (const int) const
584 jassertfalse; // if you've overridden getNumSwatches(), you also need to implement this method
585 return Colours::black;
588 void ColourSelector::setSwatchColour (const int, const Colour&) const
590 jassertfalse; // if you've overridden getNumSwatches(), you also need to implement this method
594 END_JUCE_NAMESPACE