Move common widgets from Game to Mods.Common.

This commit is contained in:
Paul Chote
2015-03-07 10:19:11 +00:00
parent eb0ea8d543
commit e5c03413cc
31 changed files with 94 additions and 59 deletions

View File

@@ -590,6 +590,32 @@
<Compile Include="Widgets\Logic\ReplayUtils.cs" />
<Compile Include="InstallUtils.cs" />
<Compile Include="Graphics\DefaultSpriteSequence.cs" />
<Compile Include="Widgets\BackgroundWidget.cs" />
<Compile Include="Widgets\ButtonWidget.cs" />
<Compile Include="Widgets\ChatDisplayWidget.cs" />
<Compile Include="Widgets\CheckboxWidget.cs" />
<Compile Include="Widgets\ClientTooltipRegionWidget.cs" />
<Compile Include="Widgets\ColorBlockWidget.cs" />
<Compile Include="Widgets\DropDownButtonWidget.cs" />
<Compile Include="Widgets\GridLayout.cs" />
<Compile Include="Widgets\HotkeyEntryWidget.cs" />
<Compile Include="Widgets\ImageWidget.cs" />
<Compile Include="Widgets\LabelWidget.cs" />
<Compile Include="Widgets\LineGraphWidget.cs" />
<Compile Include="Widgets\ListLayout.cs" />
<Compile Include="Widgets\MapPreviewWidget.cs" />
<Compile Include="Widgets\PasswordFieldWidget.cs" />
<Compile Include="Widgets\PerfGraphWidget.cs" />
<Compile Include="Widgets\ProgressBarWidget.cs" />
<Compile Include="Widgets\RGBASpriteWidget.cs" />
<Compile Include="Widgets\ScrollItemWidget.cs" />
<Compile Include="Widgets\ScrollPanelWidget.cs" />
<Compile Include="Widgets\SliderWidget.cs" />
<Compile Include="Widgets\SpriteWidget.cs" />
<Compile Include="Widgets\TextFieldWidget.cs" />
<Compile Include="Widgets\TooltipContainerWidget.cs" />
<Compile Include="Widgets\ViewportControllerWidget.cs" />
<Compile Include="Widgets\VqaPlayerWidget.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View File

@@ -11,6 +11,7 @@
using System;
using System.IO;
using OpenRA.FileFormats;
using OpenRA.Mods.Common.Widgets;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Scripting

View File

@@ -0,0 +1,73 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class BackgroundWidget : Widget
{
public readonly string Background = "dialog";
public readonly bool ClickThrough = false;
public readonly bool Draggable = false;
public override void Draw()
{
WidgetUtils.DrawPanel(Background, RenderBounds);
}
public BackgroundWidget() { }
bool moving;
int2? prevMouseLocation;
public override bool HandleMouseInput(MouseInput mi)
{
if (ClickThrough || !RenderBounds.Contains(mi.Location))
return false;
if (!Draggable || (moving && (!TakeMouseFocus(mi) || mi.Button != MouseButton.Left)))
return true;
if (prevMouseLocation == null)
prevMouseLocation = mi.Location;
var vec = mi.Location - (int2)prevMouseLocation;
prevMouseLocation = mi.Location;
switch (mi.Event)
{
case MouseInputEvent.Up:
moving = false;
YieldMouseFocus(mi);
break;
case MouseInputEvent.Down:
moving = true;
Bounds = new Rectangle(Bounds.X + vec.X, Bounds.Y + vec.Y, Bounds.Width, Bounds.Height);
break;
case MouseInputEvent.Move:
if (moving)
Bounds = new Rectangle(Bounds.X + vec.X, Bounds.Y + vec.Y, Bounds.Width, Bounds.Height);
break;
}
return true;
}
protected BackgroundWidget(BackgroundWidget other)
: base(other)
{
Background = other.Background;
ClickThrough = other.ClickThrough;
Draggable = other.Draggable;
}
public override Widget Clone() { return new BackgroundWidget(this); }
}
}

View File

@@ -0,0 +1,253 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class ButtonWidget : Widget
{
public readonly string TooltipContainer;
public readonly string TooltipTemplate = "BUTTON_TOOLTIP";
public Func<ButtonWidget, Hotkey> GetKey = _ => Hotkey.Invalid;
public Hotkey Key
{
get { return GetKey(this); }
set { GetKey = _ => value; }
}
[Translate] public string Text = "";
public string Background = "button";
public bool Depressed = false;
public int VisualHeight = ChromeMetrics.Get<int>("ButtonDepth");
public int BaseLine = 0;
public string Font = ChromeMetrics.Get<string>("ButtonFont");
public Color TextColor = ChromeMetrics.Get<Color>("ButtonTextColor");
public Color TextColorDisabled = ChromeMetrics.Get<Color>("ButtonTextColorDisabled");
public bool Contrast = ChromeMetrics.Get<bool>("ButtonTextContrast");
public Color ContrastColor = ChromeMetrics.Get<Color>("ButtonTextContrastColor");
public bool Disabled = false;
public bool Highlighted = false;
public Func<string> GetText;
public Func<Color> GetColor;
public Func<Color> GetColorDisabled;
public Func<Color> GetContrastColor;
public Func<bool> IsDisabled;
public Func<bool> IsHighlighted;
public Action<MouseInput> OnMouseDown = _ => { };
public Action<MouseInput> OnMouseUp = _ => { };
Lazy<TooltipContainerWidget> tooltipContainer;
[Translate] public string TooltipText;
public Func<string> GetTooltipText;
// Equivalent to OnMouseUp, but without an input arg
public Action OnClick = () => { };
public Action OnDoubleClick = () => { };
public Action<KeyInput> OnKeyPress = _ => { };
protected readonly Ruleset ModRules;
[ObjectCreator.UseCtor]
public ButtonWidget(Ruleset modRules)
{
ModRules = modRules;
GetText = () => Text;
GetColor = () => TextColor;
GetColorDisabled = () => TextColorDisabled;
GetContrastColor = () => ContrastColor;
OnMouseUp = _ => OnClick();
OnKeyPress = _ => OnClick();
IsDisabled = () => Disabled;
IsHighlighted = () => Highlighted;
GetTooltipText = () => TooltipText;
tooltipContainer = Exts.Lazy(() =>
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
}
protected ButtonWidget(ButtonWidget other)
: base(other)
{
ModRules = other.ModRules;
Text = other.Text;
Font = other.Font;
BaseLine = other.BaseLine;
TextColor = other.TextColor;
TextColorDisabled = other.TextColorDisabled;
Contrast = other.Contrast;
ContrastColor = other.ContrastColor;
Depressed = other.Depressed;
Background = other.Background;
VisualHeight = other.VisualHeight;
GetText = other.GetText;
GetColor = other.GetColor;
GetColorDisabled = other.GetColorDisabled;
GetContrastColor = other.GetContrastColor;
OnMouseDown = other.OnMouseDown;
Disabled = other.Disabled;
IsDisabled = other.IsDisabled;
Highlighted = other.Highlighted;
IsHighlighted = other.IsHighlighted;
OnMouseUp = mi => OnClick();
OnKeyPress = _ => OnClick();
TooltipTemplate = other.TooltipTemplate;
TooltipText = other.TooltipText;
GetTooltipText = other.GetTooltipText;
TooltipContainer = other.TooltipContainer;
tooltipContainer = Exts.Lazy(() =>
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
}
public override bool YieldMouseFocus(MouseInput mi)
{
Depressed = false;
return base.YieldMouseFocus(mi);
}
public override bool HandleKeyPress(KeyInput e)
{
if (Hotkey.FromKeyInput(e) != Key || e.Event != KeyInputEvent.Down)
return false;
if (!IsDisabled())
{
OnKeyPress(e);
Sound.PlayNotification(ModRules, null, "Sounds", "ClickSound", null);
}
else
Sound.PlayNotification(ModRules, null, "Sounds", "ClickDisabledSound", null);
return true;
}
public override bool HandleMouseInput(MouseInput mi)
{
if (mi.Button != MouseButton.Left)
return false;
if (mi.Event == MouseInputEvent.Down && !TakeMouseFocus(mi))
return false;
var disabled = IsDisabled();
if (HasMouseFocus && mi.Event == MouseInputEvent.Up && mi.MultiTapCount == 2)
{
if (!disabled)
{
OnDoubleClick();
return YieldMouseFocus(mi);
}
}
else if (HasMouseFocus && mi.Event == MouseInputEvent.Up)
{
// Only fire the onMouseUp event if we successfully lost focus, and were pressed
if (Depressed && !disabled)
OnMouseUp(mi);
return YieldMouseFocus(mi);
}
if (mi.Event == MouseInputEvent.Down)
{
// OnMouseDown returns false if the button shouldn't be pressed
if (!disabled)
{
OnMouseDown(mi);
Depressed = true;
Sound.PlayNotification(ModRules, null, "Sounds", "ClickSound", null);
}
else
{
YieldMouseFocus(mi);
Sound.PlayNotification(ModRules, null, "Sounds", "ClickDisabledSound", null);
}
}
else if (mi.Event == MouseInputEvent.Move && HasMouseFocus)
Depressed = RenderBounds.Contains(mi.Location);
return Depressed;
}
public override void MouseEntered()
{
if (TooltipContainer == null || GetTooltipText() == null)
return;
tooltipContainer.Value.SetTooltip(TooltipTemplate,
new WidgetArgs { { "button", this } });
}
public override void MouseExited()
{
if (TooltipContainer == null || !tooltipContainer.IsValueCreated)
return;
tooltipContainer.Value.RemoveTooltip();
}
public override int2 ChildOrigin
{
get
{
return RenderOrigin +
(Depressed ? new int2(VisualHeight, VisualHeight) : new int2(0, 0));
}
}
public override void Draw()
{
var rb = RenderBounds;
var disabled = IsDisabled();
var highlighted = IsHighlighted();
var font = Game.Renderer.Fonts[Font];
var text = GetText();
var color = GetColor();
var colordisabled = GetColorDisabled();
var contrast = GetContrastColor();
var s = font.Measure(text);
var stateOffset = Depressed ? new int2(VisualHeight, VisualHeight) : new int2(0, 0);
var position = new int2(rb.X + (UsableWidth - s.X) / 2, rb.Y - BaseLine + (Bounds.Height - s.Y) / 2);
DrawBackground(rb, disabled, Depressed, Ui.MouseOverWidget == this, highlighted);
if (Contrast)
font.DrawTextWithContrast(text, position + stateOffset,
disabled ? colordisabled : color, contrast, 2);
else
font.DrawText(text, position + stateOffset,
disabled ? colordisabled : color);
}
public override Widget Clone() { return new ButtonWidget(this); }
public virtual int UsableWidth { get { return Bounds.Width; } }
public virtual void DrawBackground(Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted)
{
DrawBackground(Background, rect, disabled, pressed, hover, highlighted);
}
public static void DrawBackground(string baseName, Rectangle rect, bool disabled, bool pressed, bool hover, bool highlighted)
{
var variant = highlighted ? "-highlighted" : "";
var state = disabled ? "-disabled" :
pressed ? "-pressed" :
hover ? "-hover" :
"";
WidgetUtils.DrawPanel(baseName + variant + state, rect);
}
}
}

View File

@@ -0,0 +1,111 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 System.Linq;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class ChatDisplayWidget : Widget
{
public readonly int RemoveTime = 0;
public readonly bool UseContrast = false;
public string Notification = "";
const int LogLength = 9;
List<ChatLine> recentLines = new List<ChatLine>();
public override Rectangle EventBounds { get { return Rectangle.Empty; } }
public override void Draw()
{
var pos = RenderOrigin;
var chatLogArea = new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height);
var chatpos = new int2(chatLogArea.X + 5, chatLogArea.Bottom - 5);
var font = Game.Renderer.Fonts["Regular"];
Game.Renderer.EnableScissor(chatLogArea);
foreach (var line in recentLines.AsEnumerable().Reverse())
{
var inset = 0;
string owner = null;
if (!string.IsNullOrEmpty(line.Owner))
{
owner = line.Owner + ":";
inset = font.Measure(owner).X + 5;
}
var text = WidgetUtils.WrapText(line.Text, chatLogArea.Width - inset - 6, font);
chatpos = chatpos.WithY(chatpos.Y - (Math.Max(15, font.Measure(text).Y) + 5));
if (chatpos.Y < pos.Y)
break;
if (owner != null)
{
font.DrawTextWithContrast(owner, chatpos,
line.Color, Color.Black, UseContrast ? 1 : 0);
}
font.DrawTextWithContrast(text, chatpos + new int2(inset, 0),
Color.White, Color.Black, UseContrast ? 1 : 0);
}
Game.Renderer.DisableScissor();
}
public void AddLine(Color c, string from, string text)
{
recentLines.Add(new ChatLine(from, text, Game.LocalTick + RemoveTime, c));
if (Notification != null)
Sound.Play(Notification);
while (recentLines.Count > LogLength)
recentLines.RemoveAt(0);
}
public void RemoveLine()
{
if (recentLines.Count > 0)
recentLines.RemoveAt(0);
}
public override void Tick()
{
if (RemoveTime == 0)
return;
// This takes advantage of the fact that recentLines is ordered by expiration, from sooner to later
while (recentLines.Count > 0 && Game.LocalTick >= recentLines[0].Expiration)
recentLines.RemoveAt(0);
}
}
class ChatLine
{
public readonly Color Color;
public readonly string Owner, Text;
public readonly int Expiration;
public ChatLine(string owner, string text, int expiration, Color color)
{
Owner = owner;
Text = text;
Expiration = expiration;
Color = color;
}
}
}

