Add possibility to show RGB/HSV/HSL sliders at the same time

This commit is contained in:
David Capello 2017-06-21 18:28:42 -03:00
parent 55646484f0
commit b3c83d6905
8 changed files with 389 additions and 338 deletions

View File

@ -96,9 +96,7 @@ private:
ButtonSet m_changeMode;
HexColorEntry m_hexColorEntry;
Label m_entryLabel;
RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders;
HslSliders m_hslSliders;
ColorSliders m_sliders;
// This variable is used to avoid updating the m_hexColorEntry text
// when the color change is generated from a
@ -274,18 +272,14 @@ PaletteEntryEditor::PaletteEntryEditor()
// Main vertical box
m_vbox.addChild(&m_topBox);
m_vbox.addChild(&m_rgbSliders);
m_vbox.addChild(&m_hsvSliders);
m_vbox.addChild(&m_hslSliders);
m_vbox.addChild(&m_sliders);
m_vbox.addChild(&m_bottomBox);
addChild(&m_vbox);
m_colorType.ItemChange.connect(base::Bind<void>(&PaletteEntryEditor::onColorTypeClick, this));
m_changeMode.ItemChange.connect(base::Bind<void>(&PaletteEntryEditor::onChangeModeClick, this));
m_rgbSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hsvSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hslSliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_sliders.ColorChange.connect(&PaletteEntryEditor::onColorSlidersChange, this);
m_hexColorEntry.ColorChange.connect(&PaletteEntryEditor::onColorHexEntryChange, this);
m_changeMode.setSelectedItem(ABS_MODE);
@ -312,9 +306,7 @@ PaletteEntryEditor::PaletteEntryEditor()
void PaletteEntryEditor::setColor(const app::Color& color)
{
m_rgbSliders.setColor(color);
m_hsvSliders.setColor(color);
m_hslSliders.setColor(color);
m_sliders.setColor(color);
if (!m_disableHexUpdate)
m_hexColorEntry.setColor(color);
@ -429,7 +421,7 @@ void PaletteEntryEditor::onColorSlidersChange(ColorSlidersChangeEvent& ev)
{
setColor(ev.color());
if (ev.mode() == ColorSliders::Absolute)
if (ev.mode() == ColorSliders::Mode::Absolute)
setAbsolutePaletteEntryChannel(ev.channel(), ev.color());
else
setRelativePaletteEntryChannel(ev.channel(), ev.delta());
@ -471,14 +463,10 @@ void PaletteEntryEditor::onChangeModeClick()
{
switch (m_changeMode.selectedItem()) {
case ABS_MODE:
m_rgbSliders.setMode(ColorSliders::Absolute);
m_hsvSliders.setMode(ColorSliders::Absolute);
m_hslSliders.setMode(ColorSliders::Absolute);
m_sliders.setMode(ColorSliders::Mode::Absolute);
break;
case REL_MODE:
m_rgbSliders.setMode(ColorSliders::Relative);
m_hsvSliders.setMode(ColorSliders::Relative);
m_hslSliders.setMode(ColorSliders::Relative);
m_sliders.setMode(ColorSliders::Mode::Relative);
break;
}
@ -537,15 +525,15 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
else {
// Setup the new RGB values depending of the modified channel.
switch (channel) {
case ColorSliders::Red:
case ColorSliders::Channel::Red:
r = color.getRed();
case ColorSliders::Green:
case ColorSliders::Channel::Green:
g = color.getGreen();
break;
case ColorSliders::Blue:
case ColorSliders::Channel::Blue:
b = color.getBlue();
break;
case ColorSliders::Alpha:
case ColorSliders::Channel::Alpha:
a = color.getAlpha();
break;
}
@ -569,16 +557,16 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
// Only modify the desired HSV channel
switch (channel) {
case ColorSliders::HsvHue:
case ColorSliders::Channel::HsvHue:
hsv.hue(color.getHsvHue());
break;
case ColorSliders::HsvSaturation:
case ColorSliders::Channel::HsvSaturation:
hsv.saturation(color.getHsvSaturation());
break;
case ColorSliders::HsvValue:
case ColorSliders::Channel::HsvValue:
hsv.value(color.getHsvValue());
break;
case ColorSliders::Alpha:
case ColorSliders::Channel::Alpha:
a = color.getAlpha();
break;
}
@ -609,16 +597,16 @@ void PaletteEntryEditor::setAbsolutePaletteEntryChannel(ColorSliders::Channel ch
// Only modify the desired HSL channel
switch (channel) {
case ColorSliders::HslHue:
case ColorSliders::Channel::HslHue:
hsl.hue(color.getHslHue());
break;
case ColorSliders::HslSaturation:
case ColorSliders::Channel::HslSaturation:
hsl.saturation(color.getHslSaturation());
break;
case ColorSliders::HslLightness:
case ColorSliders::Channel::HslLightness:
hsl.lightness(color.getHslLightness());
break;
case ColorSliders::Alpha:
case ColorSliders::Channel::Alpha:
a = color.getAlpha();
break;
}
@ -664,19 +652,19 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
switch (m_type) {
case app::Color::RgbType:
r = MID(0, r+m_relDeltas[ColorSliders::Red], 255);
g = MID(0, g+m_relDeltas[ColorSliders::Green], 255);
b = MID(0, b+m_relDeltas[ColorSliders::Blue], 255);
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
r = MID(0, r+m_relDeltas[ColorSliders::Channel::Red], 255);
g = MID(0, g+m_relDeltas[ColorSliders::Channel::Green], 255);
b = MID(0, b+m_relDeltas[ColorSliders::Channel::Blue], 255);
a = MID(0, a+m_relDeltas[ColorSliders::Channel::Alpha], 255);
break;
case app::Color::HsvType: {
// Convert RGB to HSV
Hsv hsv(Rgb(r, g, b));
double h = hsv.hue() +m_relDeltas[ColorSliders::HsvHue];
double s = hsv.saturation()+m_relDeltas[ColorSliders::HsvSaturation]/100.0;
double v = hsv.value() +m_relDeltas[ColorSliders::HsvValue] /100.0;
double h = hsv.hue() +m_relDeltas[ColorSliders::Channel::HsvHue];
double s = hsv.saturation()+m_relDeltas[ColorSliders::Channel::HsvSaturation]/100.0;
double v = hsv.value() +m_relDeltas[ColorSliders::Channel::HsvValue] /100.0;
if (h < 0.0) h += 360.0;
else if (h > 360.0) h -= 360.0;
@ -690,7 +678,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
r = rgb.red();
g = rgb.green();
b = rgb.blue();
a = MID(0, a+m_relDeltas[ColorSliders::Alpha], 255);
a = MID(0, a+m_relDeltas[ColorSliders::Channel::Alpha], 255);
break;
}
@ -698,9 +686,9 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
// Convert RGB to HSL
Hsl hsl(Rgb(r, g, b));
double h = hsl.hue() +m_relDeltas[ColorSliders::HslHue];
double s = hsl.saturation()+m_relDeltas[ColorSliders::HslSaturation]/100.0;
double l = hsl.lightness() +m_relDeltas[ColorSliders::HslLightness] /100.0;
double h = hsl.hue() +m_relDeltas[ColorSliders::Channel::HslHue];
double s = hsl.saturation()+m_relDeltas[ColorSliders::Channel::HslSaturation]/100.0;
double l = hsl.lightness() +m_relDeltas[ColorSliders::Channel::HslLightness] /100.0;
if (h < 0.0) h += 360.0;
else if (h > 360.0) h -= 360.0;
@ -727,9 +715,7 @@ void PaletteEntryEditor::setRelativePaletteEntryChannel(ColorSliders::Channel ch
void PaletteEntryEditor::selectColorType(app::Color::Type type)
{
m_type = type;
m_rgbSliders.setVisible(type == app::Color::RgbType);
m_hsvSliders.setVisible(type == app::Color::HsvType);
m_hslSliders.setVisible(type == app::Color::HslType);
m_sliders.setColorType(type);
resetRelativeInfo();
@ -822,9 +808,7 @@ void PaletteEntryEditor::onPalChange()
void PaletteEntryEditor::resetRelativeInfo()
{
m_rgbSliders.resetRelativeSliders();
m_hsvSliders.resetRelativeSliders();
m_hslSliders.resetRelativeSliders();
m_sliders.resetRelativeSliders();
get_current_palette()->copyColorsTo(&m_fromPalette);
m_relDeltas.clear();
}

View File

@ -42,23 +42,31 @@ public:
, m_filter(filter)
{
getContainer()->addChild(&m_sliders);
m_sliders.setMode(ColorSliders::Relative);
m_sliders.setColorType(app::Color::HslType);
m_sliders.setMode(ColorSliders::Mode::Relative);
m_sliders.ColorChange.connect(base::Bind<void>(&HueSaturationWindow::onChangeControls, this));
}
private:
void onChangeControls() {
m_filter.setHue(double(m_sliders.getRelSliderValue(0)));
m_filter.setSaturation(m_sliders.getRelSliderValue(1) / 100.0);
m_filter.setLightness(m_sliders.getRelSliderValue(2) / 100.0);
m_filter.setAlpha(m_sliders.getRelSliderValue(3));
m_filter.setHue(
double(m_sliders.getRelSliderValue(ColorSliders::Channel::HslHue)));
m_filter.setSaturation(
m_sliders.getRelSliderValue(ColorSliders::Channel::HslSaturation) / 100.0);
m_filter.setLightness(
m_sliders.getRelSliderValue(ColorSliders::Channel::HslLightness) / 100.0);
m_filter.setAlpha(
m_sliders.getRelSliderValue(ColorSliders::Channel::Alpha));
restartPreview();
}
HueSaturationFilter& m_filter;
HslSliders m_sliders;
ColorSliders m_sliders;
};
class HueSaturationCommand : public Command {

View File

@ -162,7 +162,7 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
if (mnemonicPressed ||
(hasFocus() && keymsg->scancode() == kKeySpace)) {
buttonSet()->setSelectedItem(this);
buttonSet()->onSelectItem(this, true, msg);
onClick();
}
}
@ -179,7 +179,7 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
}
captureMouse();
buttonSet()->setSelectedItem(this);
buttonSet()->onSelectItem(this, true, msg);
invalidate();
if (static_cast<MouseMessage*>(msg)->left() &&
@ -213,10 +213,15 @@ bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
// Only for ButtonSets trigerred on mouse up.
if (buttonSet()->m_triggerOnMouseUp &&
g_itemBeforeCapture >= 0) {
// As we never received a kMouseUpMessage (so we never
// called onClick()), we have to restore the selected
// item at the point when we received the mouse capture.
buttonSet()->setSelectedItem(g_itemBeforeCapture);
if (g_itemBeforeCapture < (int)children().size()) {
Item* item = dynamic_cast<Item*>(at(g_itemBeforeCapture));
ASSERT(item);
// As we never received a kMouseUpMessage (so we never
// called onClick()), we have to restore the selected
// item at the point when we received the mouse capture.
buttonSet()->onSelectItem(item, true, msg);
}
g_itemBeforeCapture = -1;
}
}
@ -304,6 +309,17 @@ ButtonSet::Item* ButtonSet::getItem(int index)
return dynamic_cast<Item*>(at(index));
}
int ButtonSet::getItemIndex(const Item* item) const
{
int index = 0;
for (Widget* child : children()) {
if (child == item)
return index;
++index;
}
return -1;
}
int ButtonSet::selectedItem() const
{
int index = 0;
@ -324,6 +340,11 @@ void ButtonSet::setSelectedItem(int index, bool focusItem)
}
void ButtonSet::setSelectedItem(Item* item, bool focusItem)
{
onSelectItem(item, focusItem, nullptr);
}
void ButtonSet::onSelectItem(Item* item, bool focusItem, ui::Message* msg)
{
if (!m_multipleSelection) {
if (item && item->isSelected())

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2016 David Capello
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -41,8 +41,10 @@ namespace app {
Item* addItem(const skin::SkinPartPtr& icon, int hspan = 1, int vspan = 1);
Item* addItem(Item* item, int hspan = 1, int vspan = 1);
Item* getItem(int index);
int getItemIndex(const Item* item) const;
int selectedItem() const;
Item* findSelectedItem() const;
void setSelectedItem(int index, bool focusItem = true);
void setSelectedItem(Item* item, bool focusItem = true);
void deselectItems();
@ -57,10 +59,9 @@ namespace app {
protected:
virtual void onItemChange(Item* item);
virtual void onRightClick(Item* item);
virtual void onSelectItem(Item* item, bool focusItem, ui::Message* msg);
private:
Item* findSelectedItem() const;
bool m_offerCapture;
bool m_triggerOnMouseUp;
bool m_multipleSelection;

View File

@ -116,6 +116,54 @@ public:
}
};
ColorPopup::CustomButtonSet::CustomButtonSet()
: ButtonSet(COLOR_MODES)
{
}
int ColorPopup::CustomButtonSet::countSelectedItems()
{
int count = 0;
for (int i=0; i<COLOR_MODES; ++i)
if (getItem(i)->isSelected())
++count;
return count;
}
void ColorPopup::CustomButtonSet::onSelectItem(Item* item, bool focusItem, ui::Message* msg)
{
int count = countSelectedItems();
int itemIndex = getItemIndex(item);
if (itemIndex == INDEX_MODE ||
itemIndex == MASK_MODE ||
!msg ||
// Any key modifier will act as multiple selection
(!msg->shiftPressed() &&
!msg->altPressed() &&
!msg->ctrlPressed() &&
!msg->cmdPressed())) {
if (item &&
item->isSelected() &&
count == 1)
return;
for (int i=0; i<COLOR_MODES; ++i)
if (getItem(i)->isSelected())
getItem(i)->setSelected(false);
}
if (item) {
// Item already selected
if (count == 1 && item == findSelectedItem())
return;
item->setSelected(!item->isSelected());
if (focusItem)
item->requestFocus();
}
}
ColorPopup::ColorPopup(const bool canPin,
bool showSimpleColors)
: PopupWindowPin(" ", // Non-empty to create title-bar and close button
@ -126,7 +174,6 @@ ColorPopup::ColorPopup(const bool canPin,
, m_color(app::Color::fromMask())
, m_colorPalette(false, PaletteView::SelectOneColor, this, 7*guiscale())
, m_simpleColors(nullptr)
, m_colorType(COLOR_MODES)
, m_maskLabel("Transparent Color Selected")
, m_canPin(canPin)
, m_disableHexUpdate(false)
@ -157,10 +204,7 @@ ColorPopup::ColorPopup(const bool canPin,
m_colorPaletteContainer.attachToView(&m_colorPalette);
m_colorPaletteContainer.setExpansive(true);
m_rgbSliders.setExpansive(true);
m_hsvSliders.setExpansive(true);
m_hslSliders.setExpansive(true);
m_graySlider.setExpansive(true);
m_sliders.setExpansive(true);
m_topBox.addChild(&m_colorType);
m_topBox.addChild(new Separator("", VERTICAL));
@ -192,19 +236,13 @@ ColorPopup::ColorPopup(const bool canPin,
m_vbox.addChild(m_simpleColors);
m_vbox.addChild(&m_topBox);
m_vbox.addChild(&m_colorPaletteContainer);
m_vbox.addChild(&m_rgbSliders);
m_vbox.addChild(&m_hsvSliders);
m_vbox.addChild(&m_hslSliders);
m_vbox.addChild(&m_graySlider);
m_vbox.addChild(&m_sliders);
m_vbox.addChild(&m_maskLabel);
addChild(&m_vbox);
m_colorType.ItemChange.connect(base::Bind<void>(&ColorPopup::onColorTypeClick, this));
m_rgbSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_hsvSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_hslSliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_graySlider.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_sliders.ColorChange.connect(&ColorPopup::onColorSlidersChange, this);
m_hexColorEntry.ColorChange.connect(&ColorPopup::onColorHexEntryChange, this);
// Set RGB just for the sizeHint(), and then deselect the color type
@ -244,10 +282,7 @@ void ColorPopup::setColor(const app::Color& color, SetColorOptions options)
m_colorPalette.selectColor(color.getIndex());
}
m_rgbSliders.setColor(m_color);
m_hsvSliders.setColor(m_color);
m_hslSliders.setColor(m_color);
m_graySlider.setColor(m_color);
m_sliders.setColor(m_color);
if (!m_disableHexUpdate)
m_hexColorEntry.setColor(m_color);
@ -404,21 +439,31 @@ void ColorPopup::setColorWithSignal(const app::Color& color)
void ColorPopup::selectColorType(app::Color::Type type)
{
m_colorPaletteContainer.setVisible(type == app::Color::IndexType);
m_rgbSliders.setVisible(type == app::Color::RgbType);
m_hsvSliders.setVisible(type == app::Color::HsvType);
m_hslSliders.setVisible(type == app::Color::HslType);
m_graySlider.setVisible(type == app::Color::GrayType);
m_maskLabel.setVisible(type == app::Color::MaskType);
switch (type) {
case app::Color::IndexType: m_colorType.setSelectedItem(INDEX_MODE); break;
case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break;
case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break;
case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break;
case app::Color::GrayType: m_colorType.setSelectedItem(GRAY_MODE); break;
case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break;
// Count selected items.
if (m_colorType.countSelectedItems() < 2) {
switch (type) {
case app::Color::IndexType: m_colorType.setSelectedItem(INDEX_MODE); break;
case app::Color::RgbType: m_colorType.setSelectedItem(RGB_MODE); break;
case app::Color::HsvType: m_colorType.setSelectedItem(HSV_MODE); break;
case app::Color::HslType: m_colorType.setSelectedItem(HSL_MODE); break;
case app::Color::GrayType: m_colorType.setSelectedItem(GRAY_MODE); break;
case app::Color::MaskType: m_colorType.setSelectedItem(MASK_MODE); break;
}
}
std::vector<app::Color::Type> types;
if (m_colorType.getItem(RGB_MODE)->isSelected())
types.push_back(app::Color::RgbType);
if (m_colorType.getItem(HSV_MODE)->isSelected())
types.push_back(app::Color::HsvType);
if (m_colorType.getItem(HSL_MODE)->isSelected())
types.push_back(app::Color::HslType);
if (m_colorType.getItem(GRAY_MODE)->isSelected())
types.push_back(app::Color::GrayType);
m_sliders.setColorTypes(types);
// Remove focus from hidden RGB/HSV/HSL text entries
auto widget = manager()->getFocus();
if (widget && !widget->isVisible()) {

View File

@ -59,6 +59,13 @@ namespace app {
void findBestfitIndex(const app::Color& color);
class SimpleColors;
class CustomButtonSet : public ButtonSet {
public:
CustomButtonSet();
int countSelectedItems();
private:
void onSelectItem(Item* item, bool focusItem, ui::Message* msg) override;
};
ui::Box m_vbox;
ui::TooltipManager m_tooltips;
@ -67,12 +74,9 @@ namespace app {
ui::View m_colorPaletteContainer;
PaletteView m_colorPalette;
SimpleColors* m_simpleColors;
ButtonSet m_colorType;
CustomButtonSet m_colorType;
HexColorEntry m_hexColorEntry;
RgbSliders m_rgbSliders;
HsvSliders m_hsvSliders;
HslSliders m_hslSliders;
GraySlider m_graySlider;
ColorSliders m_sliders;
ui::Label m_maskLabel;
obs::scoped_connection m_onPaletteChangeConn;
bool m_canPin;

View File

@ -50,7 +50,7 @@ namespace {
void paint(Slider* slider, Graphics* g, const gfx::Rect& rc) {
// Special alpha bar (with two vertical lines)
if (m_channel == ColorSliders::Alpha) {
if (m_channel == ColorSliders::Channel::Alpha) {
draw_alpha_slider(g, rc, m_color);
return;
}
@ -60,55 +60,55 @@ namespace {
for (int x=0; x <= w; ++x) {
switch (m_channel) {
case ColorSliders::Red:
case ColorSliders::Channel::Red:
color = gfx::rgba(255 * x / w, m_color.getGreen(), m_color.getBlue());
break;
case ColorSliders::Green:
case ColorSliders::Channel::Green:
color = gfx::rgba(m_color.getRed(), 255 * x / w, m_color.getBlue());
break;
case ColorSliders::Blue:
case ColorSliders::Channel::Blue:
color = gfx::rgba(m_color.getRed(), m_color.getGreen(), 255 * x / w);
break;
case ColorSliders::HsvHue:
case ColorSliders::Channel::HsvHue:
color = color_utils::color_for_ui(
app::Color::fromHsv(360.0 * x / w,
m_color.getHsvSaturation(),
m_color.getHsvValue()));
break;
case ColorSliders::HsvSaturation:
case ColorSliders::Channel::HsvSaturation:
color = color_utils::color_for_ui(
app::Color::fromHsv(m_color.getHsvHue(),
double(x) / double(w),
m_color.getHsvValue()));
break;
case ColorSliders::HsvValue:
case ColorSliders::Channel::HsvValue:
color = color_utils::color_for_ui(
app::Color::fromHsv(m_color.getHsvHue(),
m_color.getHsvSaturation(),
double(x) / double(w)));
break;
case ColorSliders::HslHue:
case ColorSliders::Channel::HslHue:
color = color_utils::color_for_ui(
app::Color::fromHsl(360.0 * x / w,
m_color.getHslSaturation(),
m_color.getHslLightness()));
break;
case ColorSliders::HslSaturation:
case ColorSliders::Channel::HslSaturation:
color = color_utils::color_for_ui(
app::Color::fromHsl(m_color.getHslHue(),
double(x) / double(w),
m_color.getHslLightness()));
break;
case ColorSliders::HslLightness:
case ColorSliders::Channel::HslLightness:
color = color_utils::color_for_ui(
app::Color::fromHsl(m_color.getHslHue(),
m_color.getHslSaturation(),
double(x) / double(w)));
break;
case ColorSliders::Gray:
case ColorSliders::Channel::Gray:
color = color_utils::color_for_ui(
app::Color::fromGray(255 * x / w));
break;
@ -227,43 +227,117 @@ namespace {
ColorSliders::ColorSliders()
: Widget(kGenericWidget)
, m_items(int(Channel::Channels))
, m_grid(3, false)
, m_mode(Absolute)
, m_mode(Mode::Absolute)
, m_lockEntry(-1)
, m_color(app::Color::fromMask())
{
addChild(&m_grid);
m_grid.setChildSpacing(0);
}
ColorSliders::~ColorSliders()
{
// Same order as in Channel enum
static_assert(Channel::Red == (Channel)0, "");
static_assert(Channel::Alpha == (Channel)10, "");
addSlider(Channel::Red, "R", 0, 255, -255, 255);
addSlider(Channel::Green, "G", 0, 255, -255, 255);
addSlider(Channel::Blue, "B", 0, 255, -255, 255);
addSlider(Channel::HsvHue, "H", 0, 360, -180, 180);
addSlider(Channel::HsvSaturation, "S", 0, 100, -100, 100);
addSlider(Channel::HsvValue, "V", 0, 100, -100, 100);
addSlider(Channel::HslHue, "H", 0, 360, -180, 180);
addSlider(Channel::HslSaturation, "S", 0, 100, -100, 100);
addSlider(Channel::HslLightness, "L", 0, 100, -100, 100);
addSlider(Channel::Gray, "V", 0, 255, -255, 255);
addSlider(Channel::Alpha, "A", 0, 255, -255, 255);
}
void ColorSliders::setColor(const app::Color& color)
{
m_color = color;
onSetColor(color);
updateSlidersBgColor();
}
updateSlidersBgColor(color);
void ColorSliders::setColorType(const app::Color::Type type)
{
std::vector<app::Color::Type> types(1, type);
setColorTypes(types);
}
void ColorSliders::setColorTypes(const std::vector<app::Color::Type>& types)
{
for (Item& item : m_items)
item.show = false;
bool visible = false;
for (auto type : types) {
switch (type) {
case app::Color::RgbType:
m_items[Channel::Red].show = true;
m_items[Channel::Green].show = true;
m_items[Channel::Blue].show = true;
m_items[Channel::Alpha].show = true;
visible = true;
break;
case app::Color::HsvType:
m_items[Channel::HsvHue].show = true;
m_items[Channel::HsvSaturation].show = true;
m_items[Channel::HsvValue].show = true;
m_items[Channel::Alpha].show = true;
visible = true;
break;
case app::Color::HslType:
m_items[Channel::HslHue].show = true;
m_items[Channel::HslSaturation].show = true;
m_items[Channel::HslLightness].show = true;
m_items[Channel::Alpha].show = true;
visible = true;
break;
case app::Color::GrayType:
m_items[Channel::Gray].show = true;
m_items[Channel::Alpha].show = true;
visible = true;
break;
case app::Color::MaskType:
case app::Color::IndexType:
// Do nothing
break;
}
}
setVisible(visible);
updateSlidersVisibility();
updateSlidersBgColor();
layout();
}
void ColorSliders::setMode(Mode mode)
{
m_mode = mode;
for (Slider* slider : m_absSlider)
slider->setVisible(mode == Absolute);
for (Slider* slider : m_relSlider)
slider->setVisible(mode == Relative);
updateSlidersVisibility();
resetRelativeSliders();
layout();
}
void ColorSliders::updateSlidersVisibility()
{
for (auto& item : m_items) {
bool v = item.show;
item.label->setVisible(v);
item.box->setVisible(v);
item.entry->setVisible(v);
item.absSlider->setVisible(v && m_mode == Mode::Absolute);
item.relSlider->setVisible(v && m_mode == Mode::Relative);
}
}
void ColorSliders::resetRelativeSliders()
{
for (Slider* slider : m_relSlider)
slider->setValue(0);
for (Item& item : m_items)
item.relSlider->setValue(0);
}
void ColorSliders::onSizeHint(SizeHintEvent& ev)
@ -276,112 +350,107 @@ void ColorSliders::addSlider(const Channel channel,
const int absMin, const int absMax,
const int relMin, const int relMax)
{
Label* label = new Label(labelText);
Slider* absSlider = new Slider(absMin, absMax, 0);
Slider* relSlider = new Slider(relMin, relMax, 0);
Entry* entry = new ColorEntry(absSlider, relSlider);
Item& item = m_items[channel];
ASSERT(!item.label);
item.label = new Label(labelText);
item.box = new HBox();
item.absSlider = new Slider(absMin, absMax, 0);
item.relSlider = new Slider(relMin, relMax, 0);
item.entry = new ColorEntry(item.absSlider, item.relSlider);
m_label.push_back(label);
m_absSlider.push_back(absSlider);
m_relSlider.push_back(relSlider);
m_entry.push_back(entry);
m_channel.push_back(channel);
item.absSlider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel))));
item.absSlider->setDoubleBuffered(true);
get_skin_property(item.entry)->setLook(MiniLook);
absSlider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel))));
absSlider->setDoubleBuffered(true);
get_skin_property(entry)->setLook(MiniLook);
item.absSlider->Change.connect(base::Bind<void>(&ColorSliders::onSliderChange, this, channel));
item.relSlider->Change.connect(base::Bind<void>(&ColorSliders::onSliderChange, this, channel));
item.entry->Change.connect(base::Bind<void>(&ColorSliders::onEntryChange, this, channel));
absSlider->Change.connect(base::Bind<void>(&ColorSliders::onSliderChange, this, m_absSlider.size()-1));
relSlider->Change.connect(base::Bind<void>(&ColorSliders::onSliderChange, this, m_relSlider.size()-1));
entry->Change.connect(base::Bind<void>(&ColorSliders::onEntryChange, this, m_entry.size()-1));
HBox* box = new HBox();
box->addChild(absSlider);
box->addChild(relSlider);
absSlider->setFocusStop(false);
relSlider->setFocusStop(false);
absSlider->setExpansive(true);
relSlider->setExpansive(true);
relSlider->setVisible(false);
item.box->addChild(item.absSlider);
item.box->addChild(item.relSlider);
item.absSlider->setFocusStop(false);
item.relSlider->setFocusStop(false);
item.absSlider->setExpansive(true);
item.relSlider->setExpansive(true);
item.relSlider->setVisible(false);
gfx::Size sz(INT_MAX, SkinTheme::instance()->dimensions.colorSliderHeight());
label->setMaxSize(sz);
box->setMaxSize(sz);
entry->setMaxSize(sz);
item.label->setMaxSize(sz);
item.box->setMaxSize(sz);
item.entry->setMaxSize(sz);
m_grid.addChildInCell(label, 1, 1, LEFT | MIDDLE);
m_grid.addChildInCell(box, 1, 1, HORIZONTAL | VERTICAL);
m_grid.addChildInCell(entry, 1, 1, LEFT | MIDDLE);
m_grid.addChildInCell(item.label, 1, 1, LEFT | MIDDLE);
m_grid.addChildInCell(item.box, 1, 1, HORIZONTAL | VERTICAL);
m_grid.addChildInCell(item.entry, 1, 1, LEFT | MIDDLE);
}
void ColorSliders::setAbsSliderValue(int sliderIndex, int value)
void ColorSliders::setAbsSliderValue(const Channel i, int value)
{
m_absSlider[sliderIndex]->setValue(value);
updateEntryText(sliderIndex);
m_items[i].absSlider->setValue(value);
updateEntryText(i);
}
int ColorSliders::getAbsSliderValue(int sliderIndex) const
int ColorSliders::getAbsSliderValue(const Channel i) const
{
return m_absSlider[sliderIndex]->getValue();
return m_items[i].absSlider->getValue();
}
int ColorSliders::getRelSliderValue(int sliderIndex) const
int ColorSliders::getRelSliderValue(const Channel i) const
{
return m_relSlider[sliderIndex]->getValue();
return m_items[i].relSlider->getValue();
}
void ColorSliders::onSliderChange(int i)
void ColorSliders::onSliderChange(const Channel i)
{
updateEntryText(i);
onControlChange(i);
}
void ColorSliders::onEntryChange(int i)
void ColorSliders::onEntryChange(const Channel i)
{
base::ScopedValue<int> lock(m_lockEntry, i, m_lockEntry);
// Update the slider related to the changed entry widget.
int value = m_entry[i]->textInt();
int value = m_items[i].entry->textInt();
Slider* slider = (m_mode == Absolute ? m_absSlider[i]: m_relSlider[i]);
Slider* slider = (m_mode == Mode::Absolute ?
m_items[i].absSlider:
m_items[i].relSlider);
value = MID(slider->getMinValue(), value, slider->getMaxValue());
slider->setValue(value);
onControlChange(i);
}
void ColorSliders::onControlChange(int i)
void ColorSliders::onControlChange(const Channel i)
{
// Call derived class impl of getColorFromSliders() to update the
// background color of sliders.
app::Color color = getColorFromSliders();
updateSlidersBgColor(color);
m_color = getColorFromSliders(i);
updateSlidersBgColor();
// Fire ColorChange() signal
ColorSlidersChangeEvent ev(m_channel[i], m_mode,
color, m_relSlider[i]->getValue(), this);
ColorSlidersChangeEvent ev(i, m_mode, m_color,
m_items[i].relSlider->getValue(), this);
ColorChange(ev);
}
// Updates the entry related to the changed slider widget.
void ColorSliders::updateEntryText(int entryIndex)
void ColorSliders::updateEntryText(const Channel i)
{
if (m_lockEntry == entryIndex)
if (m_lockEntry == i)
return;
Slider* slider = (m_mode == Absolute ? m_absSlider[entryIndex]:
m_relSlider[entryIndex]);
Slider* slider = (m_mode == Mode::Absolute ? m_items[i].absSlider:
m_items[i].relSlider);
m_entry[entryIndex]->setTextf("%d", slider->getValue());
if (m_entry[entryIndex]->hasFocus())
m_entry[entryIndex]->selectAllText();
m_items[i].entry->setTextf("%d", slider->getValue());
if (m_items[i].entry->hasFocus())
m_items[i].entry->selectAllText();
}
void ColorSliders::updateSlidersBgColor(const app::Color& color)
void ColorSliders::updateSlidersBgColor()
{
for (size_t i = 0; i < m_absSlider.size(); ++i)
updateSliderBgColor(m_absSlider[i], color);
for (auto& item : m_items)
updateSliderBgColor(item.absSlider, m_color);
}
void ColorSliders::updateSliderBgColor(Slider* slider, const app::Color& color)
@ -393,110 +462,60 @@ void ColorSliders::updateSliderBgColor(Slider* slider, const app::Color& color)
slider->invalidate();
}
//////////////////////////////////////////////////////////////////////
// RgbSliders
RgbSliders::RgbSliders()
: ColorSliders()
void ColorSliders::onSetColor(const app::Color& color)
{
addSlider(Red, "R", 0, 255, -255, 255);
addSlider(Green, "G", 0, 255, -255, 255);
addSlider(Blue, "B", 0, 255, -255, 255);
addSlider(Alpha, "A", 0, 255, -255, 255);
setAbsSliderValue(Channel::Red, color.getRed());
setAbsSliderValue(Channel::Green, color.getGreen());
setAbsSliderValue(Channel::Blue, color.getBlue());
setAbsSliderValue(Channel::HsvHue, int(color.getHsvHue()));
setAbsSliderValue(Channel::HsvSaturation, int(color.getHsvSaturation() * 100.0));
setAbsSliderValue(Channel::HsvValue, int(color.getHsvValue() * 100.0));
setAbsSliderValue(Channel::HslHue, int(color.getHslHue()));
setAbsSliderValue(Channel::HslSaturation, int(color.getHslSaturation() * 100.0));
setAbsSliderValue(Channel::HslLightness, int(color.getHslLightness() * 100.0));
setAbsSliderValue(Channel::Gray, color.getGray());
setAbsSliderValue(Channel::Alpha, color.getAlpha());
}
void RgbSliders::onSetColor(const app::Color& color)
app::Color ColorSliders::getColorFromSliders(const Channel channel) const
{
setAbsSliderValue(0, color.getRed());
setAbsSliderValue(1, color.getGreen());
setAbsSliderValue(2, color.getBlue());
setAbsSliderValue(3, color.getAlpha());
}
app::Color RgbSliders::getColorFromSliders()
{
return app::Color::fromRgb(getAbsSliderValue(0),
getAbsSliderValue(1),
getAbsSliderValue(2),
getAbsSliderValue(3));
}
//////////////////////////////////////////////////////////////////////
// HsvSliders
HsvSliders::HsvSliders()
: ColorSliders()
{
addSlider(HsvHue, "H", 0, 360, -180, 180);
addSlider(HsvSaturation, "S", 0, 100, -100, 100);
addSlider(HsvValue, "V", 0, 100, -100, 100);
addSlider(Alpha, "A", 0, 255, -255, 255);
}
void HsvSliders::onSetColor(const app::Color& color)
{
setAbsSliderValue(0, int(color.getHsvHue()));
setAbsSliderValue(1, int(color.getHsvSaturation() * 100.0));
setAbsSliderValue(2, int(color.getHsvValue() * 100.0));
setAbsSliderValue(3, color.getAlpha());
}
app::Color HsvSliders::getColorFromSliders()
{
return app::Color::fromHsv(getAbsSliderValue(0),
getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2) / 100.0,
getAbsSliderValue(3));
}
//////////////////////////////////////////////////////////////////////
// HslSliders
HslSliders::HslSliders()
: ColorSliders()
{
addSlider(HslHue, "H", 0, 360, -180, 180);
addSlider(HslSaturation, "S", 0, 100, -100, 100);
addSlider(HslLightness, "L", 0, 100, -100, 100);
addSlider(Alpha, "A", 0, 255, -255, 255);
}
void HslSliders::onSetColor(const app::Color& color)
{
setAbsSliderValue(0, int(color.getHslHue()));
setAbsSliderValue(1, int(color.getHslSaturation() * 100.0));
setAbsSliderValue(2, int(color.getHslLightness() * 100.0));
setAbsSliderValue(3, color.getAlpha());
}
app::Color HslSliders::getColorFromSliders()
{
return app::Color::fromHsl(getAbsSliderValue(0),
getAbsSliderValue(1) / 100.0,
getAbsSliderValue(2) / 100.0,
getAbsSliderValue(3));
}
//////////////////////////////////////////////////////////////////////
// GraySlider
GraySlider::GraySlider()
: ColorSliders()
{
addSlider(Gray, "V", 0, 255, -255, 255);
addSlider(Alpha, "A", 0, 255, -255, 255);
}
void GraySlider::onSetColor(const app::Color& color)
{
setAbsSliderValue(0, color.getGray());
setAbsSliderValue(1, color.getAlpha());
}
app::Color GraySlider::getColorFromSliders()
{
return app::Color::fromGray(getAbsSliderValue(0),
getAbsSliderValue(1));
// Get the color from sliders.
switch (channel) {
case Channel::Red:
case Channel::Green:
case Channel::Blue:
return app::Color::fromRgb(
getAbsSliderValue(Channel::Red),
getAbsSliderValue(Channel::Green),
getAbsSliderValue(Channel::Blue),
getAbsSliderValue(Channel::Alpha));
case Channel::HsvHue:
case Channel::HsvSaturation:
case Channel::HsvValue:
return app::Color::fromHsv(
getAbsSliderValue(Channel::HsvHue),
getAbsSliderValue(Channel::HsvSaturation) / 100.0,
getAbsSliderValue(Channel::HsvValue) / 100.0,
getAbsSliderValue(Channel::Alpha));
case Channel::HslHue:
case Channel::HslSaturation:
case Channel::HslLightness:
return app::Color::fromHsl(
getAbsSliderValue(Channel::HslHue),
getAbsSliderValue(Channel::HslSaturation) / 100.0,
getAbsSliderValue(Channel::HslLightness) / 100.0,
getAbsSliderValue(Channel::Alpha));
case Channel::Gray:
return app::Color::fromGray(
getAbsSliderValue(Channel::Gray),
getAbsSliderValue(Channel::Alpha));
case Channel::Alpha: {
app::Color color = m_color;
color.setAlpha(getAbsSliderValue(Channel::Alpha));
return color;
}
}
return app::Color::fromMask();
}
} // namespace app

View File

@ -17,6 +17,7 @@
#include <vector>
namespace ui {
class Box;
class Label;
class Slider;
class Entry;
@ -31,23 +32,25 @@ namespace app {
enum Channel { Red, Green, Blue,
HsvHue, HsvSaturation, HsvValue,
HslHue, HslSaturation, HslLightness,
Gray, Alpha };
Gray, Alpha,
Channels };
enum Mode { Absolute, Relative };
ColorSliders();
~ColorSliders();
void setColor(const app::Color& color);
void setColorType(const app::Color::Type type);
void setColorTypes(const std::vector<app::Color::Type>& types);
void setMode(Mode mode);
void resetRelativeSliders();
int getAbsSliderValue(int sliderIndex) const;
int getRelSliderValue(int sliderIndex) const;
int getAbsSliderValue(const Channel i) const;
int getRelSliderValue(const Channel i) const;
// Signals
obs::signal<void(ColorSlidersChangeEvent&)> ColorChange;
protected:
private:
void onSizeHint(ui::SizeHintEvent& ev) override;
// For derived classes
@ -55,67 +58,33 @@ namespace app {
const char* labelText,
const int absMin, const int absMax,
const int relMin, const int relMax);
void setAbsSliderValue(int sliderIndex, int value);
void setAbsSliderValue(const Channel i, int value);
virtual void onSetColor(const app::Color& color) = 0;
virtual app::Color getColorFromSliders() = 0;
void updateSlidersVisibility();
void onSetColor(const app::Color& color);
app::Color getColorFromSliders(const Channel channel) const;
void onSliderChange(const Channel i);
void onEntryChange(const Channel i);
void onControlChange(const Channel i);
private:
void onSliderChange(int i);
void onEntryChange(int i);
void onControlChange(int i);
void updateEntryText(int entryIndex);
void updateSlidersBgColor(const app::Color& color);
void updateEntryText(const Channel i);
void updateSlidersBgColor();
void updateSliderBgColor(ui::Slider* slider, const app::Color& color);
std::vector<ui::Label*> m_label;
std::vector<ui::Slider*> m_absSlider;
std::vector<ui::Slider*> m_relSlider;
std::vector<ui::Entry*> m_entry;
std::vector<Channel> m_channel;
struct Item {
bool show = false;
ui::Label* label = nullptr;
ui::Box* box = nullptr;
ui::Slider* absSlider = nullptr;
ui::Slider* relSlider = nullptr;
ui::Entry* entry = nullptr;
};
std::vector<Item> m_items;
ui::Grid m_grid;
Mode m_mode;
int m_lockEntry;
};
//////////////////////////////////////////////////////////////////////
// Derived-classes
class RgbSliders : public ColorSliders {
public:
RgbSliders();
private:
virtual void onSetColor(const app::Color& color) override;
virtual app::Color getColorFromSliders() override;
};
class HsvSliders : public ColorSliders {
public:
HsvSliders();
private:
virtual void onSetColor(const app::Color& color) override;
virtual app::Color getColorFromSliders() override;
};
class HslSliders : public ColorSliders {
public:
HslSliders();
private:
virtual void onSetColor(const app::Color& color) override;
virtual app::Color getColorFromSliders() override;
};
class GraySlider : public ColorSliders {
public:
GraySlider();
private:
virtual void onSetColor(const app::Color& color) override;
virtual app::Color getColorFromSliders() override;
app::Color m_color;
};
//////////////////////////////////////////////////////////////////////