Merge pull request #6632 from steelphase-forks/common-widgets
Mods.Common Widgets
This commit is contained in:
@@ -12,7 +12,7 @@ using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Mods.RA.Graphics
|
||||
namespace OpenRA.Mods.Common.Graphics
|
||||
{
|
||||
public struct TextRenderable : IRenderable
|
||||
{
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
<Compile Include="Graphics\ContrailRenderable.cs" />
|
||||
<Compile Include="Graphics\RangeCircleRenderable.cs" />
|
||||
<Compile Include="ModChooserLoadScreen.cs" />
|
||||
<Compile Include="PaletteFromFile.cs" />
|
||||
<Compile Include="Traits\ProvidesRadar.cs" />
|
||||
<Compile Include="ServerTraits\ColorValidator.cs" />
|
||||
<Compile Include="ServerTraits\MasterServerPinger.cs" />
|
||||
<Compile Include="ServerTraits\PlayerPinger.cs" />
|
||||
@@ -69,8 +71,24 @@
|
||||
<Compile Include="Graphics\TextRenderable.cs" />
|
||||
<Compile Include="Graphics\VoxelActorPreview.cs" />
|
||||
<Compile Include="Graphics\VoxelRenderable.cs" />
|
||||
<Compile Include="Widgets\ConfirmationDialogs.cs" />
|
||||
<Compile Include="Widgets\HueSliderWidget.cs" />
|
||||
<Compile Include="Widgets\LabelWithTooltipWidget.cs" />
|
||||
<Compile Include="Widgets\LogicKeyListenerWidget.cs" />
|
||||
<Compile Include="Widgets\Logic\AssetBrowserLogic.cs" />
|
||||
<Compile Include="Widgets\ColorMixerWidget.cs" />
|
||||
<Compile Include="Widgets\LogicTickerWidget.cs" />
|
||||
<Compile Include="Widgets\Logic\ButtonTooltipLogic.cs" />
|
||||
<Compile Include="Widgets\Logic\ColorPickerLogic.cs" />
|
||||
<Compile Include="Widgets\ColorPreviewManagerWidget.cs" />
|
||||
<Compile Include="Widgets\Logic\DisconnectWatcherLogic.cs" />
|
||||
<Compile Include="Widgets\Logic\Ingame\IngameRadarDisplayLogic.cs" />
|
||||
<Compile Include="Widgets\Logic\Ingame\LoadIngamePlayerOrObserverUILogic.cs" />
|
||||
<Compile Include="Widgets\Logic\ModBrowserLogic.cs" />
|
||||
<Compile Include="Widgets\MenuButtonWidget.cs" />
|
||||
<Compile Include="Widgets\RadarWidget.cs" />
|
||||
<Compile Include="Widgets\ResourceBarWidget.cs" />
|
||||
<Compile Include="World\RadarPings.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
|
||||
58
OpenRA.Mods.Common/PaletteFromFile.cs
Normal file
58
OpenRA.Mods.Common/PaletteFromFile.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common
|
||||
{
|
||||
class PaletteFromFileInfo : ITraitInfo
|
||||
{
|
||||
[Desc("internal palette name")]
|
||||
public readonly string Name = null;
|
||||
[Desc("If defined, load the palette only for this tileset.")]
|
||||
public readonly string Tileset = null;
|
||||
[Desc("filename to load")]
|
||||
public readonly string Filename = null;
|
||||
[Desc("Map listed indices to shadow. Ignores previous color.")]
|
||||
public readonly int[] ShadowIndex = { };
|
||||
public readonly bool AllowModifiers = true;
|
||||
|
||||
public object Create(ActorInitializer init) { return new PaletteFromFile(init.world, this); }
|
||||
}
|
||||
|
||||
class PaletteFromFile : ILoadsPalettes
|
||||
{
|
||||
readonly World world;
|
||||
readonly PaletteFromFileInfo info;
|
||||
public PaletteFromFile(World world, PaletteFromFileInfo info)
|
||||
{
|
||||
this.world = world;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void LoadPalettes(WorldRenderer wr)
|
||||
{
|
||||
if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant())
|
||||
wr.AddPalette(info.Name, new ImmutablePalette(GlobalFileSystem.Open(info.Filename), info.ShadowIndex), info.AllowModifiers);
|
||||
}
|
||||
|
||||
public string Filename
|
||||
{
|
||||
get { return info.Filename; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return info.Name; }
|
||||
}
|
||||
}
|
||||
}
|
||||
45
OpenRA.Mods.Common/Traits/ProvidesRadar.cs
Normal file
45
OpenRA.Mods.Common/Traits/ProvidesRadar.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
[Desc("This actor enables the radar minimap.")]
|
||||
public class ProvidesRadarInfo : TraitInfo<ProvidesRadar> { }
|
||||
|
||||
public class ProvidesRadar : ITick
|
||||
{
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
public void Tick(Actor self) { IsActive = UpdateActive(self); }
|
||||
|
||||
static bool UpdateActive(Actor self)
|
||||
{
|
||||
// Check if powered
|
||||
if (self.IsDisabled()) return false;
|
||||
|
||||
var isJammed = self.World.ActorsWithTrait<JamsRadar>().Any(a => a.Actor.Owner.Stances[self.Owner] != Stance.Ally
|
||||
&& (self.Location - a.Actor.Location).Length <= a.Actor.Info.Traits.Get<JamsRadarInfo>().Range);
|
||||
|
||||
return !isJammed;
|
||||
}
|
||||
}
|
||||
|
||||
[Desc("When an actor with this trait is in range of an actor with ProvidesRadar, it will temporarily disable the radar minimap for the enemy player.")]
|
||||
public class JamsRadarInfo : TraitInfo<JamsRadar>
|
||||
{
|
||||
[Desc("Range for jamming.")]
|
||||
public readonly int Range = 0;
|
||||
}
|
||||
|
||||
public class JamsRadar { }
|
||||
}
|
||||
224
OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs
Normal file
224
OpenRA.Mods.Common/Widgets/ColorMixerWidget.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class ColorMixerWidget : Widget
|
||||
{
|
||||
public float[] SRange = {0.0f, 1.0f};
|
||||
public float[] VRange = {0.2f, 1.0f};
|
||||
public event Action OnChange = () => {};
|
||||
|
||||
float H, S, V;
|
||||
byte[] front, back;
|
||||
Sprite mixerSprite;
|
||||
bool isMoving;
|
||||
|
||||
bool update;
|
||||
object syncWorker = new object();
|
||||
Thread workerThread;
|
||||
bool workerAlive;
|
||||
|
||||
public ColorMixerWidget() {}
|
||||
public ColorMixerWidget(ColorMixerWidget other)
|
||||
: base(other)
|
||||
{
|
||||
OnChange = other.OnChange;
|
||||
H = other.H;
|
||||
S = other.S;
|
||||
V = other.V;
|
||||
}
|
||||
|
||||
public override void Initialize(WidgetArgs args)
|
||||
{
|
||||
base.Initialize(args);
|
||||
|
||||
// Bitmap data is generated in a background thread and then flipped
|
||||
front = new byte[4*256*256];
|
||||
back = new byte[4*256*256];
|
||||
|
||||
var rect = new Rectangle((int)(255*SRange[0]), (int)(255*(1 - VRange[1])), (int)(255*(SRange[1] - SRange[0]))+1, (int)(255*(VRange[1] - VRange[0])) + 1);
|
||||
var mixerSheet = new Sheet(new Size(256, 256), false);
|
||||
mixerSheet.Texture.SetData(front, 256, 256);
|
||||
mixerSprite = new Sprite(mixerSheet, rect, TextureChannel.Alpha);
|
||||
}
|
||||
|
||||
void GenerateBitmap()
|
||||
{
|
||||
// Generating the selection bitmap is slow,
|
||||
// so we do it in a background thread
|
||||
lock (syncWorker)
|
||||
{
|
||||
update = true;
|
||||
|
||||
if (workerThread == null || !workerAlive)
|
||||
{
|
||||
workerThread = new Thread(GenerateBitmapWorker);
|
||||
workerThread.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateBitmapWorker()
|
||||
{
|
||||
lock (syncWorker)
|
||||
workerAlive = true;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
float hue;
|
||||
lock (syncWorker)
|
||||
{
|
||||
if (!update)
|
||||
{
|
||||
workerAlive = false;
|
||||
break;
|
||||
}
|
||||
update = false;
|
||||
|
||||
// Take a local copy of the hue to generate to avoid tearing
|
||||
hue = H;
|
||||
}
|
||||
|
||||
lock (back)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
// Generate palette in HSV
|
||||
fixed (byte* cc = &back[0])
|
||||
{
|
||||
var c = (int*)cc;
|
||||
for (var v = 0; v < 256; v++)
|
||||
for (var s = 0; s < 256; s++)
|
||||
*(c + (v * 256) + s) = HSLColor.FromHSV(hue, s / 255f, (255 - v) / 255f).RGB.ToArgb();
|
||||
}
|
||||
}
|
||||
|
||||
lock (front)
|
||||
{
|
||||
var swap = front;
|
||||
front = back;
|
||||
back = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
if (Monitor.TryEnter(front))
|
||||
{
|
||||
try
|
||||
{
|
||||
mixerSprite.sheet.Texture.SetData(front, 256, 256);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(front);
|
||||
}
|
||||
}
|
||||
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(mixerSprite, RenderOrigin, new float2(RenderBounds.Size));
|
||||
|
||||
var sprite = ChromeProvider.GetImage("lobby-bits", "colorpicker");
|
||||
var pos = RenderOrigin + PxFromValue() - new int2(sprite.bounds.Width, sprite.bounds.Height) / 2;
|
||||
WidgetUtils.FillEllipseWithColor(new Rectangle(pos.X + 1, pos.Y + 1, sprite.bounds.Width - 2, sprite.bounds.Height - 2), Color.RGB);
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos);
|
||||
}
|
||||
|
||||
void SetValueFromPx(int2 xy)
|
||||
{
|
||||
var rb = RenderBounds;
|
||||
var s = SRange[0] + xy.X*(SRange[1] - SRange[0])/rb.Width;
|
||||
var v = SRange[1] - xy.Y*(VRange[1] - VRange[0])/rb.Height;
|
||||
S = s.Clamp(SRange[0], SRange[1]);
|
||||
V = v.Clamp(VRange[0], VRange[1]);
|
||||
}
|
||||
|
||||
int2 PxFromValue()
|
||||
{
|
||||
var rb = RenderBounds;
|
||||
var x = RenderBounds.Width*(S - SRange[0])/(SRange[1] - SRange[0]);
|
||||
var y = RenderBounds.Height*(1 - (V - VRange[0])/(VRange[1] - VRange[0]));
|
||||
return new int2((int)x.Clamp(0, rb.Width), (int)y.Clamp(0, rb.Height));
|
||||
}
|
||||
|
||||
public override bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
if (mi.Button != MouseButton.Left)
|
||||
return false;
|
||||
if (mi.Event == MouseInputEvent.Down && !TakeMouseFocus(mi))
|
||||
return false;
|
||||
if (!HasMouseFocus)
|
||||
return false;
|
||||
|
||||
switch (mi.Event)
|
||||
{
|
||||
case MouseInputEvent.Up:
|
||||
isMoving = false;
|
||||
YieldMouseFocus(mi);
|
||||
break;
|
||||
|
||||
case MouseInputEvent.Down:
|
||||
isMoving = true;
|
||||
SetValueFromPx(mi.Location - RenderOrigin);
|
||||
OnChange();
|
||||
break;
|
||||
|
||||
case MouseInputEvent.Move:
|
||||
if (isMoving)
|
||||
{
|
||||
SetValueFromPx(mi.Location - RenderOrigin);
|
||||
OnChange();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public HSLColor Color { get { return HSLColor.FromHSV(H, S, V); } }
|
||||
|
||||
public void Set(float hue)
|
||||
{
|
||||
if (H != hue)
|
||||
{
|
||||
H = hue;
|
||||
GenerateBitmap();
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(HSLColor color)
|
||||
{
|
||||
float h,s,v;
|
||||
color.ToHSV(out h, out s, out v);
|
||||
|
||||
if (H != h || S != s || V != v)
|
||||
{
|
||||
if (H != h)
|
||||
{
|
||||
H = h;
|
||||
GenerateBitmap();
|
||||
}
|
||||
|
||||
S = s.Clamp(SRange[0], SRange[1]);
|
||||
V = v.Clamp(VRange[0], VRange[1]);
|
||||
OnChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
OpenRA.Mods.Common/Widgets/ColorPreviewManagerWidget.cs
Normal file
51
OpenRA.Mods.Common/Widgets/ColorPreviewManagerWidget.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class ColorPreviewManagerWidget : Widget
|
||||
{
|
||||
public readonly string PaletteName = "colorpicker";
|
||||
public readonly int[] RemapIndices = ChromeMetrics.Get<int[]>("ColorPickerRemapIndices");
|
||||
public readonly float Ramp = 0.05f;
|
||||
public HSLColor Color;
|
||||
|
||||
HSLColor cachedColor;
|
||||
WorldRenderer worldRenderer;
|
||||
IPalette preview;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public ColorPreviewManagerWidget(WorldRenderer worldRenderer)
|
||||
{
|
||||
this.worldRenderer = worldRenderer;
|
||||
}
|
||||
|
||||
public override void Initialize(WidgetArgs args)
|
||||
{
|
||||
base.Initialize(args);
|
||||
preview = worldRenderer.Palette(PaletteName).Palette;
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
if (cachedColor == Color)
|
||||
return;
|
||||
cachedColor = Color;
|
||||
|
||||
var newPalette = new MutablePalette(preview);
|
||||
newPalette.ApplyRemap(new PlayerColorRemap(RemapIndices, Color, Ramp));
|
||||
worldRenderer.ReplacePalette(PaletteName, newPalette);
|
||||
}
|
||||
}
|
||||
}
|
||||
138
OpenRA.Mods.Common/Widgets/ConfirmationDialogs.cs
Normal file
138
OpenRA.Mods.Common/Widgets/ConfirmationDialogs.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public static class ConfirmationDialogs
|
||||
{
|
||||
public static void PromptConfirmAction(string title, string text, Action onConfirm, Action onCancel = null, string confirmText = null, string cancelText = null)
|
||||
{
|
||||
var prompt = Ui.OpenWindow("CONFIRM_PROMPT");
|
||||
prompt.Get<LabelWidget>("PROMPT_TITLE").GetText = () => title;
|
||||
prompt.Get<LabelWidget>("PROMPT_TEXT").GetText = () => text;
|
||||
if (!string.IsNullOrEmpty(confirmText))
|
||||
prompt.Get<ButtonWidget>("CONFIRM_BUTTON").GetText = () => confirmText;
|
||||
if (!string.IsNullOrEmpty(cancelText))
|
||||
prompt.Get<ButtonWidget>("CANCEL_BUTTON").GetText = () => cancelText;
|
||||
|
||||
prompt.Get<ButtonWidget>("CONFIRM_BUTTON").OnClick = () =>
|
||||
{
|
||||
Ui.CloseWindow();
|
||||
onConfirm();
|
||||
};
|
||||
|
||||
prompt.Get<ButtonWidget>("CANCEL_BUTTON").OnClick = () =>
|
||||
{
|
||||
Ui.CloseWindow();
|
||||
if (onCancel != null)
|
||||
onCancel();
|
||||
};
|
||||
}
|
||||
|
||||
public static void TextInputPrompt(
|
||||
string title, string prompt, string initialText,
|
||||
Action<string> onAccept, Action onCancel = null,
|
||||
string acceptText = null, string cancelText = null,
|
||||
Func<string, bool> inputValidator = null)
|
||||
{
|
||||
var panel = Ui.OpenWindow("TEXT_INPUT_PROMPT");
|
||||
Func<bool> doValidate = null;
|
||||
ButtonWidget acceptButton = null, cancelButton = null;
|
||||
|
||||
//
|
||||
// Title
|
||||
//
|
||||
panel.Get<LabelWidget>("PROMPT_TITLE").GetText = () => title;
|
||||
|
||||
//
|
||||
// Prompt
|
||||
//
|
||||
panel.Get<LabelWidget>("PROMPT_TEXT").GetText = () => prompt;
|
||||
|
||||
//
|
||||
// Text input
|
||||
//
|
||||
var input = panel.Get<TextFieldWidget>("INPUT_TEXT");
|
||||
var isValid = false;
|
||||
input.Text = initialText;
|
||||
input.IsValid = () => isValid;
|
||||
input.OnEnterKey = () =>
|
||||
{
|
||||
if (acceptButton.IsDisabled())
|
||||
return false;
|
||||
|
||||
acceptButton.OnClick();
|
||||
return true;
|
||||
};
|
||||
input.OnEscKey = () =>
|
||||
{
|
||||
if (cancelButton.IsDisabled())
|
||||
return false;
|
||||
|
||||
cancelButton.OnClick();
|
||||
return true;
|
||||
};
|
||||
input.TakeKeyboardFocus();
|
||||
input.CursorPosition = input.Text.Length;
|
||||
input.OnTextEdited = () => doValidate();
|
||||
|
||||
//
|
||||
// Buttons
|
||||
//
|
||||
acceptButton = panel.Get<ButtonWidget>("ACCEPT_BUTTON");
|
||||
if (!string.IsNullOrEmpty(acceptText))
|
||||
acceptButton.GetText = () => acceptText;
|
||||
|
||||
acceptButton.OnClick = () =>
|
||||
{
|
||||
if (!doValidate())
|
||||
return;
|
||||
|
||||
Ui.CloseWindow();
|
||||
onAccept(input.Text);
|
||||
};
|
||||
|
||||
cancelButton = panel.Get<ButtonWidget>("CANCEL_BUTTON");
|
||||
if (!string.IsNullOrEmpty(cancelText))
|
||||
cancelButton.GetText = () => cancelText;
|
||||
|
||||
cancelButton.OnClick = () =>
|
||||
{
|
||||
Ui.CloseWindow();
|
||||
if (onCancel != null)
|
||||
onCancel();
|
||||
};
|
||||
|
||||
//
|
||||
// Validation
|
||||
//
|
||||
doValidate = () =>
|
||||
{
|
||||
if (inputValidator == null)
|
||||
return true;
|
||||
|
||||
isValid = inputValidator(input.Text);
|
||||
if (isValid)
|
||||
{
|
||||
acceptButton.Disabled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
acceptButton.Disabled = true;
|
||||
return false;
|
||||
};
|
||||
|
||||
doValidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
61
OpenRA.Mods.Common/Widgets/HueSliderWidget.cs
Normal file
61
OpenRA.Mods.Common/Widgets/HueSliderWidget.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class HueSliderWidget : SliderWidget
|
||||
{
|
||||
Sprite hueSprite;
|
||||
|
||||
public HueSliderWidget() { }
|
||||
public HueSliderWidget(HueSliderWidget other) : base(other) { }
|
||||
|
||||
public override void Initialize(WidgetArgs args)
|
||||
{
|
||||
base.Initialize(args);
|
||||
|
||||
using (var hueBitmap = new Bitmap(256, 256))
|
||||
{
|
||||
var hueSheet = new Sheet(new Size(256, 256), false);
|
||||
hueSprite = new Sprite(hueSheet, new Rectangle(0, 0, 256, 1), TextureChannel.Alpha);
|
||||
|
||||
var bitmapData = hueBitmap.LockBits(hueBitmap.Bounds(),
|
||||
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
unsafe
|
||||
{
|
||||
var c = (int*)bitmapData.Scan0;
|
||||
for (var h = 0; h < 256; h++)
|
||||
*(c + h) = HSLColor.FromHSV(h / 255f, 1, 1).RGB.ToArgb();
|
||||
}
|
||||
hueBitmap.UnlockBits(bitmapData);
|
||||
hueSheet.Texture.SetData(hueBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
if (!IsVisible())
|
||||
return;
|
||||
|
||||
var ro = RenderOrigin;
|
||||
var rb = RenderBounds;
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(hueSprite, ro, new float2(rb.Size));
|
||||
|
||||
var sprite = ChromeProvider.GetImage("lobby-bits", "huepicker");
|
||||
var pos = RenderOrigin + new int2(PxFromValue(Value).Clamp(0, rb.Width - 1) - sprite.bounds.Width / 2, (rb.Height - sprite.bounds.Height) / 2);
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
OpenRA.Mods.Common/Widgets/LabelWithTooltipWidget.cs
Normal file
62
OpenRA.Mods.Common/Widgets/LabelWithTooltipWidget.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class LabelWithTooltipWidget : LabelWidget
|
||||
{
|
||||
public readonly string TooltipTemplate;
|
||||
public readonly string TooltipContainer;
|
||||
Lazy<TooltipContainerWidget> tooltipContainer;
|
||||
|
||||
public Func<string> GetTooltipText = () => "";
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public LabelWithTooltipWidget(World world)
|
||||
: base()
|
||||
{
|
||||
tooltipContainer = Exts.Lazy(() =>
|
||||
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
}
|
||||
|
||||
protected LabelWithTooltipWidget(LabelWithTooltipWidget other)
|
||||
: base(other)
|
||||
{
|
||||
TooltipTemplate = other.TooltipTemplate;
|
||||
TooltipContainer = other.TooltipContainer;
|
||||
|
||||
tooltipContainer = Exts.Lazy(() =>
|
||||
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
|
||||
GetTooltipText = other.GetTooltipText;
|
||||
}
|
||||
|
||||
public override Widget Clone() { return new LabelWithTooltipWidget(this); }
|
||||
|
||||
public override void MouseEntered()
|
||||
{
|
||||
if (TooltipContainer == null)
|
||||
return;
|
||||
|
||||
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "getText", GetTooltipText }});
|
||||
}
|
||||
|
||||
public override void MouseExited()
|
||||
{
|
||||
if (TooltipContainer == null)
|
||||
return;
|
||||
|
||||
tooltipContainer.Value.RemoveTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
320
OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs
Normal file
320
OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs
Normal file
@@ -0,0 +1,320 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileSystem;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class AssetBrowserLogic
|
||||
{
|
||||
Widget panel;
|
||||
|
||||
TextFieldWidget filenameInput;
|
||||
SliderWidget frameSlider;
|
||||
ScrollPanelWidget assetList;
|
||||
ScrollItemWidget template;
|
||||
|
||||
IFolder assetSource = null;
|
||||
List<string> availableShps = new List<string>();
|
||||
bool animateFrames = false;
|
||||
|
||||
string currentPalette;
|
||||
string currentFilename;
|
||||
Sprite[] currentSprites;
|
||||
int currentFrame;
|
||||
|
||||
readonly World world;
|
||||
|
||||
static readonly string[] AllowedExtensions = { ".shp", ".r8", "tmp", ".tem", ".des", ".sno", ".int", ".jun" };
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public AssetBrowserLogic(Widget widget, Action onExit, World world)
|
||||
{
|
||||
this.world = world;
|
||||
|
||||
panel = widget;
|
||||
assetSource = GlobalFileSystem.MountedFolders.First();
|
||||
|
||||
var ticker = panel.GetOrNull<LogicTickerWidget>("ANIMATION_TICKER");
|
||||
if (ticker != null)
|
||||
{
|
||||
ticker.OnTick = () =>
|
||||
{
|
||||
if (animateFrames)
|
||||
SelectNextFrame();
|
||||
};
|
||||
}
|
||||
|
||||
var sourceDropdown = panel.GetOrNull<DropDownButtonWidget>("SOURCE_SELECTOR");
|
||||
if (sourceDropdown != null)
|
||||
{
|
||||
sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown);
|
||||
sourceDropdown.GetText = () =>
|
||||
{
|
||||
var name = assetSource != null ? assetSource.Name.Replace(Platform.SupportDir, "^") : "All Packages";
|
||||
if (name.Length > 15)
|
||||
name = "..." + name.Substring(name.Length - 15);
|
||||
|
||||
return name;
|
||||
};
|
||||
}
|
||||
|
||||
var spriteWidget = panel.GetOrNull<SpriteWidget>("SPRITE");
|
||||
if (spriteWidget != null)
|
||||
{
|
||||
spriteWidget.GetSprite = () => currentSprites != null ? currentSprites[currentFrame] : null;
|
||||
currentPalette = spriteWidget.Palette;
|
||||
spriteWidget.GetPalette = () => currentPalette;
|
||||
}
|
||||
|
||||
var paletteDropDown = panel.GetOrNull<DropDownButtonWidget>("PALETTE_SELECTOR");
|
||||
if (paletteDropDown != null)
|
||||
{
|
||||
paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world);
|
||||
paletteDropDown.GetText = () => currentPalette;
|
||||
}
|
||||
|
||||
var colorPreview = panel.GetOrNull<ColorPreviewManagerWidget>("COLOR_MANAGER");
|
||||
if (colorPreview != null)
|
||||
colorPreview.Color = Game.Settings.Player.Color;
|
||||
|
||||
var colorDropdown = panel.GetOrNull<DropDownButtonWidget>("COLOR");
|
||||
if (colorDropdown != null)
|
||||
{
|
||||
colorDropdown.IsDisabled = () => currentPalette != colorPreview.PaletteName;
|
||||
colorDropdown.OnMouseDown = _ => ShowColorDropDown(colorDropdown, colorPreview, world);
|
||||
panel.Get<ColorBlockWidget>("COLORBLOCK").GetColor = () => Game.Settings.Player.Color.RGB;
|
||||
}
|
||||
|
||||
filenameInput = panel.Get<TextFieldWidget>("FILENAME_INPUT");
|
||||
filenameInput.OnTextEdited = () => ApplyFilter(filenameInput.Text);
|
||||
|
||||
var frameContainer = panel.GetOrNull("FRAME_SELECTOR");
|
||||
if (frameContainer != null)
|
||||
frameContainer.IsVisible = () => currentSprites != null && currentSprites.Length > 1;
|
||||
|
||||
frameSlider = panel.Get<SliderWidget>("FRAME_SLIDER");
|
||||
frameSlider.OnChange += x => { currentFrame = (int)Math.Round(x); };
|
||||
frameSlider.GetValue = () => currentFrame;
|
||||
|
||||
var frameText = panel.GetOrNull<LabelWidget>("FRAME_COUNT");
|
||||
if (frameText != null)
|
||||
frameText.GetText = () => "{0} / {1}".F(currentFrame + 1, currentSprites.Length);
|
||||
|
||||
var playButton = panel.GetOrNull<ButtonWidget>("BUTTON_PLAY");
|
||||
if (playButton != null)
|
||||
{
|
||||
playButton.OnClick = () => animateFrames = true;
|
||||
playButton.IsVisible = () => !animateFrames;
|
||||
}
|
||||
|
||||
var pauseButton = panel.GetOrNull<ButtonWidget>("BUTTON_PAUSE");
|
||||
if (pauseButton != null)
|
||||
{
|
||||
pauseButton.OnClick = () => animateFrames = false;
|
||||
pauseButton.IsVisible = () => animateFrames;
|
||||
}
|
||||
|
||||
var stopButton = panel.GetOrNull<ButtonWidget>("BUTTON_STOP");
|
||||
if (stopButton != null)
|
||||
{
|
||||
stopButton.OnClick = () =>
|
||||
{
|
||||
frameSlider.Value = 0;
|
||||
currentFrame = 0;
|
||||
animateFrames = false;
|
||||
};
|
||||
}
|
||||
|
||||
var nextButton = panel.GetOrNull<ButtonWidget>("BUTTON_NEXT");
|
||||
if (nextButton != null)
|
||||
nextButton.OnClick = SelectNextFrame;
|
||||
|
||||
var prevButton = panel.GetOrNull<ButtonWidget>("BUTTON_PREV");
|
||||
if (prevButton != null)
|
||||
prevButton.OnClick = SelectPreviousFrame;
|
||||
|
||||
assetList = panel.Get<ScrollPanelWidget>("ASSET_LIST");
|
||||
template = panel.Get<ScrollItemWidget>("ASSET_TEMPLATE");
|
||||
PopulateAssetList();
|
||||
|
||||
var closeButton = panel.GetOrNull<ButtonWidget>("CLOSE_BUTTON");
|
||||
if (closeButton != null)
|
||||
closeButton.OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||
}
|
||||
|
||||
void SelectNextFrame()
|
||||
{
|
||||
currentFrame++;
|
||||
if (currentFrame >= currentSprites.Length)
|
||||
currentFrame = 0;
|
||||
}
|
||||
|
||||
void SelectPreviousFrame()
|
||||
{
|
||||
currentFrame--;
|
||||
if (currentFrame < 0)
|
||||
currentFrame = currentSprites.Length - 1;
|
||||
}
|
||||
|
||||
Dictionary<string, bool> assetVisByName = new Dictionary<string, bool>();
|
||||
|
||||
bool FilterAsset(string filename)
|
||||
{
|
||||
var filter = filenameInput.Text;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filter))
|
||||
return true;
|
||||
|
||||
if (filename.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApplyFilter(string filename)
|
||||
{
|
||||
assetVisByName.Clear();
|
||||
assetList.Layout.AdjustChildren();
|
||||
assetList.ScrollToTop();
|
||||
|
||||
// Select the first visible
|
||||
var firstVisible = assetVisByName.FirstOrDefault(kvp => kvp.Value);
|
||||
if (firstVisible.Key != null)
|
||||
LoadAsset(firstVisible.Key);
|
||||
}
|
||||
|
||||
void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template)
|
||||
{
|
||||
var filename = Path.GetFileName(filepath);
|
||||
var item = ScrollItemWidget.Setup(template,
|
||||
() => currentFilename == filename,
|
||||
() => { LoadAsset(filename); });
|
||||
item.Get<LabelWidget>("TITLE").GetText = () => filepath;
|
||||
item.IsVisible = () =>
|
||||
{
|
||||
bool visible;
|
||||
if (assetVisByName.TryGetValue(filepath, out visible))
|
||||
return visible;
|
||||
|
||||
visible = FilterAsset(filepath);
|
||||
assetVisByName.Add(filepath, visible);
|
||||
return visible;
|
||||
};
|
||||
|
||||
list.AddChild(item);
|
||||
}
|
||||
|
||||
bool LoadAsset(string filename)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
return false;
|
||||
|
||||
if (!GlobalFileSystem.Exists(filename))
|
||||
return false;
|
||||
|
||||
currentFilename = filename;
|
||||
currentSprites = world.Map.SequenceProvider.SpriteLoader.LoadAllSprites(filename);
|
||||
currentFrame = 0;
|
||||
frameSlider.MaximumValue = (float)currentSprites.Length - 1;
|
||||
frameSlider.Ticks = currentSprites.Length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowSourceDropdown(DropDownButtonWidget dropdown)
|
||||
{
|
||||
Func<IFolder, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) =>
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => assetSource == source,
|
||||
() => { assetSource = source; PopulateAssetList(); });
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => source != null ? source.Name.Replace(Platform.SupportDir, "^") : "All Packages";
|
||||
return item;
|
||||
};
|
||||
|
||||
// TODO: Re-enable "All Packages" once list generation is done in a background thread
|
||||
// var sources = new[] { (IFolder)null }.Concat(GlobalFileSystem.MountedFolders);
|
||||
|
||||
var sources = GlobalFileSystem.MountedFolders;
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PopulateAssetList()
|
||||
{
|
||||
assetList.RemoveChildren();
|
||||
availableShps.Clear();
|
||||
|
||||
// TODO: This is too slow to run in the main thread
|
||||
// var files = AssetSource != null ? AssetSource.AllFileNames() :
|
||||
// GlobalFileSystem.MountedFolders.SelectMany(f => f.AllFileNames());
|
||||
|
||||
if (assetSource == null)
|
||||
return;
|
||||
|
||||
var files = assetSource.AllFileNames().OrderBy(s => s);
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (AllowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture)))
|
||||
{
|
||||
AddAsset(assetList, file, template);
|
||||
availableShps.Add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world)
|
||||
{
|
||||
Func<PaletteFromFile, ScrollItemWidget, ScrollItemWidget> setupItem = (palette, itemTemplate) =>
|
||||
{
|
||||
var name = palette.Name;
|
||||
var item = ScrollItemWidget.Setup(itemTemplate,
|
||||
() => currentPalette == name,
|
||||
() => currentPalette = name);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => name;
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
var palettes = world.WorldActor.TraitsImplementing<PaletteFromFile>();
|
||||
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ShowColorDropDown(DropDownButtonWidget color, ColorPreviewManagerWidget preview, World world)
|
||||
{
|
||||
Action onExit = () =>
|
||||
{
|
||||
Game.Settings.Player.Color = preview.Color;
|
||||
Game.Settings.Save();
|
||||
};
|
||||
|
||||
color.RemovePanel();
|
||||
|
||||
Action<HSLColor> onChange = c => preview.Color = c;
|
||||
|
||||
var colorChooser = Game.LoadWidget(world, "COLOR_CHOOSER", null, new WidgetArgs()
|
||||
{
|
||||
{ "onChange", onChange },
|
||||
{ "initialColor", Game.Settings.Player.Color }
|
||||
});
|
||||
|
||||
color.AttachPanel(colorChooser, onExit);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs
Normal file
57
OpenRA.Mods.Common/Widgets/Logic/ColorPickerLogic.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class ColorPickerLogic
|
||||
{
|
||||
[ObjectCreator.UseCtor]
|
||||
public ColorPickerLogic(Widget widget, HSLColor initialColor, Action<HSLColor> onChange, WorldRenderer worldRenderer)
|
||||
{
|
||||
var ticker = widget.GetOrNull<LogicTickerWidget>("ANIMATE_PREVIEW");
|
||||
if (ticker != null)
|
||||
{
|
||||
var preview = widget.Get<SpriteSequenceWidget>("PREVIEW");
|
||||
var anim = preview.GetAnimation();
|
||||
anim.PlayRepeating(anim.CurrentSequence.Name);
|
||||
ticker.OnTick = anim.Tick;
|
||||
}
|
||||
|
||||
var hueSlider = widget.Get<SliderWidget>("HUE");
|
||||
var mixer = widget.Get<ColorMixerWidget>("MIXER");
|
||||
var randomButton = widget.GetOrNull<ButtonWidget>("RANDOM_BUTTON");
|
||||
|
||||
hueSlider.OnChange += _ => mixer.Set(hueSlider.Value);
|
||||
mixer.OnChange += () => onChange(mixer.Color);
|
||||
|
||||
if (randomButton != null)
|
||||
randomButton.OnClick = () =>
|
||||
{
|
||||
// Avoid colors with low sat or lum
|
||||
var hue = (byte)Game.CosmeticRandom.Next(255);
|
||||
var sat = (byte)Game.CosmeticRandom.Next(70, 255);
|
||||
var lum = (byte)Game.CosmeticRandom.Next(70, 255);
|
||||
|
||||
mixer.Set(new HSLColor(hue, sat, lum));
|
||||
hueSlider.Value = hue / 255f;
|
||||
};
|
||||
|
||||
// Set the initial state
|
||||
mixer.Set(initialColor);
|
||||
hueSlider.Value = initialColor.H / 255f;
|
||||
onChange(mixer.Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
OpenRA.Mods.Common/Widgets/Logic/DisconnectWatcherLogic.cs
Normal file
37
OpenRA.Mods.Common/Widgets/Logic/DisconnectWatcherLogic.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class DisconnectWatcherLogic
|
||||
{
|
||||
[ObjectCreator.UseCtor]
|
||||
public DisconnectWatcherLogic(Widget widget, OrderManager orderManager)
|
||||
{
|
||||
var disconnected = false;
|
||||
widget.Get<LogicTickerWidget>("DISCONNECT_WATCHER").OnTick = () =>
|
||||
{
|
||||
if (disconnected || orderManager.Connection.ConnectionState != ConnectionState.NotConnected)
|
||||
return;
|
||||
|
||||
Game.RunAfterTick(() => Ui.OpenWindow("CONNECTIONFAILED_PANEL", new WidgetArgs {
|
||||
{ "orderManager", orderManager },
|
||||
{ "onAbort", null },
|
||||
{ "onRetry", null }
|
||||
}));
|
||||
|
||||
disconnected = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class IngameRadarDisplayLogic
|
||||
{
|
||||
[ObjectCreator.UseCtor]
|
||||
public IngameRadarDisplayLogic(Widget widget, World world)
|
||||
{
|
||||
var radarEnabled = false;
|
||||
var cachedRadarEnabled = false;
|
||||
var blockColor = Color.Transparent;
|
||||
var radar = widget.Get<RadarWidget>("RADAR_MINIMAP");
|
||||
radar.IsEnabled = () => radarEnabled;
|
||||
|
||||
var ticker = widget.Get<LogicTickerWidget>("RADAR_TICKER");
|
||||
ticker.OnTick = () =>
|
||||
{
|
||||
radarEnabled = world.ActorsWithTrait<ProvidesRadar>()
|
||||
.Any(a => a.Actor.Owner == world.LocalPlayer && a.Trait.IsActive);
|
||||
|
||||
if (radarEnabled != cachedRadarEnabled)
|
||||
Sound.PlayNotification(world.Map.Rules, null, "Sounds", radarEnabled ? "RadarUp" : "RadarDown", null);
|
||||
cachedRadarEnabled = radarEnabled;
|
||||
};
|
||||
|
||||
var block = widget.GetOrNull<ColorBlockWidget>("RADAR_FADETOBLACK");
|
||||
if (block != null)
|
||||
{
|
||||
radar.Animating = x => blockColor = Color.FromArgb((int)(255 * x), Color.Black);
|
||||
block.IsVisible = () => blockColor.A != 0;
|
||||
block.GetColor = () => blockColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
{
|
||||
public class LoadIngamePlayerOrObserverUILogic
|
||||
{
|
||||
[ObjectCreator.UseCtor]
|
||||
public LoadIngamePlayerOrObserverUILogic(Widget widget, World world)
|
||||
{
|
||||
var ingameRoot = widget.Get("INGAME_ROOT");
|
||||
var playerRoot = ingameRoot.Get("PLAYER_ROOT");
|
||||
|
||||
if (world.LocalPlayer == null)
|
||||
Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs());
|
||||
else
|
||||
{
|
||||
var playerWidgets = Game.LoadWidget(world, "PLAYER_WIDGETS", playerRoot, new WidgetArgs());
|
||||
var sidebarTicker = playerWidgets.Get<LogicTickerWidget>("SIDEBAR_TICKER");
|
||||
|
||||
sidebarTicker.OnTick = () =>
|
||||
{
|
||||
// Switch to observer mode after win/loss
|
||||
if (world.ObserveAfterWinOrLose && world.LocalPlayer.WinState != WinState.Undefined)
|
||||
Game.RunAfterTick(() =>
|
||||
{
|
||||
playerRoot.RemoveChildren();
|
||||
Game.LoadWidget(world, "OBSERVER_WIDGETS", playerRoot, new WidgetArgs());
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Game.LoadWidget(world, "CHAT_PANEL", ingameRoot, new WidgetArgs());
|
||||
|
||||
Action showLeaveMapWidget = () =>
|
||||
{
|
||||
ingameRoot.RemoveChildren();
|
||||
Game.LoadWidget(world, "LEAVE_MAP_WIDGET", Ui.Root, new WidgetArgs());
|
||||
};
|
||||
world.GameOver += showLeaveMapWidget;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
OpenRA.Mods.Common/Widgets/LogicKeyListenerWidget.cs
Normal file
25
OpenRA.Mods.Common/Widgets/LogicKeyListenerWidget.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class LogicKeyListenerWidget : Widget
|
||||
{
|
||||
public Func<KeyInput, bool> OnKeyPress = _ => false;
|
||||
|
||||
public override bool HandleKeyPress(KeyInput e)
|
||||
{
|
||||
return OnKeyPress(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
OpenRA.Mods.Common/Widgets/LogicTickerWidget.cs
Normal file
21
OpenRA.Mods.Common/Widgets/LogicTickerWidget.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class LogicTickerWidget : Widget
|
||||
{
|
||||
public Action OnTick = () => { };
|
||||
public override void Tick() { OnTick(); }
|
||||
}
|
||||
}
|
||||
33
OpenRA.Mods.Common/Widgets/MenuButtonWidget.cs
Normal file
33
OpenRA.Mods.Common/Widgets/MenuButtonWidget.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class MenuButtonWidget : ButtonWidget
|
||||
{
|
||||
public readonly string MenuContainer = "INGAME_MENU";
|
||||
public readonly bool Pause = true;
|
||||
public readonly bool HideIngameUI = true;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public MenuButtonWidget(Ruleset modRules)
|
||||
: base(modRules) { }
|
||||
|
||||
protected MenuButtonWidget(MenuButtonWidget other)
|
||||
: base(other)
|
||||
{
|
||||
MenuContainer = other.MenuContainer;
|
||||
Pause = other.Pause;
|
||||
HideIngameUI = other.HideIngameUI;
|
||||
}
|
||||
}
|
||||
}
|
||||
263
OpenRA.Mods.Common/Widgets/RadarWidget.cs
Normal file
263
OpenRA.Mods.Common/Widgets/RadarWidget.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public class RadarWidget : Widget
|
||||
{
|
||||
public string WorldInteractionController = null;
|
||||
public int AnimationLength = 5;
|
||||
public string RadarOnlineSound = null;
|
||||
public string RadarOfflineSound = null;
|
||||
public Func<bool> IsEnabled = () => true;
|
||||
public Action AfterOpen = () => { };
|
||||
public Action AfterClose = () => { };
|
||||
public Action<float> Animating = _ => {};
|
||||
|
||||
float radarMinimapHeight;
|
||||
int frame;
|
||||
bool hasRadar;
|
||||
bool cachedEnabled;
|
||||
int updateTicks;
|
||||
|
||||
float previewScale = 0;
|
||||
int2 previewOrigin = int2.Zero;
|
||||
Rectangle mapRect = Rectangle.Empty;
|
||||
|
||||
Sprite terrainSprite;
|
||||
Sprite customTerrainSprite;
|
||||
Sprite actorSprite;
|
||||
Sprite shroudSprite;
|
||||
|
||||
readonly World world;
|
||||
readonly WorldRenderer worldRenderer;
|
||||
|
||||
readonly RadarPings radarPings;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public RadarWidget(World world, WorldRenderer worldRenderer)
|
||||
{
|
||||
this.world = world;
|
||||
this.worldRenderer = worldRenderer;
|
||||
radarPings = world.WorldActor.TraitOrDefault<RadarPings>();
|
||||
}
|
||||
|
||||
public override void Initialize(WidgetArgs args)
|
||||
{
|
||||
base.Initialize(args);
|
||||
|
||||
var width = world.Map.Bounds.Width;
|
||||
var height = world.Map.Bounds.Height;
|
||||
var size = Math.Max(width, height);
|
||||
var rb = RenderBounds;
|
||||
|
||||
previewScale = Math.Min(rb.Width * 1f / width, rb.Height * 1f / height);
|
||||
previewOrigin = new int2((int)(previewScale * (size - width) / 2), (int)(previewScale * (size - height) / 2));
|
||||
mapRect = new Rectangle(previewOrigin.X, previewOrigin.Y, (int)(previewScale * width), (int)(previewScale * height));
|
||||
|
||||
// Only needs to be done once
|
||||
using (var terrainBitmap = Minimap.TerrainBitmap(world.Map.Rules.TileSets[world.Map.Tileset], world.Map))
|
||||
{
|
||||
var r = new Rectangle(0, 0, width, height);
|
||||
var s = new Size(terrainBitmap.Width, terrainBitmap.Height);
|
||||
var terrainSheet = new Sheet(s, false);
|
||||
terrainSheet.Texture.SetData(terrainBitmap);
|
||||
terrainSprite = new Sprite(terrainSheet, r, TextureChannel.Alpha);
|
||||
|
||||
// Data is set in Tick()
|
||||
customTerrainSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha);
|
||||
actorSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha);
|
||||
shroudSprite = new Sprite(new Sheet(s, false), r, TextureChannel.Alpha);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetCursor(int2 pos)
|
||||
{
|
||||
if (world == null || !hasRadar)
|
||||
return null;
|
||||
|
||||
var cell = MinimapPixelToCell(pos);
|
||||
var location = worldRenderer.Viewport.WorldToViewPx(worldRenderer.ScreenPxPosition(world.Map.CenterOfCell(cell)));
|
||||
|
||||
var mi = new MouseInput
|
||||
{
|
||||
Location = location,
|
||||
Button = MouseButton.Right,
|
||||
Modifiers = Game.GetModifierKeys()
|
||||
};
|
||||
|
||||
var cursor = world.OrderGenerator.GetCursor(world, cell, mi);
|
||||
if (cursor == null)
|
||||
return "default";
|
||||
|
||||
return Game.modData.CursorProvider.HasCursorSequence(cursor + "-minimap") ? cursor + "-minimap" : cursor;
|
||||
}
|
||||
|
||||
public override bool HandleMouseInput(MouseInput mi)
|
||||
{
|
||||
if (!mapRect.Contains(mi.Location))
|
||||
return false;
|
||||
|
||||
if (!hasRadar)
|
||||
return true;
|
||||
|
||||
var cell = MinimapPixelToCell(mi.Location);
|
||||
var pos = world.Map.CenterOfCell(cell);
|
||||
if ((mi.Event == MouseInputEvent.Down || mi.Event == MouseInputEvent.Move) && mi.Button == MouseButton.Left)
|
||||
worldRenderer.Viewport.Center(pos);
|
||||
|
||||
if (mi.Event == MouseInputEvent.Down && mi.Button == MouseButton.Right)
|
||||
{
|
||||
// fake a mousedown/mouseup here
|
||||
var location = worldRenderer.Viewport.WorldToViewPx(worldRenderer.ScreenPxPosition(pos));
|
||||
var fakemi = new MouseInput
|
||||
{
|
||||
Event = MouseInputEvent.Down,
|
||||
Button = MouseButton.Right,
|
||||
Modifiers = mi.Modifiers,
|
||||
Location = location
|
||||
};
|
||||
|
||||
if (WorldInteractionController != null)
|
||||
{
|
||||
var controller = Ui.Root.Get<WorldInteractionControllerWidget>(WorldInteractionController);
|
||||
controller.HandleMouseInput(fakemi);
|
||||
fakemi.Event = MouseInputEvent.Up;
|
||||
controller.HandleMouseInput(fakemi);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
if (world == null)
|
||||
return;
|
||||
|
||||
var o = new float2(mapRect.Location.X, mapRect.Location.Y + world.Map.Bounds.Height * previewScale * (1 - radarMinimapHeight) / 2);
|
||||
var s = new float2(mapRect.Size.Width, mapRect.Size.Height * radarMinimapHeight);
|
||||
|
||||
var rsr = Game.Renderer.RgbaSpriteRenderer;
|
||||
rsr.DrawSprite(terrainSprite, o, s);
|
||||
rsr.DrawSprite(customTerrainSprite, o, s);
|
||||
rsr.DrawSprite(actorSprite, o, s);
|
||||
rsr.DrawSprite(shroudSprite, o, s);
|
||||
|
||||
// Draw viewport rect
|
||||
if (hasRadar)
|
||||
{
|
||||
var tl = CellToMinimapPixel(world.Map.CellContaining(worldRenderer.Position(worldRenderer.Viewport.TopLeft)));
|
||||
var br = CellToMinimapPixel(world.Map.CellContaining(worldRenderer.Position(worldRenderer.Viewport.BottomRight)));
|
||||
|
||||
Game.Renderer.EnableScissor(mapRect);
|
||||
DrawRadarPings();
|
||||
Game.Renderer.LineRenderer.DrawRect(tl, br, Color.White);
|
||||
Game.Renderer.DisableScissor();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawRadarPings()
|
||||
{
|
||||
if (radarPings == null)
|
||||
return;
|
||||
|
||||
var lr = Game.Renderer.LineRenderer;
|
||||
var oldWidth = lr.LineWidth;
|
||||
lr.LineWidth = 2;
|
||||
|
||||
foreach (var radarPing in radarPings.Pings.Where(e => e.IsVisible()))
|
||||
{
|
||||
var c = radarPing.Color;
|
||||
var pingCell = world.Map.CellContaining(radarPing.Position);
|
||||
var points = radarPing.Points(CellToMinimapPixel(pingCell)).ToArray();
|
||||
|
||||
lr.DrawLine(points[0], points[1], c, c);
|
||||
lr.DrawLine(points[1], points[2], c, c);
|
||||
lr.DrawLine(points[2], points[0], c, c);
|
||||
}
|
||||
|
||||
lr.LineWidth = oldWidth;
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
// Update the radar animation even when its closed
|
||||
// This avoids obviously stale data from being shown when first opened.
|
||||
// TODO: This delayed updating is a giant hack
|
||||
--updateTicks;
|
||||
if (updateTicks <= 0)
|
||||
{
|
||||
updateTicks = 12;
|
||||
using (var bitmap = Minimap.CustomTerrainBitmap(world))
|
||||
customTerrainSprite.sheet.Texture.SetData(bitmap);
|
||||
}
|
||||
|
||||
if (updateTicks == 8)
|
||||
using (var bitmap = Minimap.ActorsBitmap(world))
|
||||
actorSprite.sheet.Texture.SetData(bitmap);
|
||||
|
||||
if (updateTicks == 4)
|
||||
using (var bitmap = Minimap.ShroudBitmap(world))
|
||||
shroudSprite.sheet.Texture.SetData(bitmap);
|
||||
|
||||
// Enable/Disable the radar
|
||||
var enabled = IsEnabled();
|
||||
if (enabled != cachedEnabled)
|
||||
Sound.Play(enabled ? RadarOnlineSound : RadarOfflineSound);
|
||||
cachedEnabled = enabled;
|
||||
|
||||
var targetFrame = enabled ? AnimationLength : 0;
|
||||
hasRadar = enabled && frame == AnimationLength;
|
||||
if (frame == targetFrame)
|
||||
return;
|
||||
|
||||
frame += enabled ? 1 : -1;
|
||||
radarMinimapHeight = float2.Lerp(0, 1, (float)frame / AnimationLength);
|
||||
|
||||
Animating(frame * 1f / AnimationLength);
|
||||
|
||||
// Update map rectangle for event handling
|
||||
var ro = RenderOrigin;
|
||||
mapRect = new Rectangle(previewOrigin.X + ro.X, previewOrigin.Y + ro.Y, mapRect.Width, mapRect.Height);
|
||||
|
||||
// Animation is complete
|
||||
if (frame == targetFrame)
|
||||
{
|
||||
if (enabled)
|
||||
AfterOpen();
|
||||
else
|
||||
AfterClose();
|
||||
}
|
||||
}
|
||||
|
||||
int2 CellToMinimapPixel(CPos p)
|
||||
{
|
||||
var mapOrigin = new CVec(world.Map.Bounds.Left, world.Map.Bounds.Top);
|
||||
var mapOffset = Map.CellToMap(world.Map.TileShape, p) - mapOrigin;
|
||||
|
||||
return new int2(mapRect.X, mapRect.Y) + (previewScale * new float2(mapOffset.X, mapOffset.Y)).ToInt2();
|
||||
}
|
||||
|
||||
CPos MinimapPixelToCell(int2 p)
|
||||
{
|
||||
var viewOrigin = new float2(mapRect.X, mapRect.Y);
|
||||
var mapOrigin = new float2(world.Map.Bounds.Left, world.Map.Bounds.Top);
|
||||
var fcell = mapOrigin + (1f / previewScale) * (p - viewOrigin);
|
||||
return Map.MapToCell(world.Map.TileShape, new CPos((int)fcell.X, (int)fcell.Y));
|
||||
}
|
||||
}
|
||||
}
|
||||
136
OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs
Normal file
136
OpenRA.Mods.Common/Widgets/ResourceBarWidget.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
public enum ResourceBarOrientation { Vertical, Horizontal }
|
||||
public enum ResourceBarStyle { Flat, Bevelled }
|
||||
public class ResourceBarWidget : Widget
|
||||
{
|
||||
public readonly string TooltipTemplate;
|
||||
public readonly string TooltipContainer;
|
||||
Lazy<TooltipContainerWidget> tooltipContainer;
|
||||
|
||||
public string TooltipFormat = "";
|
||||
public ResourceBarOrientation Orientation = ResourceBarOrientation.Vertical;
|
||||
public ResourceBarStyle Style = ResourceBarStyle.Flat;
|
||||
public string IndicatorCollection = "sidebar-bits";
|
||||
public string IndicatorImage = "indicator";
|
||||
|
||||
public Func<float> GetProvided = () => 0;
|
||||
public Func<float> GetUsed = () => 0;
|
||||
public Func<Color> GetBarColor = () => Color.White;
|
||||
EWMA providedLerp = new EWMA(0.3f);
|
||||
EWMA usedLerp = new EWMA(0.3f);
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public ResourceBarWidget(World world)
|
||||
{
|
||||
tooltipContainer = Exts.Lazy(() =>
|
||||
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
|
||||
}
|
||||
|
||||
public override void MouseEntered()
|
||||
{
|
||||
if (TooltipContainer == null)
|
||||
return;
|
||||
|
||||
Func<string> getText = () => TooltipFormat.F(GetUsed(), GetProvided());
|
||||
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() {{ "getText", getText }});
|
||||
}
|
||||
|
||||
public override void MouseExited()
|
||||
{
|
||||
if (TooltipContainer == null)
|
||||
return;
|
||||
tooltipContainer.Value.RemoveTooltip();
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
var scaleBy = 100.0f;
|
||||
var provided = GetProvided();
|
||||
var used = GetUsed();
|
||||
var max = Math.Max(provided, used);
|
||||
while (max >= scaleBy)
|
||||
scaleBy *= 2;
|
||||
|
||||
var providedFrac = providedLerp.Update(provided/scaleBy);
|
||||
var usedFrac = usedLerp.Update(used/scaleBy);
|
||||
|
||||
var b = RenderBounds;
|
||||
var indicator = ChromeProvider.GetImage(IndicatorCollection, IndicatorImage);
|
||||
|
||||
var color = GetBarColor();
|
||||
if (Orientation == ResourceBarOrientation.Vertical)
|
||||
{
|
||||
if (Style == ResourceBarStyle.Bevelled)
|
||||
{
|
||||
var colorDark = Exts.ColorLerp(0.25f, color, Color.Black);
|
||||
for (var i = 0; i < b.Height; i++)
|
||||
{
|
||||
color = (i - 1 < b.Height / 2) ? color : colorDark;
|
||||
var bottom = new float2(b.Left + i, b.Bottom);
|
||||
var top = new float2(b.Left + i, b.Bottom + providedFrac*b.Height);
|
||||
|
||||
// Indent corners
|
||||
if ((i == 0 || i == b.Width - 1) && providedFrac*b.Height > 1)
|
||||
{
|
||||
bottom.Y += 1;
|
||||
top.Y -= 1;
|
||||
}
|
||||
|
||||
Game.Renderer.LineRenderer.DrawLine(bottom, top, color, color);
|
||||
}
|
||||
}
|
||||
else
|
||||
Game.Renderer.LineRenderer.FillRect(new Rectangle(b.X, (int)float2.Lerp(b.Bottom, b.Top, providedFrac),
|
||||
b.Width, (int)(providedFrac*b.Height)), color);
|
||||
|
||||
var x = (b.Left + b.Right - indicator.size.X) / 2;
|
||||
var y = float2.Lerp(b.Bottom, b.Top, usedFrac) - indicator.size.Y / 2;
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, new float2(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Style == ResourceBarStyle.Bevelled)
|
||||
{
|
||||
var colorDark = Exts.ColorLerp(0.25f, color, Color.Black);
|
||||
for (var i = 0; i < b.Height; i++)
|
||||
{
|
||||
color = (i - 1 < b.Height / 2) ? color : colorDark;
|
||||
var left = new float2(b.Left, b.Top + i);
|
||||
var right = new float2(b.Left + providedFrac*b.Width, b.Top + i);
|
||||
|
||||
// Indent corners
|
||||
if ((i == 0 || i == b.Height - 1) && providedFrac*b.Width > 1)
|
||||
{
|
||||
left.X += 1;
|
||||
right.X -= 1;
|
||||
}
|
||||
|
||||
Game.Renderer.LineRenderer.DrawLine(left, right, color, color);
|
||||
}
|
||||
}
|
||||
else
|
||||
Game.Renderer.LineRenderer.FillRect(new Rectangle(b.X, b.Y, (int)(providedFrac*b.Width), b.Height), color);
|
||||
|
||||
var x = float2.Lerp(b.Left, b.Right, usedFrac) - indicator.size.X / 2;
|
||||
var y = (b.Bottom + b.Top - indicator.size.Y) / 2;
|
||||
Game.Renderer.RgbaSpriteRenderer.DrawSprite(indicator, new float2(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
OpenRA.Mods.Common/World/RadarPings.cs
Normal file
113
OpenRA.Mods.Common/World/RadarPings.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common
|
||||
{
|
||||
public class RadarPingsInfo : ITraitInfo
|
||||
{
|
||||
public readonly int FromRadius = 200;
|
||||
public readonly int ToRadius = 15;
|
||||
public readonly int ShrinkSpeed = 4;
|
||||
public readonly float RotationSpeed = 0.12f;
|
||||
|
||||
public object Create(ActorInitializer init) { return new RadarPings(this); }
|
||||
}
|
||||
|
||||
public class RadarPings : ITick
|
||||
{
|
||||
public readonly List<RadarPing> Pings = new List<RadarPing>();
|
||||
readonly RadarPingsInfo info;
|
||||
|
||||
public WPos? LastPingPosition;
|
||||
|
||||
public RadarPings(RadarPingsInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
foreach (var ping in Pings.ToArray())
|
||||
if (!ping.Tick())
|
||||
Pings.Remove(ping);
|
||||
}
|
||||
|
||||
public RadarPing Add(Func<bool> isVisible, WPos position, Color color, int duration)
|
||||
{
|
||||
var ping = new RadarPing(isVisible, position, color, duration,
|
||||
info.FromRadius, info.ToRadius, info.ShrinkSpeed, info.RotationSpeed);
|
||||
|
||||
if (ping.IsVisible())
|
||||
LastPingPosition = ping.Position;
|
||||
|
||||
Pings.Add(ping);
|
||||
|
||||
return ping;
|
||||
}
|
||||
|
||||
public void Remove(RadarPing ping)
|
||||
{
|
||||
Pings.Remove(ping);
|
||||
}
|
||||
}
|
||||
|
||||
public class RadarPing
|
||||
{
|
||||
public Func<bool> IsVisible;
|
||||
public WPos Position;
|
||||
public Color Color;
|
||||
public int Duration;
|
||||
public int FromRadius;
|
||||
public int ToRadius;
|
||||
public int ShrinkSpeed;
|
||||
public float RotationSpeed;
|
||||
|
||||
int radius;
|
||||
float angle;
|
||||
int tick;
|
||||
|
||||
public RadarPing(Func<bool> isVisible, WPos position, Color color, int duration,
|
||||
int fromRadius, int toRadius, int shrinkSpeed, float rotationSpeed)
|
||||
{
|
||||
IsVisible = isVisible;
|
||||
Position = position;
|
||||
Color = color;
|
||||
Duration = duration;
|
||||
FromRadius = fromRadius;
|
||||
ToRadius = toRadius;
|
||||
ShrinkSpeed = shrinkSpeed;
|
||||
RotationSpeed = rotationSpeed;
|
||||
|
||||
radius = fromRadius;
|
||||
}
|
||||
|
||||
public bool Tick()
|
||||
{
|
||||
if (++tick == Duration)
|
||||
return false;
|
||||
|
||||
radius = Math.Max(radius - ShrinkSpeed, ToRadius);
|
||||
angle -= RotationSpeed;
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<float2> Points(float2 center)
|
||||
{
|
||||
yield return center + radius * float2.FromAngle(angle);
|
||||
yield return center + radius * float2.FromAngle((float)(angle + 2 * Math.PI / 3));
|
||||
yield return center + radius * float2.FromAngle((float)(angle + 4 * Math.PI / 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user