View File

@@ -0,0 +1,84 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 class CheckboxWidget : ButtonWidget
{
public string CheckType = "checked";
public Func<string> GetCheckType;
public Func<bool> IsChecked = () => false;
public int CheckOffset = 2;
public bool HasPressedState = ChromeMetrics.Get<bool>("CheckboxPressedState");
[ObjectCreator.UseCtor]
public CheckboxWidget(Ruleset modRules)
: base(modRules)
{
GetCheckType = () => CheckType;
}
protected CheckboxWidget(CheckboxWidget other)
: base(other)
{
CheckType = other.CheckType;
GetCheckType = other.GetCheckType;
IsChecked = other.IsChecked;
CheckOffset = other.CheckOffset;
HasPressedState = other.HasPressedState;
}
public override void Draw()
{
var disabled = IsDisabled();
var highlighted = IsHighlighted();
var font = Game.Renderer.Fonts[Font];
var color = GetColor();
var colordisabled = GetColorDisabled();
var contrast = GetContrastColor();
var rect = RenderBounds;
var text = GetText();
var textSize = font.Measure(text);
var check = new Rectangle(rect.Location, new Size(Bounds.Height, Bounds.Height));
var state = disabled ? "checkbox-disabled" :
highlighted ? "checkbox-highlighted" :
Depressed && HasPressedState ? "checkbox-pressed" :
Ui.MouseOverWidget == this ? "checkbox-hover" :
"checkbox";
WidgetUtils.DrawPanel(state, check);
var position = new float2(rect.Left + rect.Height * 1.5f, RenderOrigin.Y - BaseLine + (Bounds.Height - textSize.Y) / 2);
if (Contrast)
font.DrawTextWithContrast(text, position,
disabled ? colordisabled : color, contrast, 2);
else
font.DrawText(text, position,
disabled ? colordisabled : color);
if (IsChecked() || (Depressed && HasPressedState && !disabled))
{
var checkType = GetCheckType();
if (HasPressedState && (Depressed || disabled))
checkType += "-disabled";
var offset = new float2(rect.Left + CheckOffset, rect.Top + CheckOffset);
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("checkbox-bits", checkType), offset);
}
}
public override Widget Clone() { return new CheckboxWidget(this); }
}
}

View File

@@ -0,0 +1,62 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Network;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class ClientTooltipRegionWidget : Widget
{
public readonly string Template;
public readonly string TooltipContainer;
Lazy<TooltipContainerWidget> tooltipContainer;
OrderManager orderManager;
int clientIndex;
public ClientTooltipRegionWidget()
{
tooltipContainer = Exts.Lazy(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
}
protected ClientTooltipRegionWidget(ClientTooltipRegionWidget other)
: base(other)
{
Template = other.Template;
TooltipContainer = other.TooltipContainer;
tooltipContainer = Exts.Lazy(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
orderManager = other.orderManager;
clientIndex = other.clientIndex;
}
public override Widget Clone() { return new ClientTooltipRegionWidget(this); }
public void Bind(OrderManager orderManager, int clientIndex)
{
this.orderManager = orderManager;
this.clientIndex = clientIndex;
}
public override void MouseEntered()
{
if (TooltipContainer == null)
return;
tooltipContainer.Value.SetTooltip(Template, new WidgetArgs() { { "orderManager", orderManager }, { "clientIndex", clientIndex } });
}
public override void MouseExited()
{
if (TooltipContainer == null)
return;
tooltipContainer.Value.RemoveTooltip();
}
}
}

View File

@@ -0,0 +1,42 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class ColorBlockWidget : Widget
{
public Func<Color> GetColor;
public ColorBlockWidget()
{
GetColor = () => Color.White;
}
protected ColorBlockWidget(ColorBlockWidget widget)
: base(widget)
{
GetColor = widget.GetColor;
}
public override Widget Clone()
{
return new ColorBlockWidget(this);
}
public override void Draw()
{
WidgetUtils.FillRectWithColor(RenderBounds, GetColor());
}
}
}

View File

@@ -0,0 +1,184 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Graphics;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class DropDownButtonWidget : ButtonWidget
{
Widget panel;
MaskWidget fullscreenMask;
Widget panelRoot;
public string PanelRoot;
[ObjectCreator.UseCtor]
public DropDownButtonWidget(Ruleset modRules)
: base(modRules) { }
protected DropDownButtonWidget(DropDownButtonWidget widget)
: base(widget)
{
PanelRoot = widget.PanelRoot;
}
public override void Draw()
{
base.Draw();
var stateOffset = Depressed ? new int2(VisualHeight, VisualHeight) : new int2(0, 0);
var image = ChromeProvider.GetImage("scrollbar", IsDisabled() ? "down_pressed" : "down_arrow");
var rb = RenderBounds;
var color = GetColor();
var colorDisabled = GetColorDisabled();
WidgetUtils.DrawRGBA(image, stateOffset + new float2(rb.Right - rb.Height + 4, rb.Top + (rb.Height - image.Bounds.Height) / 2));
WidgetUtils.FillRectWithColor(new Rectangle(stateOffset.X + rb.Right - rb.Height,
stateOffset.Y + rb.Top + 3, 1, rb.Height - 6),
IsDisabled() ? colorDisabled : color);
}
public override Widget Clone() { return new DropDownButtonWidget(this); }
// This is crap
public override int UsableWidth { get { return Bounds.Width - Bounds.Height; } } /* space for button */
public override void Removed()
{
base.Removed();
RemovePanel();
}
public void RemovePanel()
{
if (panel == null)
return;
panelRoot.RemoveChild(fullscreenMask);
panelRoot.RemoveChild(panel);
panel = fullscreenMask = null;
}
public void AttachPanel(Widget p) { AttachPanel(p, null); }
public void AttachPanel(Widget p, Action onCancel)
{
if (panel != null)
throw new InvalidOperationException("Attempted to attach a panel to an open dropdown");
panel = p;
// Mask to prevent any clicks from being sent to other widgets
fullscreenMask = new MaskWidget();
fullscreenMask.Bounds = new Rectangle(0, 0, Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height);
fullscreenMask.OnMouseDown += mi => { Sound.PlayNotification(this.ModRules, null, "Sounds", "ClickSound", null); RemovePanel(); };
if (onCancel != null)
fullscreenMask.OnMouseDown += _ => onCancel();
panelRoot = PanelRoot == null ? Ui.Root : Ui.Root.Get(PanelRoot);
panelRoot.AddChild(fullscreenMask);
var oldBounds = panel.Bounds;
panel.Bounds = new Rectangle(
RenderOrigin.X - panelRoot.RenderOrigin.X,
RenderOrigin.Y + Bounds.Height - panelRoot.RenderOrigin.Y,
oldBounds.Width,
oldBounds.Height);
panelRoot.AddChild(panel);
}
public void ShowDropDown<T>(string panelTemplate, int maxHeight, IEnumerable<T> options, Func<T, ScrollItemWidget, ScrollItemWidget> setupItem)
{
var substitutions = new Dictionary<string, int>() { { "DROPDOWN_WIDTH", Bounds.Width } };
var panel = (ScrollPanelWidget)Ui.LoadWidget(panelTemplate, null, new WidgetArgs() { { "substitutions", substitutions } });
var itemTemplate = panel.Get<ScrollItemWidget>("TEMPLATE");
panel.RemoveChildren();
foreach (var option in options)
{
var o = option;
var item = setupItem(o, itemTemplate);
var onClick = item.OnClick;
item.OnClick = () => { onClick(); RemovePanel(); };
panel.AddChild(item);
}
panel.Bounds.Height = Math.Min(maxHeight, panel.ContentHeight);
AttachPanel(panel);
}
public void ShowDropDown<T>(string panelTemplate, int height, Dictionary<string, IEnumerable<T>> groups, Func<T, ScrollItemWidget, ScrollItemWidget> setupItem)
{
var substitutions = new Dictionary<string, int>() { { "DROPDOWN_WIDTH", Bounds.Width } };
var panel = (ScrollPanelWidget)Ui.LoadWidget(panelTemplate, null, new WidgetArgs() { { "substitutions", substitutions } });
var headerTemplate = panel.GetOrNull<ScrollItemWidget>("HEADER");
var itemTemplate = panel.Get<ScrollItemWidget>("TEMPLATE");
panel.RemoveChildren();
foreach (var kv in groups)
{
var group = kv.Key;
if (group.Length > 0 && headerTemplate != null)
{
var header = ScrollItemWidget.Setup(headerTemplate, () => true, () => { });
header.Get<LabelWidget>("LABEL").GetText = () => group;
panel.AddChild(header);
}
foreach (var option in kv.Value)
{
var o = option;
var item = setupItem(o, itemTemplate);
var onClick = item.OnClick;
item.OnClick = () => { onClick(); RemovePanel(); };
panel.AddChild(item);
}
}
panel.Bounds.Height = Math.Min(height, panel.ContentHeight);
AttachPanel(panel);
}
}
public class MaskWidget : Widget
{
public event Action<MouseInput> OnMouseDown = _ => { };
public MaskWidget() { }
public MaskWidget(MaskWidget other)
: base(other)
{
OnMouseDown = other.OnMouseDown;
}
public override bool HandleMouseInput(MouseInput mi)
{
if (mi.Event != MouseInputEvent.Down && mi.Event != MouseInputEvent.Up)
return false;
if (mi.Event == MouseInputEvent.Down)
OnMouseDown(mi);
return true;
}
public override string GetCursor(int2 pos) { return null; }
public override Widget Clone() { return new MaskWidget(this); }
}
}

