Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Color picker update with team color presets #14853

Merged
merged 1 commit into from Mar 19, 2018

Conversation

Projects
None yet
8 participants
@drogoganor
Copy link
Contributor

drogoganor commented Feb 25, 2018

Changes to the color picker and ColorValidator to support built-in team colors.

colorpresets

Preset colors are defined in mod.yaml as TeamColorPresets. These are based off the colors in the original games, with a couple of extras I selected myself.

Users can also save a selected color in the Custom Colors by holding LCtrl and clicking a swatch.

Bots added to skirmish or multiplayer games will use a preset color if there are any available. If all preset colors are used, a random color will be used instead.

The previous attempt at this was: #13072

@@ -0,0 +1,79 @@
#region Copyright & License Information
/*
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)

This comment has been minimized.

@GraionDilach

GraionDilach Feb 25, 2018

Contributor

Outdated header.

@MustaphaTR

This comment has been minimized.

Copy link
Member

MustaphaTR commented Feb 25, 2018

These are based off the colors in the original games, with a couple of extras I selected myself.

I think we should refer the tests done by @pi99y on #11248. Which was meant to be differ from eachother and tilesets as much as possible (he had 15 color for each mod tho, not 10). Rather than sticking to original colors.


namespace OpenRA.Mods.Common.Widgets
{
public class ColorPaletteSwatchWidget : BackgroundWidget

This comment has been minimized.

@pchote

pchote Feb 25, 2018

Member

Can you please add the click handling to ColorBlockWidget instead of creating a new widget type?

@@ -69,12 +69,13 @@ public class Manifest
public readonly string[] SoundFormats = { };
public readonly string[] SpriteFormats = { };
public readonly string[] PackageFormats = { };
public readonly string[] TeamColorPresets = { };

This comment has been minimized.

@pchote

pchote Feb 25, 2018

Member

Please define these on the ColorValidator instead of creating a new engine-level field. IGlobalModData implementations can automatically parse information out of the mod.yaml: see MapGrid for a simple example.

@@ -86,6 +86,62 @@ public bool IsValid(Color askedColor, out Color forbiddenColor, IEnumerable<Colo
return true;
}

public List<Color> GetModPresetColors()

This comment has been minimized.

@pchote

pchote Feb 25, 2018

Member

It would be better to stick with HSLColors from the start, otherwise you need to needlessly convert between types.

@@ -42,3 +42,23 @@ Background@COLOR_CHOOSER:
Y: 21
Width: 80
Height: 73
Label@PRESETCOLORSLABEL:

This comment has been minimized.

@pchote

pchote Feb 25, 2018

Member

Having everything on the one panel looks awkward IMO.
Can you put these into a separate tab instead? Here is an old mockup from when the color picker was originally being built showing how it could look:

htoxo14

This comment has been minimized.

@drogoganor

drogoganor Feb 25, 2018

Author Contributor

Thanks for the feedback. I'll give this another try.

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Feb 25, 2018

Thanks all, I'll give this another shot soon.

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Feb 27, 2018

I have a new version of this in the works, here's what it looks like so far. The colors used are the ones recommended by pi99y.

colorpresets2

Any advice you have would be welcomed. I'm not so sure of how it looks. Is a Clear button even required for the custom palette? Should it prompt the user to ensure they want to delete their custom palette?

@pchote

This comment has been minimized.

Copy link
Member

pchote commented Feb 27, 2018

The way I would do it is to make the custom colors a rolling queue and remove the Clear button. Then, instead of using Ctrl+click, I would have an explicit "Store" button below the "Random" button on the side.

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Feb 27, 2018

I've changed things to be that way, with a Store button. I quite like it. I will need to do some more rework though. I also increased the size of the swatches, to have two rows of 8.

colorpresets3

@GraionDilach

This comment has been minimized.

Copy link
Contributor

GraionDilach commented Feb 27, 2018

I wouldn't go requiring 16 preset colors, but format the code to allow it being set up with 8 colors alone as well.

As #11248 proves, it's really hard to set up 16 significantly different colors on all terrain types of a mod. Sure, there is a setup for RA1 in the ticket, but the same color shades might not work for Tiberian Sun or the thirdparty mods (KKND, D2, RA2 comes in mind) which probably only deliver 8 colors from their respective games.

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 1, 2018

Here's what it looks like with just 8, a random shortlist of colors:

colorpresets4

I think 8 is perfectly fine, but it can be changed easily now. I've made the swatches including the label be dynamically generated.

I've retained the Ctrl+Click functionality to set colors - if your colors are maxed out, you might not want to overwrite the first color.

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch from 538042f to 0c691d3 Mar 1, 2018

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 1, 2018

For reference, the colors included for all 4 mods. TS is the same colors for CNC as this wasn't included in pi99y's analysis: #11248

colorpresets5

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 3, 2018

I've spoken to some peeps and I'm going to use the very compact scroll widget headers for Preset and Custom Colors labels. I'm also going to fit the swatches to the window size more appropriately (or at least try). Hopeful to get onto this today.

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 3, 2018

Here's what I have so far. Swatch is now a template item which can be resized in the yaml instead of constructed by code.

colorpresets6

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch 2 times, most recently from 6c3c43d to a9f7818 Mar 3, 2018

for (int i = 0; i < colorList.Length; i++)
{
var nameString = controlName + i;
var newSwatch = new ColorBlockWidget()

This comment has been minimized.

@pchote

pchote Mar 3, 2018

Member

This can simplify to newSwatch = (ColorBlockWidget)template.Clone()

This comment has been minimized.

@drogoganor

drogoganor Mar 4, 2018

Author Contributor

Is it alright if it looks like this afterward?

var newSwatch = (ColorBlockWidget)template.Clone();
newSwatch.Visible = true;
newSwatch.IsVisible = () => true;
newSwatch.Id = nameString;
newSwatch.X = x.ToString();
newSwatch.Y = y.ToString();
newSwatch.Initialize(new WidgetArgs());

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch from a9f7818 to 66ca303 Mar 3, 2018

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 3, 2018

New version having resized the mixer:

colorpresets6

@pchote

This comment has been minimized.

Copy link
Member

pchote commented Mar 3, 2018

Looks great!

Two last UI nits:

  • Can you please make the Random and Store buttons a few px wider so that they have the same margin on the left as on the right?
  • The header background in RA and TS should use the "up" version of the panel rather than the "down" version. I think this is called dialog2.

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch from 66ca303 to cf29ac4 Mar 3, 2018

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 3, 2018

Good one on the dialog2. This is what it looks like now:

colorpresets6

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch from cf29ac4 to ca9cbbc Mar 4, 2018

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 4, 2018

Changed swatch creation to use a clone of the template swatch. I had to set Visible to true and also IsVisible = () => true; to get it to work correctly. Also fixed a bug with swatch removal after moving to the new UI element types. I'm pretty happy with it, fingers crossed!

@pchote
Copy link
Member

pchote left a comment

Looking good!

I have one moderate structural request that should simplify the implementation a lot. I expect to have some smaller comments once this has been done.

@@ -161,6 +161,7 @@ public class PlayerSettings
public string Name = "Newbie";
public HSLColor Color = new HSLColor(75, 255, 180);
public string LastServer = "localhost:1234";
public string[] CustomColors;

This comment has been minimized.

@pchote

pchote Mar 10, 2018

Member

Please declare this as public HSLColor[] CustomColors = {}. The engine will automatically handle serialization to/from strings, and defaulting to an empty array here saves you having to check for null later.

@@ -24,6 +24,7 @@ public class ColorValidator : IGlobalModData
public readonly int Threshold = 0x50;
public readonly float[] HsvSaturationRange = new[] { 0.25f, 1f };
public readonly float[] HsvValueRange = new[] { 0.2f, 1.0f };
public readonly string[] TeamColorPresets = { };

This comment has been minimized.

@pchote

pchote Mar 10, 2018

Member

Likewise here.

}
else
{
// Wrap around if reached maximum

This comment has been minimized.

@pchote

pchote Mar 10, 2018

Member

IMO it would feel much better ingame if this always inserted the color at the start (list.Insert(0, hexColor)), rolling all the older colors one step forward in the list.


int initX = x;

for (int i = 0; i < colorList.Length; i++)

This comment has been minimized.

@pchote

pchote Mar 10, 2018

Member

Style nit: loop indices should be declared as var

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 11, 2018

Sure thing, using HSLColor was a really good idea. I didn't know it would automatically serialize like that. It simplified things a bit.

I've added the latest change as a separate commit, because it might be a bit easier to review that way. Although if I should use a single squashed commit instead, let me know. I was going to squash it into a single commit at the end once it gets approved.

@pchote
Copy link
Member

pchote left a comment

Here are a few more suggestions to further simplify things:

@@ -86,6 +87,36 @@ public bool IsValid(Color askedColor, out Color forbiddenColor, IEnumerable<Colo
return true;
}

public HSLColor RandomPresetColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors)

This comment has been minimized.

@pchote

pchote Mar 17, 2018

Member

This method can simplify down to:

public HSLColor RandomPresetColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors)
{
	if (TeamColorPresets.Any())
	{
		Color forbidden;
		Action<string> ignoreError = _ => { };
		foreach (var c in TeamColorPresets.Shuffle(random))
			if (IsValid(c.RGB, out forbidden, terrainColors, playerColors, ignoreError))
				return c;
	}

	return RandomValidColor(random, terrainColors, playerColors);
}
var presetColorTemplate = paletteTabScrollPanel.GetOrNull<ColorBlockWidget>("COLORPRESET");
var customColorTemplate = paletteTabScrollPanel.GetOrNull<ColorBlockWidget>("COLORCUSTOM");

mixerTabButton.OnClick = () =>

This comment has been minimized.

@pchote

pchote Mar 17, 2018

Member

This can simplify to:

mixerTab.IsVisible = () => !paletteTabOpenedLast;
mixerTabButton.OnClick = () => paletteTabOpenedLast = false;
mixerTabButton.IsHighlighted = mixerTab.IsVisible;

paletteTab.IsVisible = () => paletteTabOpenedLast;
paletteTabButton.OnClick = () => paletteTabOpenedLast = true;
paletteTabButton.IsHighlighted = paletteTab.IsVisible;
@@ -65,6 +73,167 @@ public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor in

hueSlider.Value = initialColor.H / 255f;
onChange(mixer.Color);

// Setup tab controls
var mixerTab = widget.GetOrNull<BackgroundWidget>("MIXER_TAB");

This comment has been minimized.

@pchote

pchote Mar 17, 2018

Member

Using GetOrNull without checking for null results is asking for a NullReferenceException. Either use Get<> (which will throw if the requested widget doesn't exist), or add handling below for if they are missing.

mixerTab.Visible = false;
}

// Max and padding vars

This comment has been minimized.

@pchote

pchote Mar 17, 2018

Member

We can avoid all the manual state manipulation using something like this:

// TODO: these should be extracted to LogicArgs
// We can deal with these later
var paletteCols = 8;
var palettePresetRows = 2;
var paletteCustomRows = 1;

for (var j = 0; j < palettePresetRows; j++)
{
	for (var i = 0; i < paletteCols; i++)
	{
		var colorIndex = j * paletteCols + i;
		if (colorIndex >= validator.TeamColorPresets.Length)
			break;

		var color = validator.TeamColorPresets[colorIndex];
		var rgbColor = color.RGB;

		var newSwatch = (ColorBlockWidget)presetColorTemplate.Clone();
		newSwatch.GetColor = () => rgbColor;
		newSwatch.IsVisible = () => true;
		newSwatch.Bounds.X = i * newSwatch.Bounds.Width;
		newSwatch.Bounds.Y = j * newSwatch.Bounds.Height;
		newSwatch.OnMouseUp = m =>
		{
			mixer.Set(color);
			onChange(color);
		};

		presetArea.AddChild(newSwatch);
	}
}

for (var j = 0; j < paletteCustomRows; j++)
{
	for (var i = 0; i < paletteCols; i++)
	{
		var colorIndex = j * paletteCols + i;
		
		var newSwatch = (ColorBlockWidget)customColorTemplate.Clone();
		newSwatch.GetColor = () => Game.Settings.Player.CustomColors[colorIndex].RGB;
		newSwatch.IsVisible = () => Game.Settings.Player.CustomColors.Length > colorIndex;
		newSwatch.Bounds.X = i * newSwatch.Bounds.Width;
		newSwatch.Bounds.Y = j * newSwatch.Bounds.Height;
		newSwatch.OnMouseUp = m =>
		{
			var color = Game.Settings.Player.CustomColors[colorIndex];
			mixer.Set(color);
			onChange(color);
		};

		customArea.AddChild(newSwatch);
	}
}

var storeButton = widget.GetOrNull<ButtonWidget>("STORE_BUTTON");
if (storeButton != null)
{
	storeButton.OnClick = () =>
	{
		// Update the custom color list:
		//  - Remove any duplicates of the new color
		//  - Add the new color to the end
		//  - Save the last N colors
		Game.Settings.Player.CustomColors = Game.Settings.Player.CustomColors
			.Where(c => c != mixer.Color)
			.Append(mixer.Color)
			.Reverse().Take(paletteCustomRows * paletteCols).Reverse()
			.ToArray();
		Game.Settings.Save();
	};
}

newSwatch.OnMouseUp = (m) =>
{
if (isEditable && Game.GetModifierKeys().HasModifier(Modifiers.Ctrl))

This comment has been minimized.

@pchote

pchote Mar 17, 2018

Member

Note that i've dropped out this feature to simplify the code, as IMO it isn't really needed now that we have the "store" button.

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch from bc2eaf1 to a1a629e Mar 17, 2018

@pchote
Copy link
Member

pchote left a comment

A few last polish nits, then LGTM!

Can you please also apply the following yaml changes?

diff --git a/mods/cnc/chrome/color-picker.yaml b/mods/cnc/chrome/color-picker.yaml
index 6507171228..e7419c6116 100644
--- a/mods/cnc/chrome/color-picker.yaml
+++ b/mods/cnc/chrome/color-picker.yaml
@@ -5,26 +5,26 @@ Background@COLOR_CHOOSER:
 		PaletteCustomRows: 1
 	Background: panel-black
 	Width: 311
-	Height: 150
+	Height: 148
 	Children:
 		Button@RANDOM_BUTTON:
 			Key: tab
 			X: 229
-			Y: 91
+			Y: 89
 			Width: 77
 			Height: 25
 			Text: Random
 		Button@STORE_BUTTON:
 			X: 229
-			Y: 120
+			Y: 118
 			Width: 77
 			Height: 25
 			Text: Store
 			Font: Bold
 		ActorPreview@PREVIEW:
-			X: 230
+			X: 232
 			Y: 7
-			Width: 80
+			Width: 77
 			Height: 73
 			Animate: true
 		Button@MIXER_TAB_BUTTON:
@@ -41,8 +41,7 @@ Background@COLOR_CHOOSER:
 			Width: 80
 			Text: Palette
 			Font: Bold
-		Background@MIXER_TAB:
-			Background: panel-black
+		Container@MIXER_TAB:
 			X: 5
 			Y: 5
 			Width: PARENT_RIGHT - 91
@@ -66,7 +65,7 @@ Background@COLOR_CHOOSER:
 					X: 0
 					Y: 22
 					Width: PARENT_RIGHT
-					Height: 94
+					Height: 92
 					Children:
 						ColorMixer@MIXER:
 							X: 2
@@ -104,7 +103,7 @@ Background@COLOR_CHOOSER:
 							Width: PARENT_RIGHT - 4
 							Height: 58
 							X: 2
-							Y: 15
+							Y: 16
 							Children:
 								ColorBlock@COLORPRESET:
 									X: 0
@@ -117,7 +116,7 @@ Background@COLOR_CHOOSER:
 							Width: PARENT_RIGHT - 4
 							Height: 13
 							X: 2
-							Y: 72
+							Y: 71
 							Children:
 								Label@LABEL:
 									Font: TinyBold
diff --git a/mods/common/chrome/color-picker.yaml b/mods/common/chrome/color-picker.yaml
index 81e4ef7ad1..d67611fca3 100644
--- a/mods/common/chrome/color-picker.yaml
+++ b/mods/common/chrome/color-picker.yaml
@@ -5,27 +5,27 @@ Background@COLOR_CHOOSER:
 		PaletteCustomRows: 1
 	Background: dialog2
 	Width: 326
-	Height: 156
+	Height: 154
 	Children:
 		Button@RANDOM_BUTTON:
 			Key: tab
 			X: 245
-			Y: 97
+			Y: 95
 			Width: 76
 			Height: 25
 			Text: Random
 			Font: Bold
 		Button@STORE_BUTTON:
 			X: 245
-			Y: 126
+			Y: 124
 			Width: 76
 			Height: 25
 			Text: Store
 			Font: Bold
 		ActorPreview@PREVIEW:
 			X: 245
-			Y: 21
-			Width: 80
+			Y: 13
+			Width: 76
 			Height: 73
 		Button@MIXER_TAB_BUTTON:
 			X: 5
@@ -41,8 +41,7 @@ Background@COLOR_CHOOSER:
 			Width: 80
 			Text: Palette
 			Font: Bold
-		Background@MIXER_TAB:
-			Background: dialog3
+		Container@MIXER_TAB:
 			X: 5
 			Y: 5
 			Width: PARENT_RIGHT - 90
@@ -104,7 +103,7 @@ Background@COLOR_CHOOSER:
 							Width: PARENT_RIGHT - 4
 							Height: 58
 							X: 2
-							Y: 15
+							Y: 16
 							Children:
 								ColorBlock@COLORPRESET:
 									X: 0
@@ -117,7 +116,7 @@ Background@COLOR_CHOOSER:
 							Width: PARENT_RIGHT - 4
 							Height: 13
 							X: 2
-							Y: 76
+							Y: 75
 							Children:
 								Label@LABEL:
 									Font: TinyBold
diff --git a/mods/ts/chrome/color-picker.yaml b/mods/ts/chrome/color-picker.yaml
index 93f9bc184f..b833c71469 100644
--- a/mods/ts/chrome/color-picker.yaml
+++ b/mods/ts/chrome/color-picker.yaml
@@ -5,27 +5,27 @@ Background@COLOR_CHOOSER:
 		PaletteCustomRows: 1
 	Background: dialog2
 	Width: 326
-	Height: 156
+	Height: 154
 	Children:
 		Button@RANDOM_BUTTON:
 			Key: tab
 			X: 245
-			Y: 97
+			Y: 95
 			Width: 76
 			Height: 25
 			Text: Random
 			Font: Bold
 		Button@STORE_BUTTON:
 			X: 245
-			Y: 126
+			Y: 124
 			Width: 76
 			Height: 25
 			Text: Store
 			Font: Bold
 		ActorPreview@PREVIEW:
 			X: 245
-			Y: 11
-			Width: 80
+			Y: 16
+			Width: 76
 			Height: 74
 			Animate: true
 		Button@MIXER_TAB_BUTTON:
@@ -42,8 +42,7 @@ Background@COLOR_CHOOSER:
 			Width: 80
 			Text: Palette
 			Font: Bold
-		Background@MIXER_TAB:
-			Background: dialog3
+		Container@MIXER_TAB:
 			X: 5
 			Y: 5
 			Width: PARENT_RIGHT - 90
@@ -105,7 +104,7 @@ Background@COLOR_CHOOSER:
 							Width: PARENT_RIGHT - 4
 							Height: 58
 							X: 2
-							Y: 15
+							Y: 16
 							Children:
 								ColorBlock@COLORPRESET:
 									X: 0
@@ -118,7 +117,7 @@ Background@COLOR_CHOOSER:
 							Width: PARENT_RIGHT - 4
 							Height: 13
 							X: 2
-							Y: 76
+							Y: 75
 							Children:
 								Label@LABEL:
 									Font: TinyBold
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Widgets;

namespace OpenRA.Mods.Common.Widgets.Logic
{
[ChromeLogicArgsHotkeys("PaletteColumns", "PalettePresetRows", "PaletteCustomRows")]

This comment has been minimized.

@pchote

pchote Mar 18, 2018

Member

This is specific to hotkeys, so should be removed here.


MiniYaml yaml;
if (logicArgs.TryGetValue("PaletteColumns", out yaml))
int.TryParse(yaml.Value, out paletteCols);

This comment has been minimized.

@pchote

pchote Mar 18, 2018

Member

We can improve the behaviour when an invalid value is given by doing something like:

if (logicArgs.TryGetValue("PaletteColumns", out yaml))
	if (!int.TryParse(yaml.Value, out paletteCols))
		throw new YamlException("Invalid value for PaletteColumns: {0}".F(yaml.Value));

(and likewise for the other two).

@@ -65,6 +74,104 @@ public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor in

hueSlider.Value = initialColor.H / 255f;
onChange(mixer.Color);

// Setup tab controls
var mixerTab = widget.Get<BackgroundWidget>("MIXER_TAB");

This comment has been minimized.

@pchote

pchote Mar 18, 2018

Member

For these first three we don't care what type of widget they are, so just use widget.Get("MIXER_TAB"); and so on. This lets us use a ContainerWidget or a BackgroundWidget depending on whatever UI we want.

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch 2 times, most recently from c7dc713 to 8904340 Mar 18, 2018

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 18, 2018

Thanks. I've updated the code and yaml. Also rebased to the latest bleed. Fingers crossed I've done it correctly.

@reaperrr

This comment has been minimized.

Copy link
Contributor

reaperrr commented Mar 18, 2018

Looks good to me, LGTM once @pchote has given this a last look-over.

@pchote
Copy link
Member

pchote left a comment

One last minor nit, then LGTM

// Setup tab controls
var mixerTab = widget.Get("MIXER_TAB");
var paletteTab = widget.Get("PALETTE_TAB");
var paletteTabScrollPanel = widget.Get("PALETTE_TAB_SCROLLPANEL");

This comment has been minimized.

@pchote

pchote Mar 19, 2018

Member

This isn't a scrollpanel, so can you please rename to var palettePanel and PALETTE_TAB_PANEL?

@drogoganor drogoganor dismissed stale reviews from pchote and reaperrr via 2e4c2c6 Mar 19, 2018

@drogoganor drogoganor force-pushed the drogoganor:color-picker-update2 branch from 8904340 to 2e4c2c6 Mar 19, 2018

@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 19, 2018

Renamed UI component and associated variable as suggested.

@pchote

pchote approved these changes Mar 19, 2018

@pchote pchote merged commit 9bc9ce4 into OpenRA:bleed Mar 19, 2018

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@drogoganor

This comment has been minimized.

Copy link
Contributor Author

drogoganor commented Mar 19, 2018

Thanks for all your help!

@drogoganor drogoganor deleted the drogoganor:color-picker-update2 branch Mar 19, 2018

@pi99y

This comment has been minimized.

Copy link

pi99y commented May 24, 2018

Yay! Thank you guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.