Skip to content

Commit

Permalink
Color picker update with team color presets. Bots added will use avai…
Browse files Browse the repository at this point in the history
…lable team color presets by default
  • Loading branch information
drogoganor committed Mar 18, 2018
1 parent cf944ae commit c7dc713
Show file tree
Hide file tree
Showing 12 changed files with 528 additions and 89 deletions.
1 change: 1 addition & 0 deletions OpenRA.Game/Settings.cs
Expand Up @@ -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 HSLColor[] CustomColors = { };
}

public class GameSettings
Expand Down
17 changes: 16 additions & 1 deletion OpenRA.Mods.Common/ColorValidator.cs
Expand Up @@ -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 HSLColor[] TeamColorPresets = { };

double GetColorDelta(Color colorA, Color colorB)
{
Expand Down Expand Up @@ -86,6 +87,20 @@ public bool IsValid(Color askedColor, out Color forbiddenColor, IEnumerable<Colo
return true;
}

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);
}

public HSLColor RandomValidColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors)
{
HSLColor color;
Expand Down Expand Up @@ -142,7 +157,7 @@ public HSLColor MakeValid(Color askedColor, MersenneTwister random, IEnumerable<
// If we reached the limit (The ii >= 255 prevents too much calculations)
if (attempt >= 255)
{
color = RandomValidColor(random, terrainColors, playerColors);
color = RandomPresetColor(random, terrainColors, playerColors);
break;
}

Expand Down
2 changes: 1 addition & 1 deletion OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs
Expand Up @@ -321,7 +321,7 @@ public bool InterpretCommand(S server, Connection conn, Session.Client client, s
var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color);
var playerColors = server.LobbyInfo.Clients.Select(c => c.Color.RGB)
.Concat(server.Map.Players.Players.Values.Select(p => p.Color.RGB));
bot.Color = bot.PreferredColor = validator.RandomValidColor(server.Random, terrainColors, playerColors);
bot.Color = bot.PreferredColor = validator.RandomPresetColor(server.Random, terrainColors, playerColors);
server.LobbyInfo.Clients.Add(bot);
}
Expand Down
28 changes: 28 additions & 0 deletions OpenRA.Mods.Common/Widgets/ColorBlockWidget.cs
Expand Up @@ -19,6 +19,9 @@ public class ColorBlockWidget : Widget
{
public Func<Color> GetColor;

public Action<MouseInput> OnMouseDown = _ => { };
public Action<MouseInput> OnMouseUp = _ => { };

public ColorBlockWidget()
{
GetColor = () => Color.White;
Expand All @@ -39,5 +42,30 @@ public override void Draw()
{
WidgetUtils.FillRectWithColor(RenderBounds, GetColor());
}

public override bool HandleMouseInput(MouseInput mi)
{
if (mi.Button != MouseButton.Left)
return false;

if (mi.Event == MouseInputEvent.Down && !TakeMouseFocus(mi))
return false;

if (HasMouseFocus && mi.Event == MouseInputEvent.Up)
{
// Only fire the onMouseUp event if we successfully lost focus, and were pressed
OnMouseUp(mi);

return YieldMouseFocus(mi);
}

if (mi.Event == MouseInputEvent.Down)
{
// OnMouseDown returns false if the button shouldn't be pressed
OnMouseDown(mi);
}

return false;
}
}
}
111 changes: 110 additions & 1 deletion OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs
Expand Up @@ -10,7 +10,11 @@
#endregion

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Lint;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Widgets;
Expand All @@ -19,8 +23,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
public class ColorPickerLogic : ChromeLogic
{
static bool paletteTabOpenedLast;

[ObjectCreator.UseCtor]
public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor initialColor, Action<HSLColor> onChange, WorldRenderer worldRenderer)
public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor initialColor, Action<HSLColor> onChange, Dictionary<string, MiniYaml> logicArgs)
{
string actorType;
if (!ChromeMetrics.TryGet("ColorPickerActorType", out actorType))
Expand All @@ -47,6 +53,7 @@ public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor in
mixer.OnChange += () => onChange(mixer.Color);

if (randomButton != null)
{
randomButton.OnClick = () =>
{
// Avoid colors with low sat or lum
Expand All @@ -57,6 +64,7 @@ public ColorPickerLogic(Widget widget, ModData modData, World world, HSLColor in
mixer.Set(new HSLColor(hue, sat, lum));
hueSlider.Value = hue / 255f;
};
}

// Set the initial state
var validator = modData.Manifest.Get<ColorValidator>();
Expand All @@ -65,6 +73,107 @@ 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("MIXER_TAB");
var paletteTab = widget.Get("PALETTE_TAB");
var paletteTabScrollPanel = widget.Get("PALETTE_TAB_SCROLLPANEL");
var mixerTabButton = widget.Get<ButtonWidget>("MIXER_TAB_BUTTON");
var paletteTabButton = widget.Get<ButtonWidget>("PALETTE_TAB_BUTTON");
var presetArea = paletteTabScrollPanel.Get<ContainerWidget>("PRESET_AREA");
var customArea = paletteTabScrollPanel.Get<ContainerWidget>("CUSTOM_AREA");
var presetColorTemplate = paletteTabScrollPanel.Get<ColorBlockWidget>("COLORPRESET");
var customColorTemplate = paletteTabScrollPanel.Get<ColorBlockWidget>("COLORCUSTOM");

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

paletteTab.IsVisible = () => paletteTabOpenedLast;
paletteTabButton.OnClick = () => paletteTabOpenedLast = true;
paletteTabButton.IsHighlighted = paletteTab.IsVisible;

var paletteCols = 8;
var palettePresetRows = 2;
var paletteCustomRows = 1;

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

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);
}
}

// Store color button
var storeButton = widget.Get<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();
};
}
}

public static void ShowColorDropDown(DropDownButtonWidget color, ColorPreviewManagerWidget preview, World world)
Expand Down

0 comments on commit c7dc713

Please sign in to comment.