View File

@@ -0,0 +1,49 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 GridLayout : ILayout
{
ScrollPanelWidget widget;
int2 pos;
public GridLayout(ScrollPanelWidget w) { widget = w; }
public void AdjustChild(Widget w)
{
if (widget.Children.Count == 0)
{
widget.ContentHeight = widget.ItemSpacing;
pos = new int2(widget.ItemSpacing, widget.ItemSpacing);
}
if (pos.X + widget.ItemSpacing + w.Bounds.Width > widget.Bounds.Width - widget.ScrollbarWidth)
{
/* start a new row */
pos = new int2(widget.ItemSpacing, widget.ContentHeight);
}
w.Bounds.X += pos.X;
w.Bounds.Y += pos.Y;
pos = pos.WithX(pos.X + w.Bounds.Width + widget.ItemSpacing);
widget.ContentHeight = Math.Max(widget.ContentHeight, pos.Y + widget.ItemSpacing + w.Bounds.Height);
}
public void AdjustChildren()
{
}
}
}

View File

@@ -0,0 +1,139 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class HotkeyEntryWidget : Widget
{
public Hotkey Key;
public int VisualHeight = 1;
public int LeftMargin = 5;
public int RightMargin = 5;
public Action OnLoseFocus = () => { };
public Func<bool> IsDisabled = () => false;
public string Font = ChromeMetrics.Get<string>("HotkeyFont");
public Color TextColor = ChromeMetrics.Get<Color>("HotkeyColor");
public Color TextColorDisabled = ChromeMetrics.Get<Color>("HotkeyColorDisabled");
public HotkeyEntryWidget() { }
protected HotkeyEntryWidget(HotkeyEntryWidget widget)
: base(widget)
{
Font = widget.Font;
TextColor = widget.TextColor;
TextColorDisabled = widget.TextColorDisabled;
VisualHeight = widget.VisualHeight;
}
public override bool YieldKeyboardFocus()
{
OnLoseFocus();
return base.YieldKeyboardFocus();
}
public override bool HandleMouseInput(MouseInput mi)
{
if (IsDisabled())
return false;
if (mi.Event != MouseInputEvent.Down)
return false;
// Attempt to take keyboard focus
if (!RenderBounds.Contains(mi.Location) || !TakeKeyboardFocus())
return false;
blinkCycle = 15;
return true;
}
static readonly Keycode[] IgnoreKeys = new Keycode[]
{
Keycode.RSHIFT, Keycode.LSHIFT,
Keycode.RCTRL, Keycode.LCTRL,
Keycode.RALT, Keycode.LALT,
Keycode.RGUI, Keycode.LGUI
};
public override bool HandleKeyPress(KeyInput e)
{
if (IsDisabled() || e.Event == KeyInputEvent.Up)
return false;
if (!HasKeyboardFocus || IgnoreKeys.Contains(e.Key))
return false;
Key = Hotkey.FromKeyInput(e);
return true;
}
protected int blinkCycle = 15;
protected bool showEntry = true;
public override void Tick()
{
if (HasKeyboardFocus && --blinkCycle <= 0)
{
blinkCycle = 15;
showEntry ^= true;
}
}
public override void Draw()
{
var apparentText = Key.DisplayString();
var font = Game.Renderer.Fonts[Font];
var pos = RenderOrigin;
var textSize = font.Measure(apparentText);
var disabled = IsDisabled();
var state = disabled ? "textfield-disabled" :
HasKeyboardFocus ? "textfield-focused" :
Ui.MouseOverWidget == this ? "textfield-hover" :
"textfield";
WidgetUtils.DrawPanel(state, RenderBounds);
// Blink the current entry to indicate focus
if (HasKeyboardFocus && !showEntry)
return;
// Inset text by the margin and center vertically
var textPos = pos + new int2(LeftMargin, (Bounds.Height - textSize.Y) / 2 - VisualHeight);
// Scissor when the text overflows
if (textSize.X > Bounds.Width - LeftMargin - RightMargin)
{
Game.Renderer.EnableScissor(new Rectangle(pos.X + LeftMargin, pos.Y,
Bounds.Width - LeftMargin - RightMargin, Bounds.Bottom));
}
var color = disabled ? TextColorDisabled : TextColor;
font.DrawText(apparentText, textPos, color);
if (textSize.X > Bounds.Width - LeftMargin - RightMargin)
Game.Renderer.DisableScissor();
}
public override Widget Clone() { return new HotkeyEntryWidget(this); }
}
}

View File

@@ -0,0 +1,60 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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
{
public class ImageWidget : Widget
{
public string ImageCollection = "";
public string ImageName = "";
public bool ClickThrough = true;
public Func<string> GetImageName;
public Func<string> GetImageCollection;
public ImageWidget()
{
GetImageName = () => ImageName;
GetImageCollection = () => ImageCollection;
}
protected ImageWidget(ImageWidget other)
: base(other)
{
ClickThrough = other.ClickThrough;
ImageName = other.ImageName;
GetImageName = other.GetImageName;
ImageCollection = other.ImageCollection;
GetImageCollection = other.GetImageCollection;
}
public override Widget Clone() { return new ImageWidget(this); }
public override void Draw()
{
var name = GetImageName();
var collection = GetImageCollection();
var sprite = ChromeProvider.GetImage(collection, name);
if (sprite == null)
throw new ArgumentException("Sprite {0}/{1} was not found.".F(collection, name));
WidgetUtils.DrawRGBA(sprite, RenderOrigin);
}
public override bool HandleMouseInput(MouseInput mi)
{
return !ClickThrough && RenderBounds.Contains(mi.Location);
}
}
}

View File

@@ -0,0 +1,95 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 TextAlign { Left, Center, Right }
public enum TextVAlign { Top, Middle, Bottom }
public class LabelWidget : Widget
{
[Translate] public string Text = null;
public TextAlign Align = TextAlign.Left;
public TextVAlign VAlign = TextVAlign.Middle;
public string Font = ChromeMetrics.Get<string>("TextFont");
public Color TextColor = ChromeMetrics.Get<Color>("TextColor");
public bool Contrast = ChromeMetrics.Get<bool>("TextContrast");
public Color ContrastColor = ChromeMetrics.Get<Color>("TextContrastColor");
public bool WordWrap = false;
public Func<string> GetText;
public Func<Color> GetColor;
public Func<Color> GetContrastColor;
public LabelWidget()
{
GetText = () => Text;
GetColor = () => TextColor;
GetContrastColor = () => ContrastColor;
}
protected LabelWidget(LabelWidget other)
: base(other)
{
Text = other.Text;
Align = other.Align;
Font = other.Font;
TextColor = other.TextColor;
Contrast = other.Contrast;
ContrastColor = other.ContrastColor;
WordWrap = other.WordWrap;
GetText = other.GetText;
GetColor = other.GetColor;
GetContrastColor = other.GetContrastColor;
}
public override void Draw()
{
SpriteFont font;
if (!Game.Renderer.Fonts.TryGetValue(Font, out font))
throw new ArgumentException("Requested font '{0}' was not found.".F(Font));
var text = GetText();
if (text == null)
return;
var textSize = font.Measure(text);
var position = RenderOrigin;
if (VAlign == TextVAlign.Middle)
position += new int2(0, (Bounds.Height - textSize.Y) / 2);
if (VAlign == TextVAlign.Bottom)
position += new int2(0, Bounds.Height - textSize.Y);
if (Align == TextAlign.Center)
position += new int2((Bounds.Width - textSize.X) / 2, 0);
if (Align == TextAlign.Right)
position += new int2(Bounds.Width - textSize.X, 0);
if (WordWrap)
text = WidgetUtils.WrapText(text, Bounds.Width, font);
var color = GetColor();
var contrast = GetContrastColor();
if (Contrast)
font.DrawTextWithContrast(text, position, color, contrast, 2);
else
font.DrawText(text, position, color);
}
public override Widget Clone() { return new LabelWidget(this); }
}
}

View File

