I am developing an app and need a Color picker component. Is there any UI library that provides similar functionality?
I’m surprised that there isn’t one in HaxeUI or FeathersUI already. You might have to roll your own or find one that’s pre-built for your chosen target and use externs.
I’ve been waiting to add a color picker to Feathers UI until I have the time to make sure that its architecture is robust enough to be properly customizable. There are so many variations of color pickers out there, and I generally try to make sure that Feathers UI has the proper flexibility to support as wide a variety as possible.
That being said, it isn’t very difficult at all to create a basic color picker out of the ListView
component in Feathers UI. I’m thinking of sort of color picker with a grid of color “swatches”, where clicking a swatch would select that color. That would need a simple custom item renderer to display the color as a square/rectangle, and TiledRowsLayout
or TiledRowsListLayout
would position those color swatches in a grid.
I needed something like this a project, so I created a simple custom component called SwatchColorPicker
. I’ll include the code below. Warning: It is mostly just hacked together, and it is not up to the level of polish I would require of a real component included with Feathers UI.
import feathers.controls.Button;
import feathers.controls.ListView;
import feathers.core.FeathersControl;
import feathers.data.ArrayCollection;
import feathers.data.ListViewItemState;
import feathers.events.FeathersEvent;
import feathers.events.ListViewEvent;
import feathers.layout.TiledRowsLayout;
import feathers.skins.RectangleSkin;
import feathers.utils.DisplayObjectRecycler;
import openfl.events.Event;
class SwatchColorPicker extends FeathersControl {
public function new() {
super();
}
private var _listView:ListView;
private var _colorsCollection:ArrayCollection<Dynamic>;
public var selectedColor(default, set):UInt = 0x000000;
private function set_selectedColor(value:UInt):UInt {
if (this.selectedColor == value) {
return this.selectedColor;
}
this.selectedColor = value;
this.setInvalid(DATA);
FeathersEvent.dispatch(this, Event.CHANGE);
return this.selectedColor;
}
private var _ignoreColorChanges = false;
override private function initialize():Void {
super.initialize();
this._colorsCollection = new ArrayCollection([
{color: 0xFF0000}, {color: 0xFF6600}, {color: 0xFFFF00}, {color: 0x00FF00}, {color: 0x00FFFF}, {color: 0x0000FF}, {color: 0xFF00FF},
{color: 0x880088}, {color: 0x884411}, {color: 0xFFFFFF}, {color: 0x808080}, {color: 0x000000},
]);
this._listView = new ListView();
this._listView.selectable = false;
this._listView.dataProvider = this._colorsCollection;
this._listView.itemRendererRecycler = DisplayObjectRecycler.withFunction(() -> {
var itemRenderer = new Button();
itemRenderer.backgroundSkin = new RectangleSkin();
itemRenderer.width = 20.0;
itemRenderer.height = 20.0;
return itemRenderer;
}, (itemRenderer:Button, state:ListViewItemState) -> {
var backgroundSkin = cast(itemRenderer.backgroundSkin, RectangleSkin);
backgroundSkin.fill = SolidColor(state.data.color);
});
this._listView.addEventListener(ListViewEvent.ITEM_TRIGGER, itemTriggerHandler);
var listViewLayout = new TiledRowsLayout();
listViewLayout.requestedColumnCount = 6;
listViewLayout.setPadding(4.0);
listViewLayout.setGap(4.0);
this._listView.layout = listViewLayout;
this.addChild(this._listView);
}
override private function update():Void {
var dataInvalid = this.isInvalid(DATA);
if (dataInvalid) {
var oldIgnoreColorChanges = this._ignoreColorChanges;
this._ignoreColorChanges = true;
this._listView.selectedItem = this._colorsCollection.findIndex((item, index, collection) -> {
return item.color == this.selectedColor;
});
this._ignoreColorChanges = oldIgnoreColorChanges;
}
this._listView.validateNow();
this.saveMeasurements(this._listView.width, this._listView.height, this._listView.minWidth, this._listView.minHeight);
this._listView.x = 0.0;
this._listView.y = 0.0;
this._listView.width = this.actualWidth;
this._listView.height = this.actualHeight;
}
private function itemTriggerHandler(event:ListViewEvent):Void {
this.selectedColor = event.state.data.color;
}
}
I also created a variation where it’s more like a button, and clicking the currently selected color displays the swatches in a popup:
import feathers.controls.Callout;
import feathers.core.FeathersControl;
import feathers.events.FeathersEvent;
import feathers.skins.RectangleSkin;
import openfl.events.Event;
import openfl.events.MouseEvent;
class PopUpSwatchColorPicker extends FeathersControl {
public function new() {
super();
this.addEventListener(MouseEvent.CLICK, clickHandler);
}
private var _backgroundSkin:RectangleSkin;
private var _callout:Callout;
public var selectedColor(default, set):UInt = 0x000000;
private function set_selectedColor(value:UInt):UInt {
if (this.selectedColor == value) {
return this.selectedColor;
}
this.selectedColor = value;
this.setInvalid(DATA);
FeathersEvent.dispatch(this, Event.CHANGE);
return this.selectedColor;
}
override private function initialize():Void {
super.initialize();
this._backgroundSkin = new RectangleSkin(SolidColor(this.selectedColor), SolidColor(1.0, 0x000000));
this.addChild(this._backgroundSkin);
}
override private function update():Void {
var dataInvalid = this.isInvalid(DATA);
if (dataInvalid) {
this._backgroundSkin.fill = SolidColor(this.selectedColor);
}
this.saveMeasurements(20.0, 20.0, 20.0, 20.0);
this._backgroundSkin.x = 0.0;
this._backgroundSkin.y = 0.0;
this._backgroundSkin.width = this.actualWidth;
this._backgroundSkin.height = this.actualHeight;
}
private function clickHandler(event:MouseEvent):Void {
if (this._callout != null) {
return;
}
var swatches = new SwatchColorPicker();
swatches.selectedColor = this.selectedColor;
swatches.addEventListener(Event.CHANGE, swatchChangeHandler);
this._callout = Callout.show(swatches, this);
this._callout.addEventListener(Event.CLOSE, calloutCloseHandler);
}
private function swatchChangeHandler(event:Event):Void {
var swatches = cast(event.currentTarget, SwatchColorPicker);
this.selectedColor = swatches.selectedColor;
this._callout.close();
}
private function calloutCloseHandler(event:Event):Void {
this._callout = null;
}
}
Again, these are not as polished as normal components in Feathers UI, so there aren’t a lot of properties that you can customize (including which colors are displayed in the grid!). However, at least in the case of the colors, it’s easy to modify the code to include an expanded data provider of colors that you need for your app.
I started with this code from Josh then I coached AI to make this FeathersUI colour picker.
package com.feathersui;
import feathers.controls.Callout;
import feathers.core.FeathersControl;
import feathers.events.FeathersEvent;
import feathers.skins.RectangleSkin;
import openfl.events.Event;
import openfl.events.MouseEvent;
class PopUpHSBColorPicker extends FeathersControl {
public function new() {
super();
this.addEventListener(MouseEvent.CLICK, clickHandler);
}
private var _backgroundSkin:RectangleSkin;
private var _callout:Callout;
public var selectedColor(default, set):UInt = 0x000000;
private function set_selectedColor(value:UInt):UInt {
if (this.selectedColor == value) {
return this.selectedColor;
}
this.selectedColor = value;
this.setInvalid(DATA);
FeathersEvent.dispatch(this, Event.CHANGE);
return this.selectedColor;
}
override private function initialize():Void {
super.initialize();
this._backgroundSkin = new RectangleSkin(SolidColor(this.selectedColor), SolidColor(1.0, 0x000000));
this.addChild(this._backgroundSkin);
}
override private function update():Void {
var dataInvalid = this.isInvalid(DATA);
if (dataInvalid) {
this._backgroundSkin.fill = SolidColor(this.selectedColor);
}
this.saveMeasurements(20.0, 20.0, 20.0, 20.0);
this._backgroundSkin.x = 0.0;
this._backgroundSkin.y = 5.0;
this._backgroundSkin.width = this.actualWidth;
this._backgroundSkin.height = this.actualHeight;
}
private function clickHandler(event:MouseEvent):Void {
if (this._callout != null) {
return;
}
var hsbPicker = new HSBColorPicker();
hsbPicker.selectedColor = this.selectedColor;
hsbPicker.addEventListener(Event.CHANGE, hsbChangeHandler);
this._callout = Callout.show(hsbPicker, this);
this._callout.addEventListener(Event.CLOSE, calloutCloseHandler);
}
private function hsbChangeHandler(event:Event):Void {
var hsbPicker = cast(event.currentTarget, HSBColorPicker);
this.selectedColor = hsbPicker.selectedColor;
}
private function calloutCloseHandler(event:Event):Void {
this._callout = null;
}
}
package com.feathersui;
import feathers.controls.Label;
import feathers.controls.TextInput;
import feathers.core.FeathersControl;
import feathers.events.FeathersEvent;
import feathers.layout.HorizontalLayout;
import feathers.layout.VerticalLayout;
import feathers.layout.HorizontalLayoutData;
import feathers.layout.VerticalLayoutData;
import feathers.controls.LayoutGroup;
import feathers.skins.RectangleSkin;
import openfl.display.Bitmap;
import openfl.display.BitmapData;
// import openfl.display.Shape;
import openfl.events.Event;
import openfl.events.MouseEvent;
import openfl.geom.Matrix;
import openfl.geom.Point;
import ca.confidant.featherstools.ThreeDBugTheme;
class HSBColorPicker extends FeathersControl {
public function new() {
super();
}
private var _hue:Float = 0; // 0-360
private var _saturation:Float = 1; // 0-1
private var _brightness:Float = 1; // 0-1
private var _hueWheel:Sprite;
private var _hueWheelBitmap:Bitmap;
private var _sbSquare:Sprite;
private var _sbSquareBitmap:Bitmap;
private var _preview:Sprite;
private var _previewBitmap:Bitmap;
private var _hueIndicator:Sprite;
private var _sbIndicator:Sprite;
private var _rgbGroup:LayoutGroup;
private var _hsbGroup:LayoutGroup;
private var _rInput:TextInput;
private var _gInput:TextInput;
private var _bInput:TextInput;
private var _hInput:TextInput;
private var _sInput:TextInput;
private var _brightnessInput:TextInput;
private var _isDraggingHue:Bool = false;
private var _isDraggingSB:Bool = false;
private var _isUpdating:Bool = false;
public var selectedColor(default, set):UInt = 0xFF0000;
private function set_selectedColor(value:UInt):UInt {
if (this.selectedColor == value) {
return value;
}
this.selectedColor = value;
if (_isUpdating) {
return value;
}
// Only update if the component is initialized
if (_hueWheelBitmap != null) {
_isUpdating = true;
updateFromRGB();
_isUpdating = false;
}
this.setInvalid(DATA);
FeathersEvent.dispatch(this, Event.CHANGE);
return this.selectedColor;
}
override private function initialize():Void {
super.initialize();
this.mouseChildren = true;
// Create main container with layout
var mainContainer = new LayoutGroup();
var mcSkin = new RectangleSkin(SolidColor(0xffffff));
mcSkin.width = 400;
mcSkin.height = 350;
mainContainer.backgroundSkin = mcSkin;
var mainLayout = new HorizontalLayout();
mainLayout.gap = 10;
mainLayout.setPadding(10);
mainContainer.layout = mainLayout;
this.addChild(mainContainer);
// Create color picker area
var pickerGroup = new LayoutGroup();
pickerGroup.layoutData = new HorizontalLayoutData();
mainContainer.addChild(pickerGroup);
// pickerGroup.mouseChildren = true;
// Input controls
var inputGroup = new LayoutGroup();
var igSkin = new RectangleSkin(SolidColor(0xffffff, 0));
igSkin.width = 100;
igSkin.height = 30;
inputGroup.backgroundSkin = igSkin;
var inputLayout = new VerticalLayout();
inputLayout.gap = 10;
inputGroup.layout = inputLayout;
inputGroup.layoutData = new HorizontalLayoutData();
mainContainer.addChild(inputGroup);
// RGB inputs
_rgbGroup = new LayoutGroup();
_rgbGroup.layoutData = new VerticalLayoutData(100);
var rgbLayout = new VerticalLayout();
rgbLayout.gap = 5;
_rgbGroup.layout = rgbLayout;
inputGroup.addChild(_rgbGroup);
var rgbLabel = new Label();
rgbLabel.text = "RGB";
_rgbGroup.addChild(rgbLabel);
// HSB inputs
_hsbGroup = new LayoutGroup();
_hsbGroup.layoutData = new VerticalLayoutData(100);
var hsbLayout = new VerticalLayout();
hsbLayout.gap = 5;
_hsbGroup.layout = hsbLayout;
inputGroup.addChild(_hsbGroup);
var hsbLabel = new Label();
hsbLabel.text = "HSB";
_hsbGroup.addChild(hsbLabel);
// Now create inputs with proper target groups
_rInput = createNumberInput("R:", 255, _rgbGroup);
_gInput = createNumberInput("G:", 0, _rgbGroup);
_bInput = createNumberInput("B:", 0, _rgbGroup);
_hInput = createNumberInput("H:", 0, _hsbGroup);
_sInput = createNumberInput("S:", 100, _hsbGroup);
_brightnessInput = createNumberInput("B:", 100, _hsbGroup);
// Hue wheel (150x150)
_hueWheel = new Sprite();
// _hueWheel.mouseChildren = true;
_hueWheelBitmap = new Bitmap();
_hueWheelBitmap.bitmapData = createHueWheel(75);
_hueWheelBitmap.x = 10;
_hueWheelBitmap.y = 10;
_hueWheel.addChild(_hueWheelBitmap);
pickerGroup.addChild(_hueWheel);
// Hue indicator
_hueIndicator = new Sprite();
_hueIndicator.graphics.lineStyle(2, 0x000000);
_hueIndicator.graphics.drawCircle(0, 0, 3);
pickerGroup.addChild(_hueIndicator);
// SB square (150x150)
_sbSquare = new Sprite();
// _sbSquare.mouseChildren = true;
_sbSquareBitmap = new Bitmap();
_sbSquareBitmap.bitmapData = createSBSquare(150);
_sbSquareBitmap.x = 180;
_sbSquareBitmap.y = 10;
_sbSquare.addChild(_sbSquareBitmap);
pickerGroup.addChild(_sbSquare);
// SB indicator
_sbIndicator = new Sprite();
_sbIndicator.graphics.lineStyle(2, 0xFFFFFF);
_sbIndicator.graphics.drawCircle(0, 0, 4);
_sbIndicator.graphics.lineStyle(1, 0x000000);
_sbIndicator.graphics.drawCircle(0, 0, 4);
pickerGroup.addChild(_sbIndicator);
// Preview
_previewBitmap = new Bitmap();
_previewBitmap.bitmapData = new BitmapData(60, 40, false, selectedColor);
_previewBitmap.x = 350;
_previewBitmap.y = 10;
pickerGroup.addChild(_previewBitmap);
// Event listeners
_hueWheel.addEventListener(MouseEvent.MOUSE_DOWN, onHueMouseDown);
_sbSquare.addEventListener(MouseEvent.MOUSE_DOWN, onSBMouseDown);
// Now initialize the values after all inputs are created
updateFromRGB();
updateIndicators();
}
private function createNumberInput(labelText:String, value:Float, targetGroup:LayoutGroup):TextInput {
var group = new LayoutGroup();
var layout = new HorizontalLayout();
layout.gap = 5;
layout.verticalAlign = MIDDLE;
group.layout = layout;
group.layoutData = new VerticalLayoutData(100);
var label = new Label();
label.text = labelText;
label.layoutData = new HorizontalLayoutData(20);
group.addChild(label);
var input = new TextInput();
// input.variant = ThreeDBugTheme.VARIANT_HSB_PICKER;
input.text = Std.string(Math.round(value));
input.layoutData = new HorizontalLayoutData(70);
input.addEventListener(Event.CHANGE, onInputChange);
group.addChild(input);
targetGroup.addChild(group);
return input;
}
private function onHueMouseDown(event:MouseEvent):Void {
trace("onHueMouseDown() - x: " + event.localX + ", y: " + event.localY);
_isDraggingHue = true;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onHueMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onHueMouseUp);
updateHueFromMouse(event.localX, event.localY);
}
private function onHueMouseMove(event:MouseEvent):Void {
if (_isDraggingHue) {
var localPoint = _hueWheelBitmap.globalToLocal(new Point(event.stageX, event.stageY));
updateHueFromMouse(localPoint.x, localPoint.y);
}
}
private function onHueMouseUp(event:MouseEvent):Void {
_isDraggingHue = false;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onHueMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onHueMouseUp);
}
private function onSBMouseDown(event:MouseEvent):Void {
trace("onSBMouseDown() - x: " + event.localX + ", y: " + event.localY);
_isDraggingSB = true;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onSBMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onSBMouseUp);
updateSBFromMouse(event.localX, event.localY);
}
private function onSBMouseMove(event:MouseEvent):Void {
if (_isDraggingSB) {
var localPoint = _sbSquareBitmap.globalToLocal(new Point(event.stageX, event.stageY));
updateSBFromMouse(localPoint.x, localPoint.y);
}
}
private function onSBMouseUp(event:MouseEvent):Void {
_isDraggingSB = false;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onSBMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onSBMouseUp);
}
private function updateHueFromMouse(x:Float, y:Float):Void {
var centerX = 75;
var centerY = 75;
var dx = x - centerX;
var dy = y - centerY;
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
if (angle < 0) angle += 360;
_hue = angle;
updateFromHSB();
}
private function updateSBFromMouse(x:Float, y:Float):Void {
_saturation = Math.max(0, Math.min(1, x / 150));
_brightness = Math.max(0, Math.min(1, 1 - (y / 150)));
updateFromHSB();
}
private function onInputChange(event:Event):Void {
if (_isUpdating) return;
var input = cast(event.currentTarget, TextInput);
_isUpdating = true;
if (input == _rInput || input == _gInput || input == _bInput) {
var r:Float = Math.max(0, Math.min(255, Std.parseInt(_rInput.text) ?? 0));
var g:Float = Math.max(0, Math.min(255, Std.parseInt(_gInput.text) ?? 0));
var b:Float = Math.max(0, Math.min(255, Std.parseInt(_bInput.text) ?? 0));
this.selectedColor = (Math.round(r) << 16) | (Math.round(g) << 8) | Math.round(b);
updateFromRGB();
} else {
var h = Math.max(0, Math.min(360, Math.round(Std.parseFloat(_hInput.text)) ?? 0));
var s = Math.max(0, Math.min(100, Math.round(Std.parseFloat(_sInput.text)) ?? 0)) / 100;
var brightness = Math.max(0, Math.min(100, Math.round(Std.parseFloat(_brightnessInput.text)) ?? 0)) / 100;
_hue = h;
_saturation = s;
_brightness = brightness;
var rgb = hsbToRgb(_hue, _saturation, _brightness);
this.selectedColor = (rgb.r << 16) | (rgb.g << 8) | rgb.b;
updateInputs();
updateSBSquare();
updateIndicators();
updatePreview();
}
_isUpdating = false;
FeathersEvent.dispatch(this, Event.CHANGE);
}
private function updateFromRGB():Void {
var r = (selectedColor >> 16) & 0xFF;
var g = (selectedColor >> 8) & 0xFF;
var b = selectedColor & 0xFF;
var hsb = rgbToHsb(r, g, b);
_hue = hsb.h;
_saturation = hsb.s;
_brightness = hsb.b;
updateInputs();
updateSBSquare();
updateIndicators();
updatePreview();
}
private function updateFromHSB():Void {
var rgb = hsbToRgb(_hue, _saturation, _brightness);
this.selectedColor = (rgb.r << 16) | (rgb.g << 8) | rgb.b;
if (_isUpdating) return;
_isUpdating = true;
updateInputs();
updateSBSquare();
updateIndicators();
updatePreview();
_isUpdating = false;
FeathersEvent.dispatch(this, Event.CHANGE);
}
private function updateInputs():Void {
// Add null checks to prevent errors
if (_rInput == null || _gInput == null || _bInput == null ||
_hInput == null || _sInput == null || _brightnessInput == null) {
return;
}
var r = (selectedColor >> 16) & 0xFF;
var g = (selectedColor >> 8) & 0xFF;
var b = selectedColor & 0xFF;
_rInput.text = Std.string(r);
_gInput.text = Std.string(g);
_bInput.text = Std.string(b);
_hInput.text = Std.string(Math.round(_hue));
_sInput.text = Std.string(Math.round(_saturation * 100));
_brightnessInput.text = Std.string(Math.round(_brightness * 100));
}
private function updateSBSquare():Void {
if (_sbSquareBitmap == null || _sbSquareBitmap.bitmapData == null) {
return;
}
_sbSquareBitmap.bitmapData = createSBSquare(150);
}
private function updateIndicators():Void {
if (_hueIndicator == null || _sbIndicator == null || _hueWheelBitmap == null || _sbSquareBitmap == null) {
return;
}
// Update hue indicator
var hueAngle = _hue * Math.PI / 180;
var hueRadius = 60;
_hueIndicator.x = _hueWheelBitmap.x + 75 + Math.cos(hueAngle) * hueRadius;
_hueIndicator.y = _hueWheelBitmap.y + 75 + Math.sin(hueAngle) * hueRadius;
// Update SB indicator
_sbIndicator.x = _sbSquareBitmap.x + _saturation * 150;
_sbIndicator.y = _sbSquareBitmap.y + (1 - _brightness) * 150;
}
private function updatePreview():Void {
if (_previewBitmap == null || _previewBitmap.bitmapData == null) {
return;
}
_previewBitmap.bitmapData.fillRect(_previewBitmap.bitmapData.rect, 0xFF000000 | selectedColor);
}
private function createHueWheel(radius:Float):BitmapData {
var size = Std.int(radius * 2);
var bmd = new BitmapData(size, size, false, 0x000000);
for (y in 0...size) {
for (x in 0...size) {
var dx = x - radius;
var dy = y - radius;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= radius && distance >= radius - 15) {
var hue = Math.atan2(dy, dx) * 180 / Math.PI;
if (hue < 0) hue += 360;
var rgb = hsbToRgb(hue, 1, 1);
var color = (rgb.r << 16) | (rgb.g << 8) | rgb.b;
bmd.setPixel(x, y, color);
}
}
}
return bmd;
}
private function createSBSquare(size:Int):BitmapData {
var bmd = new BitmapData(size, size, false, 0x000000);
for (y in 0...size) {
for (x in 0...size) {
var saturation = x / size;
var brightness = 1 - (y / size);
var rgb = hsbToRgb(_hue, saturation, brightness);
var color = (rgb.r << 16) | (rgb.g << 8) | rgb.b;
bmd.setPixel(x, y, color);
}
}
return bmd;
}
private function hsbToRgb(h:Float, s:Float, b:Float):{r:Int, g:Int, b:Int} {
var c = b * s;
var x = c * (1 - Math.abs(((h / 60) % 2) - 1));
var m = b - c;
var r:Float, g:Float, blue:Float;
if (h < 60) {
r = c; g = x; blue = 0;
} else if (h < 120) {
r = x; g = c; blue = 0;
} else if (h < 180) {
r = 0; g = c; blue = x;
} else if (h < 240) {
r = 0; g = x; blue = c;
} else if (h < 300) {
r = x; g = 0; blue = c;
} else {
r = c; g = 0; blue = x;
}
return {
r: Math.round((r + m) * 255),
g: Math.round((g + m) * 255),
b: Math.round((blue + m) * 255)
};
}
private function rgbToHsb(r:Int, g:Int, b:Int):{h:Float, s:Float, b:Float} {
var rf = r / 255;
var gf = g / 255;
var bf = b / 255;
var max = Math.max(rf, Math.max(gf, bf));
var min = Math.min(rf, Math.min(gf, bf));
var delta = max - min;
var h:Float = 0;
var s:Float = max == 0 ? 0 : delta / max;
var brightness:Float = max;
if (delta != 0) {
if (max == rf) {
h = 60 * (((gf - bf) / delta) % 6);
} else if (max == gf) {
h = 60 * (((bf - rf) / delta) + 2);
} else {
h = 60 * (((rf - gf) / delta) + 4);
}
}
if (h < 0) h += 360;
return {h: h, s: s, b: brightness};
}
override private function update():Void {
this.saveMeasurements(550, 170, 550, 170);
super.update();
}
}
Then you use it like so:
var popUpHSBColorPicker = new PopUpHSBColorPicker();
addChild(popUpHSBColorPicker);
popUpHSBColorPicker.addEventListener(Event.CHANGE, (event:Event) -> {
var colorPicker = cast(event.currentTarget, PopUpHSBColorPicker);
trace("Color selected: " + colorPicker.selectedColor);
});
Late to the party (as usual!), but there is a HaxeUI version:
… though maybe there wasnt at the time of the OP - not sure
https://haxeui.org/explorer/#basic/color_pickers
Cheers,
Ian
Very nice! I was also wanting to put in sliders and some antialiasing.