@@ -0,0 +1,185 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 System.Linq;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class LineGraphWidget : Widget
{
public Func<IEnumerable<LineGraphSeries>> GetSeries;
public Func<string> GetValueFormat;
public Func<string> GetXAxisValueFormat;
public Func<string> GetYAxisValueFormat;
public Func<int> GetXAxisSize;
public Func<int> GetYAxisSize;
public Func<string> GetXAxisLabel;
public Func<string> GetYAxisLabel;
public Func<bool> GetDisplayFirstYAxisValue;
public Func<string> GetLabelFont;
public Func<string> GetAxisFont;
public string ValueFormat = "{0}";
public string XAxisValueFormat = "{0}";
public string YAxisValueFormat = "{0}";
public int XAxisSize = 10;
public int YAxisSize = 10;
public string XAxisLabel = "";
public string YAxisLabel = "";
public bool DisplayFirstYAxisValue = false;
public string LabelFont;
public string AxisFont;
public LineGraphWidget()
{
GetValueFormat = () => ValueFormat;
GetXAxisValueFormat = () => XAxisValueFormat;
GetYAxisValueFormat = () => YAxisValueFormat;
GetXAxisSize = () => XAxisSize;
GetYAxisSize = () => YAxisSize;
GetXAxisLabel = () => XAxisLabel;
GetYAxisLabel = () => YAxisLabel;
GetDisplayFirstYAxisValue = () => DisplayFirstYAxisValue;
GetLabelFont = () => LabelFont;
GetAxisFont = () => AxisFont;
}
protected LineGraphWidget(LineGraphWidget other)
: base(other)
{
GetSeries = other.GetSeries;
GetValueFormat = other.GetValueFormat;
GetXAxisValueFormat = other.GetXAxisValueFormat;
GetYAxisValueFormat = other.GetYAxisValueFormat;
GetXAxisSize = other.GetXAxisSize;
GetYAxisSize = other.GetYAxisSize;
GetXAxisLabel = other.GetXAxisLabel;
GetYAxisLabel = other.GetYAxisLabel;
GetDisplayFirstYAxisValue = other.GetDisplayFirstYAxisValue;
GetLabelFont = other.GetLabelFont;
GetAxisFont = other.GetAxisFont;
ValueFormat = other.ValueFormat;
XAxisValueFormat = other.XAxisValueFormat;
YAxisValueFormat = other.YAxisValueFormat;
XAxisSize = other.XAxisSize;
YAxisSize = other.YAxisSize;
XAxisLabel = other.XAxisLabel;
YAxisLabel = other.YAxisLabel;
DisplayFirstYAxisValue = other.DisplayFirstYAxisValue;
LabelFont = other.LabelFont;
AxisFont = other.AxisFont;
}
public override void Draw()
{
if (GetSeries == null || !GetSeries().Any()
|| GetLabelFont == null || GetLabelFont() == null
|| GetAxisFont == null || GetAxisFont() == null)
return;
var rect = RenderBounds;
var origin = new float2(rect.Left, rect.Bottom);
var width = rect.Width;
var height = rect.Height;
var tiny = Game.Renderer.Fonts[GetLabelFont()];
var bold = Game.Renderer.Fonts[GetAxisFont()];
var xAxisSize = GetXAxisSize();
var yAxisSize = GetYAxisSize();
var maxValue = GetSeries().Select(p => p.Points).SelectMany(d => d).Concat(new[] { 0f }).Max();
var scale = 200 / Math.Max(5000, (float)Math.Ceiling(maxValue / 1000) * 1000);
var xStep = width / xAxisSize;
var yStep = height / yAxisSize;
var pointCount = GetSeries().First().Points.Count();
var pointStart = Math.Max(0, pointCount - xAxisSize);
var pointEnd = Math.Max(pointCount, xAxisSize);
var keyOffset = 0;
foreach (var series in GetSeries())
{
var key = series.Key;
var color = series.Color;
var points = series.Points;
if (points.Any())
{
points = points.Reverse().Take(xAxisSize).Reverse();
var scaledData = points.Select(d => d * scale);
var x = 0;
scaledData.Aggregate((a, b) =>
{
Game.Renderer.LineRenderer.DrawLine(
origin + new float2(x, -a),
origin + new float2(x + xStep, -b),
color, color);
x += xStep;
return b;
});
var value = points.Last();
if (value != 0)
tiny.DrawText(GetValueFormat().F(value), origin + new float2(x, -value * scale - 2), color);
}
tiny.DrawText(key, new float2(rect.Left, rect.Top) + new float2(5, 10 * keyOffset + 3), color);
keyOffset++;
}
// TODO: make this stuff not draw outside of the RenderBounds
for (int n = pointStart, x = 0; n <= pointEnd; n++, x += xStep)
{
Game.Renderer.LineRenderer.DrawLine(origin + new float2(x, 0), origin + new float2(x, -5), Color.White, Color.White);
tiny.DrawText(GetXAxisValueFormat().F(n), origin + new float2(x, 2), Color.White);
}
bold.DrawText(GetXAxisLabel(), origin + new float2(width / 2, 20), Color.White);
for (var y = GetDisplayFirstYAxisValue() ? 0 : yStep; y <= height; y += yStep)
{
var yValue = y / scale;
Game.Renderer.LineRenderer.DrawLine(origin + new float2(width - 5, -y), origin + new float2(width, -y), Color.White, Color.White);
tiny.DrawText(GetYAxisValueFormat().F(yValue), origin + new float2(width + 2, -y), Color.White);
}
bold.DrawText(GetYAxisLabel(), origin + new float2(width + 40, -(height / 2)), Color.White);
Game.Renderer.LineRenderer.DrawLine(origin, origin + new float2(width, 0), Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(origin, origin + new float2(0, -height), Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(origin + new float2(width, 0), origin + new float2(width, -height), Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(origin + new float2(0, -height), origin + new float2(width, -height), Color.White, Color.White);
}
public override Widget Clone()
{
return new LineGraphWidget(this);
}
}
public class LineGraphSeries
{
public string Key;
public Color Color;
public IEnumerable<float> Points;
public LineGraphSeries(string key, Color color, IEnumerable<float> points)
{
Key = key;
Color = color;
Points = points;
}
}
}

View File

@@ -0,0 +1,42 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 ListLayout : ILayout
{
ScrollPanelWidget widget;
public ListLayout(ScrollPanelWidget w) { widget = w; }
public void AdjustChild(Widget w)
{
if (widget.Children.Count == 0)
widget.ContentHeight = widget.ItemSpacing;
w.Bounds.Y = widget.ContentHeight;
if (!widget.CollapseHiddenChildren || w.IsVisible())
widget.ContentHeight += w.Bounds.Height + widget.ItemSpacing;
}
public void AdjustChildren()
{
widget.ContentHeight = widget.ItemSpacing;
foreach (var w in widget.Children)
{
w.Bounds.Y = widget.ContentHeight;
if (!widget.CollapseHiddenChildren || w.IsVisible())
widget.ContentHeight += w.Bounds.Height + widget.ItemSpacing;
}
}
}
}

View File

@@ -0,0 +1,195 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 System.Linq;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class SpawnOccupant
{
public readonly HSLColor Color;
public readonly int ClientIndex;
public readonly string PlayerName;
public readonly int Team;
public readonly string Country;
public readonly int SpawnPoint;
public SpawnOccupant(Session.Client client)
{
Color = client.Color;
ClientIndex = client.Index;
PlayerName = client.Name;
Team = client.Team;
Country = client.Race;
SpawnPoint = client.SpawnPoint;
}
public SpawnOccupant(GameInformation.Player player)
{
Color = player.Color;
ClientIndex = player.ClientIndex;
PlayerName = player.Name;
Team = player.Team;
Country = player.FactionId;
SpawnPoint = player.SpawnPoint;
}
}
public class MapPreviewWidget : Widget
{
public readonly bool IgnoreMouseInput = false;
public readonly bool ShowSpawnPoints = true;
public readonly string TooltipContainer;
public readonly string TooltipTemplate = "SPAWN_TOOLTIP";
readonly Lazy<TooltipContainerWidget> tooltipContainer;
readonly Sprite spawnClaimed, spawnUnclaimed;
readonly SpriteFont spawnFont;
readonly Color spawnColor, spawnContrastColor;
readonly int2 spawnLabelOffset;
public Func<MapPreview> Preview = () => null;
public Func<Dictionary<CPos, SpawnOccupant>> SpawnOccupants = () => new Dictionary<CPos, SpawnOccupant>();
public Action<MouseInput> OnMouseDown = _ => { };
public int TooltipSpawnIndex = -1;
Rectangle mapRect;
float previewScale = 0;
Sprite minimap;
public MapPreviewWidget()
{
tooltipContainer = Exts.Lazy(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
spawnClaimed = ChromeProvider.GetImage("lobby-bits", "spawn-claimed");
spawnUnclaimed = ChromeProvider.GetImage("lobby-bits", "spawn-unclaimed");
spawnFont = Game.Renderer.Fonts[ChromeMetrics.Get<string>("SpawnFont")];
spawnColor = ChromeMetrics.Get<Color>("SpawnColor");
spawnContrastColor = ChromeMetrics.Get<Color>("SpawnContrastColor");
spawnLabelOffset = ChromeMetrics.Get<int2>("SpawnLabelOffset");
}
protected MapPreviewWidget(MapPreviewWidget other)
: base(other)
{
Preview = other.Preview;
IgnoreMouseInput = other.IgnoreMouseInput;
ShowSpawnPoints = other.ShowSpawnPoints;
TooltipTemplate = other.TooltipTemplate;
TooltipContainer = other.TooltipContainer;
SpawnOccupants = other.SpawnOccupants;
tooltipContainer = Exts.Lazy(() => Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
spawnClaimed = ChromeProvider.GetImage("lobby-bits", "spawn-claimed");
spawnUnclaimed = ChromeProvider.GetImage("lobby-bits", "spawn-unclaimed");
spawnFont = Game.Renderer.Fonts[ChromeMetrics.Get<string>("SpawnFont")];
spawnColor = ChromeMetrics.Get<Color>("SpawnColor");
spawnContrastColor = ChromeMetrics.Get<Color>("SpawnContrastColor");
spawnLabelOffset = ChromeMetrics.Get<int2>("SpawnLabelOffset");
}
public override Widget Clone() { return new MapPreviewWidget(this); }
public override bool HandleMouseInput(MouseInput mi)
{
if (IgnoreMouseInput)
return base.HandleMouseInput(mi);
if (mi.Event != MouseInputEvent.Down)
return false;
OnMouseDown(mi);
return true;
}
public override void MouseEntered()
{
if (TooltipContainer != null)
tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() { { "preview", this } });
}
public override void MouseExited()
{
if (TooltipContainer != null)
tooltipContainer.Value.RemoveTooltip();
}
public int2 ConvertToPreview(CPos cell)
{
var preview = Preview();
var tileShape = Game.ModData.Manifest.TileShape;
var point = cell.ToMPos(tileShape);
var dx = (int)(previewScale * (point.U - preview.Bounds.Left));
var dy = (int)(previewScale * (point.V - preview.Bounds.Top));
return new int2(mapRect.X + dx, mapRect.Y + dy);
}
public override void Draw()
{
var preview = Preview();
if (preview == null)
return;
// Stash a copy of the minimap to ensure consistency
// (it may be modified by another thread)
minimap = preview.GetMinimap();
if (minimap == null)
return;
// Update map rect
previewScale = Math.Min(RenderBounds.Width / minimap.Size.X, RenderBounds.Height / minimap.Size.Y);
var w = (int)(previewScale * minimap.Size.X);
var h = (int)(previewScale * minimap.Size.Y);
var x = RenderBounds.X + (RenderBounds.Width - w) / 2;
var y = RenderBounds.Y + (RenderBounds.Height - h) / 2;
mapRect = new Rectangle(x, y, w, h);
Game.Renderer.RgbaSpriteRenderer.DrawSprite(minimap, new float2(mapRect.Location), new float2(mapRect.Size));
TooltipSpawnIndex = -1;
if (ShowSpawnPoints)
{
var colors = SpawnOccupants().ToDictionary(c => c.Key, c => c.Value.Color.RGB);
var spawnPoints = preview.SpawnPoints;
foreach (var p in spawnPoints)
{
var owned = colors.ContainsKey(p);
var pos = ConvertToPreview(p);
var sprite = owned ? spawnClaimed : spawnUnclaimed;
var offset = new int2(sprite.Bounds.Width, sprite.Bounds.Height) / 2;
if (owned)
WidgetUtils.FillEllipseWithColor(new Rectangle(pos.X - offset.X + 1, pos.Y - offset.Y + 1, sprite.Bounds.Width - 2, sprite.Bounds.Height - 2), colors[p]);
Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, pos - offset);
var number = Convert.ToChar('A' + spawnPoints.IndexOf(p)).ToString();
var textOffset = spawnFont.Measure(number) / 2 + spawnLabelOffset;
spawnFont.DrawTextWithContrast(number, pos - textOffset, spawnColor, spawnContrastColor, 1);
if (((pos - Viewport.LastMousePos).ToFloat2() / offset.ToFloat2()).LengthSquared <= 1)
TooltipSpawnIndex = spawnPoints.IndexOf(p) + 1;
}
}
}
public bool Loaded { get { return minimap != null; } }
}
}

View File

@@ -0,0 +1,23 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 PasswordFieldWidget : TextFieldWidget
{
public PasswordFieldWidget() { }
protected PasswordFieldWidget(PasswordFieldWidget widget) : base(widget) { }
protected override string GetApparentText() { return new string('*', Text.Length); }
public override Widget Clone() { return new PasswordFieldWidget(this); }
}
}

View File

@@ -0,0 +1,66 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Support;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class PerfGraphWidget : Widget
{
public override void Draw()
{
var rect = RenderBounds;
var origin = new float2(rect.Right, rect.Bottom);
var basis = new float2(-rect.Width / 100, -rect.Height / 100);
Game.Renderer.LineRenderer.DrawLine(origin, origin + new float2(100, 0) * basis, Color.White, Color.White);
Game.Renderer.LineRenderer.DrawLine(origin + new float2(100, 0) * basis, origin + new float2(100, 100) * basis, Color.White, Color.White);
var k = 0;
foreach (var item in PerfHistory.Items.Values)
{
var n = 0;
item.Samples().Aggregate((a, b) =>
{
Game.Renderer.LineRenderer.DrawLine(
origin + new float2(n, (float)a) * basis,
origin + new float2(n + 1, (float)b) * basis,
item.C, item.C);
++n;
return b;
});
var u = new float2(rect.Left, rect.Top);
Game.Renderer.LineRenderer.DrawLine(
u + new float2(10, 10 * k + 5),
u + new float2(12, 10 * k + 5),
item.C, item.C);
Game.Renderer.LineRenderer.DrawLine(
u + new float2(10, 10 * k + 4),
u + new float2(12, 10 * k + 4),
item.C, item.C);
++k;
}
k = 0;
foreach (var item in PerfHistory.Items.Values)
{
Game.Renderer.Fonts["Tiny"].DrawText(item.Name, new float2(rect.Left, rect.Top) + new float2(18, 10 * k - 3), Color.White);
++k;
}
}
}
}

View File

@@ -0,0 +1,77 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class ProgressBarWidget : Widget
{
public int Percentage = 0;
public bool Indeterminate = false;
public Func<int> GetPercentage;
public Func<bool> IsIndeterminate;
// Indeterminant bar properties
float offset = 0f;
float tickStep = 0.04f;
public ProgressBarWidget()
{
GetPercentage = () => Percentage;
IsIndeterminate = () => Indeterminate;
}
protected ProgressBarWidget(ProgressBarWidget other)
: base(other)
{
Percentage = other.Percentage;
GetPercentage = other.GetPercentage;
IsIndeterminate = other.IsIndeterminate;
}
public override void Draw()
{
var rb = RenderBounds;
var percentage = GetPercentage();
WidgetUtils.DrawPanel("progressbar-bg", rb);
var barRect = wasIndeterminate ?
new Rectangle(rb.X + 2 + (int)(0.75 * offset * (rb.Width - 4)), rb.Y + 2, (rb.Width - 4) / 4, rb.Height - 4) :
new Rectangle(rb.X + 2, rb.Y + 2, percentage * (rb.Width - 4) / 100, rb.Height - 4);
if (barRect.Width > 0)
WidgetUtils.DrawPanel("progressbar-thumb", barRect);
}
bool wasIndeterminate;
public override void Tick()
{
var indeterminate = IsIndeterminate();
if (indeterminate != wasIndeterminate)
offset = 0f;
if (indeterminate)
{
offset += tickStep;
offset = offset.Clamp(0f, 1f);
if (offset == 0f || offset == 1f)
tickStep *= -1;
}
wasIndeterminate = indeterminate;
}
public override Widget Clone() { return new ProgressBarWidget(this); }
}
}

View File

@@ -0,0 +1,38 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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
{
public class RGBASpriteWidget : Widget
{
public Func<Sprite> GetSprite = () => null;
public RGBASpriteWidget() { }
protected RGBASpriteWidget(RGBASpriteWidget other)
: base(other)
{
GetSprite = other.GetSprite;
}
public override Widget Clone() { return new RGBASpriteWidget(this); }
public override void Draw()
{
var sprite = GetSprite();
if (sprite != null)
Game.Renderer.RgbaSpriteRenderer.DrawSprite(sprite, RenderOrigin);
}
}
}

View File

@@ -0,0 +1,78 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 ScrollItemWidget : ButtonWidget
{
public string ItemKey;
public string BaseName = "scrollitem";
[ObjectCreator.UseCtor]
public ScrollItemWidget(Ruleset modRules)
: base(modRules)
{
IsVisible = () => false;
VisualHeight = 0;
IgnoreChildMouseOver = true;
}
protected ScrollItemWidget(ScrollItemWidget other)
: base(other)
{
IsVisible = () => false;
VisualHeight = 0;
IgnoreChildMouseOver = true;
Key = other.Key;
BaseName = other.BaseName;
}
public Func<bool> IsSelected = () => false;
public override void Draw()
{
var state = IsSelected() ? BaseName + "-selected" :
Ui.MouseOverWidget == this ? BaseName + "-hover" :
null;
if (state != null)
WidgetUtils.DrawPanel(state, RenderBounds);
}
public override Widget Clone() { return new ScrollItemWidget(this); }
public static ScrollItemWidget Setup(ScrollItemWidget template, Func<bool> isSelected, Action onClick)
{
var w = template.Clone() as ScrollItemWidget;
w.IsVisible = () => true;
w.IsSelected = isSelected;
w.OnClick = onClick;
return w;
}
public static ScrollItemWidget Setup(ScrollItemWidget template, Func<bool> isSelected, Action onClick, Action onDoubleClick)
{
var w = Setup(template, isSelected, onClick);
w.OnDoubleClick = onDoubleClick;
return w;
}
public static ScrollItemWidget Setup(string key, ScrollItemWidget template, Func<bool> isSelected, Action onClick, Action onDoubleClick)
{
var w = Setup(template, isSelected, onClick);
w.OnDoubleClick = onDoubleClick;
w.ItemKey = key;
return w;
}
}
}

View File

@@ -0,0 +1,411 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public interface ILayout
{
void AdjustChild(Widget w);
void AdjustChildren();
}
public enum ScrollPanelAlign
{
Bottom,
Top
}
public class ScrollPanelWidget : Widget
{
readonly Ruleset modRules;
public int ScrollbarWidth = 24;
public int ItemSpacing = 2;
public int ButtonDepth = ChromeMetrics.Get<int>("ButtonDepth");
public string Background = "scrollpanel-bg";
public string Button = "scrollpanel-button";
public int ContentHeight;
public ILayout Layout;
public int MinimumThumbSize = 10;
public ScrollPanelAlign Align = ScrollPanelAlign.Top;
public bool CollapseHiddenChildren;
public float SmoothScrollSpeed = 0.333f;
protected bool upPressed;
protected bool downPressed;
protected bool upDisabled;
protected bool downDisabled;
protected bool thumbPressed;
protected Rectangle upButtonRect;
protected Rectangle downButtonRect;
protected Rectangle backgroundRect;
protected Rectangle scrollbarRect;
protected Rectangle thumbRect;
// The target value is the list offset we're trying to reach
float targetListOffset;
// The current value is the actual list offset at the moment
float currentListOffset;
// Setting "smooth" to true will only update the target list offset.
// Setting "smooth" to false will also set the current list offset,
// i.e. it will scroll immediately.
//
// For example, scrolling with the mouse wheel will use smooth
// scrolling to give a nice visual effect that makes it easier
// for the user to follow. Dragging the scrollbar's thumb, however,
// will scroll to the desired position immediately.
protected void SetListOffset(float value, bool smooth)
{
targetListOffset = value;
if (!smooth)
currentListOffset = value;
}
[ObjectCreator.UseCtor]
public ScrollPanelWidget(Ruleset modRules)
{
this.modRules = modRules;
Layout = new ListLayout(this);
}
public override void RemoveChildren()
{
ContentHeight = 0;
base.RemoveChildren();
}
public override void AddChild(Widget child)
{
// Initial setup of margins/height
Layout.AdjustChild(child);
base.AddChild(child);
}
public override void RemoveChild(Widget child)
{
base.RemoveChild(child);
Layout.AdjustChildren();
Scroll(0);
}
public void ReplaceChild(Widget oldChild, Widget newChild)
{
oldChild.Removed();
newChild.Parent = this;
Children[Children.IndexOf(oldChild)] = newChild;
Layout.AdjustChildren();
Scroll(0);
}
public override void DrawOuter()
{
if (!IsVisible())
return;
var rb = RenderBounds;
var scrollbarHeight = rb.Height - 2 * ScrollbarWidth;
var thumbHeight = ContentHeight == 0 ? 0 : Math.Max(MinimumThumbSize, (int)(scrollbarHeight * Math.Min(rb.Height * 1f / ContentHeight, 1f)));
var thumbOrigin = rb.Y + ScrollbarWidth + (int)((scrollbarHeight - thumbHeight) * (-1f * currentListOffset / (ContentHeight - rb.Height)));
if (thumbHeight == scrollbarHeight)
thumbHeight = 0;
backgroundRect = new Rectangle(rb.X, rb.Y, rb.Width - ScrollbarWidth + 1, rb.Height);
upButtonRect = new Rectangle(rb.Right - ScrollbarWidth, rb.Y, ScrollbarWidth, ScrollbarWidth);
downButtonRect = new Rectangle(rb.Right - ScrollbarWidth, rb.Bottom - ScrollbarWidth, ScrollbarWidth, ScrollbarWidth);
scrollbarRect = new Rectangle(rb.Right - ScrollbarWidth, rb.Y + ScrollbarWidth - 1, ScrollbarWidth, scrollbarHeight + 2);
thumbRect = new Rectangle(rb.Right - ScrollbarWidth, thumbOrigin, ScrollbarWidth, thumbHeight);
var upHover = Ui.MouseOverWidget == this && upButtonRect.Contains(Viewport.LastMousePos);
upDisabled = thumbHeight == 0 || currentListOffset >= 0;
var downHover = Ui.MouseOverWidget == this && downButtonRect.Contains(Viewport.LastMousePos);
downDisabled = thumbHeight == 0 || currentListOffset <= Bounds.Height - ContentHeight;
var thumbHover = Ui.MouseOverWidget == this && thumbRect.Contains(Viewport.LastMousePos);
WidgetUtils.DrawPanel(Background, backgroundRect);
WidgetUtils.DrawPanel(Background, scrollbarRect);
ButtonWidget.DrawBackground(Button, upButtonRect, upDisabled, upPressed, upHover, false);
ButtonWidget.DrawBackground(Button, downButtonRect, downDisabled, downPressed, downHover, false);
if (thumbHeight > 0)
ButtonWidget.DrawBackground(Button, thumbRect, false, HasMouseFocus && thumbHover, thumbHover, false);
var upOffset = !upPressed || upDisabled ? 4 : 4 + ButtonDepth;
var downOffset = !downPressed || downDisabled ? 4 : 4 + ButtonDepth;
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", upPressed || upDisabled ? "up_pressed" : "up_arrow"),
new float2(upButtonRect.Left + upOffset, upButtonRect.Top + upOffset));
WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", downPressed || downDisabled ? "down_pressed" : "down_arrow"),
new float2(downButtonRect.Left + downOffset, downButtonRect.Top + downOffset));
Game.Renderer.EnableScissor(backgroundRect.InflateBy(-1, -1, -1, -1));
foreach (var child in Children)
child.DrawOuter();
Game.Renderer.DisableScissor();
}
public override int2 ChildOrigin { get { return RenderOrigin + new int2(0, (int)currentListOffset); } }
public override Rectangle GetEventBounds()
{
return EventBounds;
}
void Scroll(int amount, bool smooth = false)
{
var newTarget = targetListOffset + amount * Game.Settings.Game.UIScrollSpeed;
newTarget = Math.Min(0, Math.Max(Bounds.Height - ContentHeight, newTarget));
SetListOffset(newTarget, smooth);
}
public void ScrollToBottom(bool smooth = false)
{
var value = Align == ScrollPanelAlign.Top ?
Math.Min(0, Bounds.Height - ContentHeight) :
Bounds.Height - ContentHeight;
SetListOffset(value, smooth);
}
public void ScrollToTop(bool smooth = false)
{
var value = Align == ScrollPanelAlign.Top ? 0 :
Math.Max(0, Bounds.Height - ContentHeight);
SetListOffset(value, smooth);
}
public bool ScrolledToBottom
{
get { return targetListOffset == Math.Min(0, Bounds.Height - ContentHeight) || ContentHeight <= Bounds.Height; }
}
public void ScrollToItem(string itemKey, bool smooth = false)
{
var item = Children.FirstOrDefault(c =>
{
var si = c as ScrollItemWidget;
return si != null && si.ItemKey == itemKey;
});
if (item == null)
return;
// Scroll the item to be visible
float? newOffset = null;
if (item.Bounds.Top + currentListOffset < 0)
newOffset = ItemSpacing - item.Bounds.Top;
if (item.Bounds.Bottom + currentListOffset > RenderBounds.Height)
newOffset = RenderBounds.Height - item.Bounds.Bottom - ItemSpacing;
if (newOffset.HasValue)
SetListOffset(newOffset.Value, smooth);
}
public override void Tick()
{
if (upPressed)
Scroll(1);
if (downPressed)
Scroll(-1);
var offsetDiff = targetListOffset - currentListOffset;
var absOffsetDiff = Math.Abs(offsetDiff);
if (absOffsetDiff > 1f)
currentListOffset += offsetDiff * SmoothScrollSpeed.Clamp(0.1f, 1.0f);
else
SetListOffset(targetListOffset, false);
}
public override bool YieldMouseFocus(MouseInput mi)
{
upPressed = downPressed = thumbPressed = false;
return base.YieldMouseFocus(mi);
}
int2 lastMouseLocation;
public override bool HandleMouseInput(MouseInput mi)
{
if (mi.Event == MouseInputEvent.Scroll)
{
Scroll(mi.ScrollDelta, true);
return true;
}
if (mi.Button != MouseButton.Left)
return false;
if (mi.Event == MouseInputEvent.Down && !TakeMouseFocus(mi))
return false;
if (!HasMouseFocus)
return false;
if (HasMouseFocus && mi.Event == MouseInputEvent.Up)
return YieldMouseFocus(mi);
if (thumbPressed && mi.Event == MouseInputEvent.Move)
{
var rb = RenderBounds;
var scrollbarHeight = rb.Height - 2 * ScrollbarWidth;
var thumbHeight = ContentHeight == 0 ? 0 : Math.Max(MinimumThumbSize, (int)(scrollbarHeight * Math.Min(rb.Height * 1f / ContentHeight, 1f)));
var oldOffset = currentListOffset;
var newOffset = currentListOffset + ((int)((lastMouseLocation.Y - mi.Location.Y) * (ContentHeight - rb.Height) * 1f / (scrollbarHeight - thumbHeight)));
newOffset = Math.Min(0, Math.Max(rb.Height - ContentHeight, newOffset));
SetListOffset(newOffset, false);
if (oldOffset != newOffset)
lastMouseLocation = mi.Location;
}
else
{
upPressed = upButtonRect.Contains(mi.Location);
downPressed = downButtonRect.Contains(mi.Location);
thumbPressed = thumbRect.Contains(mi.Location);
if (thumbPressed)
lastMouseLocation = mi.Location;
if (mi.Event == MouseInputEvent.Down && ((upPressed && !upDisabled) || (downPressed && !downDisabled) || thumbPressed))
Sound.PlayNotification(modRules, null, "Sounds", "ClickSound", null);
}
return upPressed || downPressed || thumbPressed;
}
IObservableCollection collection;
Func<object, Widget> makeWidget;
Func<Widget, object, bool> widgetItemEquals;
bool autoScroll;
public void Unbind()
{
Bind(null, null, null, false);
}
public void Bind(IObservableCollection c, Func<object, Widget> makeWidget, Func<Widget, object, bool> widgetItemEquals, bool autoScroll)
{
this.autoScroll = autoScroll;
Game.RunAfterTick(() =>
{
if (collection != null)
{
collection.OnAdd -= BindingAdd;
collection.OnRemove -= BindingRemove;
collection.OnRemoveAt -= BindingRemoveAt;
collection.OnSet -= BindingSet;
collection.OnRefresh -= BindingRefresh;
}
this.makeWidget = makeWidget;
this.widgetItemEquals = widgetItemEquals;
RemoveChildren();
collection = c;
if (c != null)
{
foreach (var item in c.ObservedItems)
BindingAddImpl(item);
c.OnAdd += BindingAdd;
c.OnRemove += BindingRemove;
c.OnRemoveAt += BindingRemoveAt;
c.OnSet += BindingSet;
c.OnRefresh += BindingRefresh;
}
});
}
void BindingAdd(object item)
{
Game.RunAfterTick(() => BindingAddImpl(item));
}
void BindingAddImpl(object item)
{
var widget = makeWidget(item);
var scrollToBottom = autoScroll && ScrolledToBottom;
AddChild(widget);
if (scrollToBottom)
ScrollToBottom();
}
void BindingRemove(object item)
{
Game.RunAfterTick(() =>
{
var widget = Children.FirstOrDefault(w => widgetItemEquals(w, item));
if (widget != null)
RemoveChild(widget);
});
}
void BindingRemoveAt(int index)
{
Game.RunAfterTick(() =>
{
if (index < 0 || index >= Children.Count)
return;
RemoveChild(Children[index]);
});
}
void BindingSet(object oldItem, object newItem)
{
Game.RunAfterTick(() =>
{
var newWidget = makeWidget(newItem);
newWidget.Parent = this;
var i = Children.FindIndex(w => widgetItemEquals(w, oldItem));
if (i >= 0)
{
var oldWidget = Children[i];
oldWidget.Removed();
Children[i] = newWidget;
Layout.AdjustChildren();
}
else
AddChild(newWidget);
});
}
void BindingRefresh()
{
Game.RunAfterTick(() =>
{
RemoveChildren();
foreach (var item in collection.ObservedItems)
BindingAddImpl(item);
});
}
}
}

View File

@@ -0,0 +1,143 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 class SliderWidget : Widget
{
public Func<bool> IsDisabled = () => false;
public event Action<float> OnChange = _ => { };
public int Ticks = 0;
public int TrackHeight = 5;
public string Thumb = "slider-thumb";
public string Track = "slider-track";
public float MinimumValue = 0;
public float MaximumValue = 1;
public float Value = 0;
public Func<float> GetValue;
protected bool isMoving = false;
public SliderWidget()
{
GetValue = () => Value;
}
public SliderWidget(SliderWidget other)
: base(other)
{
OnChange = other.OnChange;
Ticks = other.Ticks;
MinimumValue = other.MinimumValue;
MaximumValue = other.MaximumValue;
Value = other.Value;
TrackHeight = other.TrackHeight;
GetValue = other.GetValue;
}
void UpdateValue(float newValue)
{
Value = newValue.Clamp(MinimumValue, MaximumValue);
OnChange(Value);
}
public override bool HandleMouseInput(MouseInput mi)
{
if (mi.Button != MouseButton.Left) return false;
if (IsDisabled()) 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;
/* TODO: handle snapping to ticks properly again */
/* TODO: handle nudge via clicking outside the thumb */
UpdateValue(ValueFromPx(mi.Location.X - RenderBounds.Left));
break;
case MouseInputEvent.Move:
if (isMoving)
UpdateValue(ValueFromPx(mi.Location.X - RenderBounds.Left));
break;
}
return ThumbRect.Contains(mi.Location);
}
float ValueFromPx(int x)
{
return MinimumValue + (MaximumValue - MinimumValue) * (x - 0.5f * RenderBounds.Height) / (RenderBounds.Width - RenderBounds.Height);
}
protected int PxFromValue(float x)
{
return (int)(0.5f * RenderBounds.Height + (RenderBounds.Width - RenderBounds.Height) * (x - MinimumValue) / (MaximumValue - MinimumValue));
}
public override Widget Clone() { return new SliderWidget(this); }
Rectangle ThumbRect
{
get
{
var thumbPos = PxFromValue(Value);
var rb = RenderBounds;
var width = rb.Height;
var height = rb.Height;
var origin = (int)(rb.X + thumbPos - width / 2f);
return new Rectangle(origin, rb.Y, width, height);
}
}
public override void Draw()
{
if (!IsVisible())
return;
Value = GetValue();
var tr = ThumbRect;
var rb = RenderBounds;
var trackWidth = rb.Width - rb.Height;
var trackOrigin = rb.X + rb.Height / 2;
var trackRect = new Rectangle(trackOrigin - 1, rb.Y + (rb.Height - TrackHeight) / 2, trackWidth + 2, TrackHeight);
// Tickmarks
var tick = ChromeProvider.GetImage("slider", "tick");
for (var i = 0; i < Ticks; i++)
{
var tickPos = new float2(
trackOrigin + (i * (trackRect.Width - (int)tick.Size.X) / (Ticks - 1)) - tick.Size.X / 2,
trackRect.Bottom);
WidgetUtils.DrawRGBA(tick, tickPos);
}
// Track
WidgetUtils.DrawPanel(Track, trackRect);
// Thumb
var thumbHover = Ui.MouseOverWidget == this && tr.Contains(Viewport.LastMousePos);
ButtonWidget.DrawBackground(Thumb, tr, IsDisabled(), isMoving, thumbHover, false);
}
}
}

View File

@@ -0,0 +1,73 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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
{
public class SpriteWidget : Widget
{
public string Palette = "chrome";
public Func<string> GetPalette;
public Func<Sprite> GetSprite;
protected readonly WorldRenderer WorldRenderer;
[ObjectCreator.UseCtor]
public SpriteWidget(WorldRenderer worldRenderer)
{
GetPalette = () => Palette;
this.WorldRenderer = worldRenderer;
}
protected SpriteWidget(SpriteWidget other)
: base(other)
{
Palette = other.Palette;
GetPalette = other.GetPalette;
GetSprite = other.GetSprite;
WorldRenderer = other.WorldRenderer;
}
public override Widget Clone() { return new SpriteWidget(this); }
Sprite cachedSprite = null;
string cachedPalette = null;
PaletteReference pr;
float2 offset = float2.Zero;
public override void Draw()
{
var sprite = GetSprite();
var palette = GetPalette();
if (sprite == null || palette == null)
return;
if (sprite != cachedSprite)
{
offset = 0.5f * (new float2(RenderBounds.Size) - sprite.Size);
cachedSprite = sprite;
}
if (palette != cachedPalette)
{
pr = WorldRenderer.Palette(palette);
cachedPalette = palette;
}
Game.Renderer.SpriteRenderer.DrawSprite(sprite, RenderOrigin + offset, pr);
}
}
}

View File

@@ -0,0 +1,287 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class TextFieldWidget : Widget
{
string text = "";
public string Text
{
get { return text; }
set { text = value ?? ""; CursorPosition = CursorPosition.Clamp(0, text.Length); }
}
public int MaxLength = 0;
public int VisualHeight = 1;
public int LeftMargin = 5;
public int RightMargin = 5;
public Func<bool> OnEnterKey = () => false;
public Func<bool> OnTabKey = () => false;
public Func<bool> OnEscKey = () => false;
public Func<bool> OnAltKey = () => false;
public Action OnLoseFocus = () => { };
public Action OnTextEdited = () => { };
public int CursorPosition { get; set; }
public Func<bool> IsDisabled = () => false;
public Func<bool> IsValid = () => true;
public string Font = ChromeMetrics.Get<string>("TextfieldFont");
public Color TextColor = ChromeMetrics.Get<Color>("TextfieldColor");
public Color TextColorDisabled = ChromeMetrics.Get<Color>("TextfieldColorDisabled");
public Color TextColorInvalid = ChromeMetrics.Get<Color>("TextfieldColorInvalid");
public TextFieldWidget() { }
protected TextFieldWidget(TextFieldWidget widget)
: base(widget)
{
Text = widget.Text;
MaxLength = widget.MaxLength;
Font = widget.Font;
TextColor = widget.TextColor;
TextColorDisabled = widget.TextColorDisabled;
TextColorInvalid = widget.TextColorInvalid;
VisualHeight = widget.VisualHeight;
}
public override bool YieldKeyboardFocus()
{
OnLoseFocus();
return base.YieldKeyboardFocus();
}
public override bool HandleMouseInput(MouseInput mi)
{
if (IsDisabled())
return false;
if (mi.Event != MouseInputEvent.Down)
return false;
// Attempt to take keyboard focus
if (!RenderBounds.Contains(mi.Location) || !TakeKeyboardFocus())
return false;
blinkCycle = 10;
showCursor = true;
CursorPosition = ClosestCursorPosition(mi.Location.X);
return true;
}
protected virtual string GetApparentText() { return text; }
public int ClosestCursorPosition(int x)
{
var apparentText = GetApparentText();
var font = Game.Renderer.Fonts[Font];
var textSize = font.Measure(apparentText);
var start = RenderOrigin.X + LeftMargin;
if (textSize.X > Bounds.Width - LeftMargin - RightMargin && HasKeyboardFocus)
start += Bounds.Width - LeftMargin - RightMargin - textSize.X;
var minIndex = -1;
var minValue = int.MaxValue;
for (var i = 0; i <= apparentText.Length; i++)
{
var dist = Math.Abs(start + font.Measure(apparentText.Substring(0, i)).X - x);
if (dist > minValue)
break;
minValue = dist;
minIndex = i;
}
return minIndex;
}
public override bool HandleKeyPress(KeyInput e)
{
if (IsDisabled() || e.Event == KeyInputEvent.Up)
return false;
// Only take input if we are focused
if (!HasKeyboardFocus)
return false;
if ((e.Key == Keycode.RETURN || e.Key == Keycode.KP_ENTER) && OnEnterKey())
return true;
if (e.Key == Keycode.TAB && OnTabKey())
return true;
if (e.Key == Keycode.ESCAPE && OnEscKey())
return true;
if (e.Key == Keycode.LALT && OnAltKey())
return true;
if (e.Key == Keycode.LEFT)
{
if (CursorPosition > 0)
CursorPosition--;
return true;
}
if (e.Key == Keycode.RIGHT)
{
if (CursorPosition <= Text.Length - 1)
CursorPosition++;
return true;
}
if (e.Key == Keycode.HOME)
{
CursorPosition = 0;
return true;
}
if (e.Key == Keycode.END)
{
CursorPosition = Text.Length;
return true;
}
if (e.Key == Keycode.DELETE)
{
if (CursorPosition < Text.Length)
{
Text = Text.Remove(CursorPosition, 1);
OnTextEdited();
}
return true;
}
if (e.Key == Keycode.BACKSPACE && CursorPosition > 0)
{
CursorPosition--;
Text = Text.Remove(CursorPosition, 1);
OnTextEdited();
return true;
}
if (e.Key == Keycode.V &&
((Platform.CurrentPlatform != PlatformType.OSX && e.Modifiers.HasModifier(Modifiers.Ctrl)) ||
(Platform.CurrentPlatform == PlatformType.OSX && e.Modifiers.HasModifier(Modifiers.Meta))))
{
var clipboardText = Game.Renderer.GetClipboardText();
// Take only the first line of the clipboard contents
var nl = clipboardText.IndexOf('\n');
if (nl > 0)
clipboardText = clipboardText.Substring(0, nl);
clipboardText = clipboardText.Trim();
if (clipboardText.Length > 0)
HandleTextInput(clipboardText);
return true;
}
return true;
}
public override bool HandleTextInput(string text)
{
if (!HasKeyboardFocus || IsDisabled())
return false;
if (MaxLength > 0 && Text.Length >= MaxLength)
return true;
var pasteLength = text.Length;
// Truncate the pasted string if the total length (current + paste) is greater than the maximum.
if (MaxLength > 0 && MaxLength > Text.Length)
pasteLength = Math.Min(text.Length, MaxLength - Text.Length);
Text = Text.Insert(CursorPosition, text.Substring(0, pasteLength));
CursorPosition += pasteLength;
OnTextEdited();
return true;
}
protected int blinkCycle = 10;
protected bool showCursor = true;
bool wasDisabled;
public override void Tick()
{
// Remove the blicking cursor when disabled
var isDisabled = IsDisabled();
if (isDisabled != wasDisabled)
{
wasDisabled = isDisabled;
if (isDisabled && Ui.KeyboardFocusWidget == this)
YieldKeyboardFocus();
}
if (--blinkCycle <= 0)
{
blinkCycle = 20;
showCursor ^= true;
}
}
public override void Draw()
{
var apparentText = GetApparentText();
var font = Game.Renderer.Fonts[Font];
var pos = RenderOrigin;
var textSize = font.Measure(apparentText);
var cursorPosition = font.Measure(apparentText.Substring(0, CursorPosition));
var disabled = IsDisabled();
var state = disabled ? "textfield-disabled" :
HasKeyboardFocus ? "textfield-focused" :
Ui.MouseOverWidget == this ? "textfield-hover" :
"textfield";
WidgetUtils.DrawPanel(state,
new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height));
// Inset text by the margin and center vertically
var textPos = pos + new int2(LeftMargin, (Bounds.Height - textSize.Y) / 2 - VisualHeight);
// Right align when editing and scissor when the text overflows
if (textSize.X > Bounds.Width - LeftMargin - RightMargin)
{
if (HasKeyboardFocus)
textPos += new int2(Bounds.Width - LeftMargin - RightMargin - textSize.X, 0);
Game.Renderer.EnableScissor(new Rectangle(pos.X + LeftMargin, pos.Y,
Bounds.Width - LeftMargin - RightMargin, Bounds.Bottom));
}
var color =
disabled ? TextColorDisabled
: IsValid() ? TextColor
: TextColorInvalid;
font.DrawText(apparentText, textPos, color);
if (showCursor && HasKeyboardFocus)
font.DrawText("|", new float2(textPos.X + cursorPosition.X - 2, textPos.Y), TextColor);
if (textSize.X > Bounds.Width - LeftMargin - RightMargin)
Game.Renderer.DisableScissor();
}
public override Widget Clone() { return new TextFieldWidget(this); }
}
}

View File

@@ -0,0 +1,64 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 class TooltipContainerWidget : Widget
{
static readonly Action Nothing = () => { };
public int2 CursorOffset = new int2(0, 20);
public Action BeforeRender = Nothing;
public int TooltipDelay = 5;
Widget tooltip;
public TooltipContainerWidget()
{
IsVisible = () => Viewport.TicksSinceLastMove >= TooltipDelay;
}
public void SetTooltip(string id, WidgetArgs args)
{
RemoveTooltip();
tooltip = Ui.LoadWidget(id, this, new WidgetArgs(args) { { "tooltipContainer", this } });
}
public void RemoveTooltip()
{
RemoveChildren();
BeforeRender = Nothing;
}
public override void Draw() { BeforeRender(); }
public override Rectangle GetEventBounds() { return Rectangle.Empty; }
public override int2 ChildOrigin
{
get
{
var pos = Viewport.LastMousePos + (CursorProvider.CursorViewportZoomed ? CursorOffset * 2 : CursorOffset);
if (tooltip != null)
{
if (pos.X + tooltip.Bounds.Right > Game.Renderer.Resolution.Width)
pos = pos.WithX(Game.Renderer.Resolution.Width - tooltip.Bounds.Right);
}
return pos;
}
}
public override string GetCursor(int2 pos) { return null; }
}
}

View File

@@ -0,0 +1,218 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Linq;
using OpenRA.Graphics;
using OpenRA.Orders;
using OpenRA.Traits;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public enum WorldTooltipType { None, Unexplored, Actor, FrozenActor }
public class ViewportControllerWidget : Widget
{
public readonly string TooltipTemplate = "WORLD_TOOLTIP";
public readonly string TooltipContainer;
Lazy<TooltipContainerWidget> tooltipContainer;
public WorldTooltipType TooltipType { get; private set; }
public IToolTip ActorTooltip { get; private set; }
public IEnumerable<IProvideTooltipInfo> ActorTooltipExtra { get; private set; }
public FrozenActor FrozenActorTooltip { get; private set; }
public int EdgeScrollThreshold = 15;
public int EdgeCornerScrollThreshold = 35;
static readonly Dictionary<ScrollDirection, string> ScrollCursors = new Dictionary<ScrollDirection, string>
{
{ ScrollDirection.Up | ScrollDirection.Left, "scroll-tl" },
{ ScrollDirection.Up | ScrollDirection.Right, "scroll-tr" },
{ ScrollDirection.Down | ScrollDirection.Left, "scroll-bl" },
{ ScrollDirection.Down | ScrollDirection.Right, "scroll-br" },
{ ScrollDirection.Up, "scroll-t" },
{ ScrollDirection.Down, "scroll-b" },
{ ScrollDirection.Left, "scroll-l" },
{ ScrollDirection.Right, "scroll-r" },
};
static readonly Dictionary<ScrollDirection, float2> ScrollOffsets = new Dictionary<ScrollDirection, float2>
{
{ ScrollDirection.Up, new float2(0, -1) },
{ ScrollDirection.Down, new float2(0, 1) },
{ ScrollDirection.Left, new float2(-1, 0) },
{ ScrollDirection.Right, new float2(1, 0) },
};
ScrollDirection keyboardDirections;
ScrollDirection edgeDirections;
World world;
WorldRenderer worldRenderer;
[ObjectCreator.UseCtor]
public ViewportControllerWidget(World world, WorldRenderer worldRenderer)
{
this.world = world;
this.worldRenderer = worldRenderer;
tooltipContainer = Exts.Lazy(() =>
Ui.Root.Get<TooltipContainerWidget>(TooltipContainer));
}
public override void MouseEntered()
{
if (TooltipContainer == null)
return;
tooltipContainer.Value.SetTooltip(TooltipTemplate,
new WidgetArgs() { { "world", world }, { "viewport", this } });
}
public override void MouseExited()
{
if (TooltipContainer == null)
return;
tooltipContainer.Value.RemoveTooltip();
}
public override void Draw()
{
UpdateMouseover();
base.Draw();
}
public void UpdateMouseover()
{
TooltipType = WorldTooltipType.None;
ActorTooltipExtra = null;
var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos);
if (!world.Map.Contains(cell))
return;
if (world.ShroudObscures(cell))
{
TooltipType = WorldTooltipType.Unexplored;
return;
}
var underCursor = world.ScreenMap.ActorsAt(worldRenderer.Viewport.ViewToWorldPx(Viewport.LastMousePos))
.Where(a => !world.FogObscures(a) && a.HasTrait<IToolTip>())
.WithHighestSelectionPriority();
if (underCursor != null)
{
ActorTooltip = underCursor.TraitsImplementing<IToolTip>().First();
ActorTooltipExtra = underCursor.TraitsImplementing<IProvideTooltipInfo>();
TooltipType = WorldTooltipType.Actor;
return;
}
var frozen = world.ScreenMap.FrozenActorsAt(world.RenderPlayer, worldRenderer.Viewport.ViewToWorldPx(Viewport.LastMousePos))
.Where(a => a.TooltipInfo != null && a.IsValid)
.WithHighestSelectionPriority();
if (frozen != null)
{
FrozenActorTooltip = frozen;
if (frozen.Actor != null)
ActorTooltipExtra = frozen.Actor.TraitsImplementing<IProvideTooltipInfo>();
TooltipType = WorldTooltipType.FrozenActor;
}
}
public override string GetCursor(int2 pos)
{
if (!Game.Settings.Game.ViewportEdgeScroll || Ui.MouseOverWidget != this)
return null;
var blockedDirections = worldRenderer.Viewport.GetBlockedDirections();
foreach (var dir in ScrollCursors)
if (edgeDirections.Includes(dir.Key))
return dir.Value + (blockedDirections.Includes(dir.Key) ? "-blocked" : "");
return null;
}
public override bool HandleMouseInput(MouseInput mi)
{
var scrolltype = Game.Settings.Game.MouseScroll;
if (scrolltype == MouseScrollType.Disabled)
return false;
if (mi.Event == MouseInputEvent.Move &&
(mi.Button == MouseButton.Middle || mi.Button == (MouseButton.Left | MouseButton.Right)))
{
var d = scrolltype == MouseScrollType.Inverted ? -1 : 1;
worldRenderer.Viewport.Scroll((Viewport.LastMousePos - mi.Location) * d, false);
return true;
}
return false;
}
public override bool YieldKeyboardFocus()
{
keyboardDirections = ScrollDirection.None;
return base.YieldKeyboardFocus();
}
public override bool HandleKeyPress(KeyInput e)
{
switch (e.Key)
{
case Keycode.UP: keyboardDirections = keyboardDirections.Set(ScrollDirection.Up, e.Event == KeyInputEvent.Down); return true;
case Keycode.DOWN: keyboardDirections = keyboardDirections.Set(ScrollDirection.Down, e.Event == KeyInputEvent.Down); return true;
case Keycode.LEFT: keyboardDirections = keyboardDirections.Set(ScrollDirection.Left, e.Event == KeyInputEvent.Down); return true;
case Keycode.RIGHT: keyboardDirections = keyboardDirections.Set(ScrollDirection.Right, e.Event == KeyInputEvent.Down); return true;
}
return false;
}
public override void Tick()
{
edgeDirections = ScrollDirection.None;
if (Game.Settings.Game.ViewportEdgeScroll && Game.HasInputFocus)
edgeDirections = CheckForDirections();
if (keyboardDirections != ScrollDirection.None || edgeDirections != ScrollDirection.None)
{
var scroll = float2.Zero;
foreach (var kv in ScrollOffsets)
if (keyboardDirections.Includes(kv.Key) || edgeDirections.Includes(kv.Key))
scroll += kv.Value;
var length = Math.Max(1, scroll.Length);
scroll *= (1f / length) * Game.Settings.Game.ViewportEdgeScrollStep;
worldRenderer.Viewport.Scroll(scroll, false);
}
}
ScrollDirection CheckForDirections()
{
var directions = ScrollDirection.None;
if (Viewport.LastMousePos.X < EdgeScrollThreshold)
directions |= ScrollDirection.Left;
if (Viewport.LastMousePos.Y < EdgeScrollThreshold)
directions |= ScrollDirection.Up;
if (Viewport.LastMousePos.X >= Game.Renderer.Resolution.Width - EdgeScrollThreshold)
directions |= ScrollDirection.Right;
if (Viewport.LastMousePos.Y >= Game.Renderer.Resolution.Height - EdgeScrollThreshold)
directions |= ScrollDirection.Down;
return directions;
}
}
}

View File

@@ -0,0 +1,214 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.FileFormats;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class VqaPlayerWidget : Widget
{
public Hotkey CancelKey = new Hotkey(Keycode.ESCAPE, Modifiers.None);
public float AspectRatio = 1.2f;
public bool DrawOverlay = true;
public bool Skippable = true;
public bool Paused { get { return paused; } }
public VqaReader Video { get { return video; } }
Sprite videoSprite, overlaySprite;
VqaReader video = null;
string cachedVideo;
float invLength;
float2 videoOrigin, videoSize;
uint[,] overlay;
bool stopped;
bool paused;
Action onComplete;
readonly World world;
[ObjectCreator.UseCtor]
public VqaPlayerWidget(World world)
{
this.world = world;
}
public void Load(string filename)
{
if (filename == cachedVideo)
return;
var video = new VqaReader(GlobalFileSystem.Open(filename));
cachedVideo = filename;
Open(video);
}
public void Open(VqaReader video)
{
this.video = video;
stopped = true;
paused = true;
Sound.StopVideo();
onComplete = () => { };
invLength = video.Framerate * 1f / video.Frames;
var size = Math.Max(video.Width, video.Height);
var textureSize = Exts.NextPowerOf2(size);
var videoSheet = new Sheet(new Size(textureSize, textureSize));
videoSheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
videoSheet.GetTexture().SetData(video.FrameData);
videoSprite = new Sprite(videoSheet,
new Rectangle(
0,
0,
video.Width,
video.Height),
TextureChannel.Alpha);
var scale = Math.Min((float)RenderBounds.Width / video.Width, (float)RenderBounds.Height / video.Height * AspectRatio);
videoOrigin = new float2(
RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2,
RenderBounds.Y + (RenderBounds.Height - scale * video.Height * AspectRatio) / 2);
// Round size to integer pixels. Round up to be consistent with the scale calcuation.
videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * AspectRatio * scale));
if (!DrawOverlay)
return;
var scaledHeight = (int)videoSize.Y;
overlay = new uint[Exts.NextPowerOf2(scaledHeight), 1];
var black = (uint)255 << 24;
for (var y = 0; y < scaledHeight; y += 2)
overlay[y, 0] = black;
var overlaySheet = new Sheet(new Size(1, Exts.NextPowerOf2(scaledHeight)));
overlaySheet.GetTexture().SetData(overlay);
overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, scaledHeight), TextureChannel.Alpha);
}
public override void Draw()
{
if (video == null)
return;
if (!stopped && !paused)
{
var nextFrame = 0;
if (video.HasAudio)
nextFrame = (int)float2.Lerp(0, video.Frames, Sound.VideoSeekPosition * invLength);
else
nextFrame = video.CurrentFrame + 1;
// Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame
if (nextFrame > video.Frames || nextFrame < video.CurrentFrame)
{
Stop();
return;
}
var skippedFrames = 0;
while (nextFrame > video.CurrentFrame)
{
video.AdvanceFrame();
videoSprite.Sheet.GetTexture().SetData(video.FrameData);
skippedFrames++;
}
if (skippedFrames > 1)
Log.Write("perf", "VqaPlayer : {0} skipped {1} frames at position {2}", cachedVideo, skippedFrames, video.CurrentFrame);
}
Game.Renderer.RgbaSpriteRenderer.DrawSprite(
videoSprite,
videoOrigin,
videoSize);
if (DrawOverlay)
Game.Renderer.RgbaSpriteRenderer.DrawSprite(overlaySprite, videoOrigin, videoSize);
}
public override bool HandleKeyPress(KeyInput e)
{
if (Hotkey.FromKeyInput(e) != CancelKey || e.Event != KeyInputEvent.Down || !Skippable)
return false;
Stop();
return true;
}
public override bool HandleMouseInput(MouseInput mi)
{
return RenderBounds.Contains(mi.Location) && Skippable;
}
public override string GetCursor(int2 pos)
{
return null;
}
public void Play()
{
PlayThen(() => { });
}
public void PlayThen(Action after)
{
if (video == null)
return;
onComplete = after;
if (stopped)
Sound.PlayVideo(video.AudioData, video.AudioChannels, video.SampleBits, video.SampleRate);
else
Sound.PlayVideo();
stopped = paused = false;
}
public void Pause()
{
if (stopped || paused || video == null)
return;
paused = true;
Sound.PauseVideo();
}
public void Stop()
{
if (stopped || video == null)
return;
stopped = true;
paused = true;
Sound.StopVideo();
video.Reset();
videoSprite.Sheet.GetTexture().SetData(video.FrameData);
world.AddFrameEndTask(_ => onComplete());
}
public void CloseVideo()
{
Stop();
video = null;
}
}
}