Skip to content

Commit

Permalink
Implement color inputting (OpenDreamProject#1595)
Browse files Browse the repository at this point in the history
* Implement color inputting

* Update OpenDreamRuntime/DreamConnection.cs

Co-authored-by: wixoa <[email protected]>

* bwah

---------

Co-authored-by: wixoa <[email protected]>
  • Loading branch information
Absolucy and wixoaGit authored Jan 2, 2024
1 parent fa34287 commit a143b68
Show file tree
Hide file tree
Showing 10 changed files with 496 additions and 36 deletions.
60 changes: 31 additions & 29 deletions OpenDreamClient/Interface/DreamInterfaceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ void OnPromptClose(DMValueType responseType, object? response) {
prompt = new NumberPrompt(pPrompt.Title, pPrompt.Message, pPrompt.DefaultValue, canCancel, OnPromptClose);
} else if ((pPrompt.Types & DMValueType.Message) == DMValueType.Message) {
prompt = new MessagePrompt(pPrompt.Title, pPrompt.Message, pPrompt.DefaultValue, canCancel, OnPromptClose);
} else if ((pPrompt.Types & DMValueType.Color) == DMValueType.Color) {
prompt = new ColorPrompt(pPrompt.Title, pPrompt.Message, pPrompt.DefaultValue, canCancel, OnPromptClose);
}

if (prompt != null) {
Expand Down Expand Up @@ -368,7 +370,7 @@ public void FrameUpdate(FrameEventArgs frameEventArgs) {
} else if (_popupWindows.TryGetValue(windowId, out var popup)) {
window = popup.WindowElement;
} else if (Menus.TryGetValue(windowId, out var menu)) {
if(menu.MenuElements.TryGetValue(elementId, out var menuElement))
if (menu.MenuElements.TryGetValue(elementId, out var menuElement))
return menuElement;
}

Expand Down Expand Up @@ -426,45 +428,45 @@ public void SaveScreenshot(bool openDialog) {
});
}

public void RunCommand(string command){
public void RunCommand(string command) {
switch (command) {
case string x when x.StartsWith(".quit"):
IoCManager.Resolve<IClientNetManager>().ClientDisconnect(".quit used");
break;
case string x when x.StartsWith(".quit"):
IoCManager.Resolve<IClientNetManager>().ClientDisconnect(".quit used");
break;

case string x when x.StartsWith(".screenshot"):
string[] split = command.Split(" ");
SaveScreenshot(split.Length == 1 || split[1] != "auto");
break;
case string x when x.StartsWith(".screenshot"):
string[] split = command.Split(" ");
SaveScreenshot(split.Length == 1 || split[1] != "auto");
break;

case string x when x.StartsWith(".configure"):
_sawmill.Warning(".configure command is not implemented");
break;
case string x when x.StartsWith(".configure"):
_sawmill.Warning(".configure command is not implemented");
break;

case string x when x.StartsWith(".winset"):
// Everything after .winset, excluding the space and quotes
string winsetParams = command.Substring(7); //clip .winset
winsetParams = winsetParams.Trim(); //clip space
winsetParams = winsetParams.Trim('\"'); //clip quotes
case string x when x.StartsWith(".winset"):
// Everything after .winset, excluding the space and quotes
string winsetParams = command.Substring(7); //clip .winset
winsetParams = winsetParams.Trim(); //clip space
winsetParams = winsetParams.Trim('\"'); //clip quotes

WinSet(null, winsetParams);
break;
WinSet(null, winsetParams);
break;

default: {
// Send the entire command to the server.
// It has more info about argument types so it can parse it better than we can.
_netManager.ClientSendMessage(new MsgCommand(){Command = command});
break;
}
default: {
// Send the entire command to the server.
// It has more info about argument types so it can parse it better than we can.
_netManager.ClientSendMessage(new MsgCommand() { Command = command });
break;
}
}
}

public void StartRepeatingCommand(string command) {
_netManager.ClientSendMessage(new MsgCommandRepeatStart(){Command = command});
_netManager.ClientSendMessage(new MsgCommandRepeatStart() { Command = command });
}

public void StopRepeatingCommand(string command) {
_netManager.ClientSendMessage(new MsgCommandRepeatStop(){Command = command});
_netManager.ClientSendMessage(new MsgCommandRepeatStop() { Command = command });
}

public void WinSet(string? controlId, string winsetParams) {
Expand Down Expand Up @@ -615,7 +617,7 @@ public void WinClone(string controlId, string cloneId) {
// that name already, we will create a new control of that type from scratch.
if (elementDescriptor == null) {
switch (controlId) {
case "window" :
case "window":
elementDescriptor = new WindowDescriptor(cloneId);
break;
case "menu":
Expand All @@ -636,7 +638,7 @@ public void WinClone(string controlId, string cloneId) {
}

LoadDescriptor(elementDescriptor);
if(elementDescriptor is WindowDescriptor && Windows.TryGetValue(cloneId, out var window)){
if (elementDescriptor is WindowDescriptor && Windows.TryGetValue(cloneId, out var window)) {
window.CreateChildControls();
}
}
Expand Down
175 changes: 175 additions & 0 deletions OpenDreamClient/Interface/Prompts/ColorPrompt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System.Linq;
using Linguini.Bundle.Errors;
using OpenDreamShared.Dream;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.Stylesheets;

namespace OpenDreamClient.Interface.Prompts;

internal sealed class ColorPrompt : InputWindow {
private readonly BoxContainer _baseControl;
private readonly ColorSelectorSliders _colorSelector;
private readonly LineEdit _hexColor;
private readonly Button _preview;
private readonly Color _originalColor;

public ColorPrompt(string title, string message, string defaultValue, bool canCancel,
Action<DMValueType, object?>? onClose, bool alpha = false) : base(title, message, canCancel, onClose) {
_originalColor = Color.FromHex(defaultValue, Color.White);
_colorSelector = new() {
Color = _originalColor,
VerticalAlignment = VAlignment.Top,
Stylesheet = ColorPromptStylesheet.Make(),
IsAlphaVisible = alpha,
OnColorChanged = ColorSelectorSliders_OnColorChanged
};
var defaultHex = _colorSelector.IsAlphaVisible ? _originalColor.ToHex() : _originalColor.ToHexNoAlpha();
_hexColor = new LineEdit {
Text = defaultHex,
HorizontalExpand = true,
PlaceHolder = _colorSelector.IsAlphaVisible ? "#RRGGBBAA" : "#RRGGBB",
IsValid = (string text) => {
text = text.Trim().TrimStart('#');
return text.Length <= (_colorSelector.IsAlphaVisible ? 8 : 6) && text.All(char.IsAsciiHexDigit);
}
};
_hexColor.OnFocusExit += LineEdit_OnFinishInput;
_hexColor.OnTextEntered += LineEdit_OnFinishInput;

_preview = new Button {
SetSize = new Vector2(32, 32),
Modulate = _originalColor,
MouseFilter = MouseFilterMode.Ignore,
};

_baseControl = new BoxContainer {
Orientation = BoxContainer.LayoutOrientation.Vertical,
Children = {
_colorSelector,
new BoxContainer {
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
SeparationOverride = 8,
Children = { _preview, _hexColor }
}
}
};

SetPromptControl(_baseControl, grabKeyboard: false);
}

private void ColorSelectorSliders_OnColorChanged(Color color) {
_hexColor.Text = _colorSelector.IsAlphaVisible ? color.ToHex() : color.ToHexNoAlpha();
_preview.Modulate = color;
}

private void LineEdit_OnFinishInput(LineEdit.LineEditEventArgs args) {
var text = args.Text.Trim();
if (!text.StartsWith('#')) text = '#' + text;
var newColor = Color.TryFromHex(text);
if (newColor.HasValue) {
_colorSelector.Color = newColor.Value;
}
}

protected override void OkButtonClicked() {
FinishPrompt(DMValueType.Color, _colorSelector.Color);
}
}

// WHY IS ColorSelectorSliders A PART OF ROBUST, BUT THE STYLESHEET IT USES IS IN SS14?!
internal static class ColorPromptStylesheet {
private static readonly Color PanelDark = Color.FromHex("#1E1E22");
private const string StyleClassSliderRed = "Red";
private const string StyleClassSliderGreen = "Green";
private const string StyleClassSliderBlue = "Blue";
private const string StyleClassSliderWhite = "White";

private static StyleBoxTexture MakeSliderFill(Color color) {
return new() {
Texture = IoCManager.Resolve<IResourceCache>().GetResource<TextureResource>("/Textures/Interface/Nano/slider_fill.svg.96dpi.png").Texture,
Modulate = color,
PatchMarginLeft = 12,
PatchMarginRight = 12,
PatchMarginTop = 12,
PatchMarginBottom = 12,
};
}

private static StyleBoxTexture MakeSliderGrab() {
return new() {
Texture = IoCManager.Resolve<IResourceCache>().GetResource<TextureResource>("/Textures/Interface/Nano/slider_grabber.svg.96dpi.png").Texture,
PatchMarginLeft = 12,
PatchMarginRight = 12,
PatchMarginTop = 12,
PatchMarginBottom = 12,
};
}

private static StyleBoxTexture MakeSliderOutline(Color color) {
return new() {
Texture = IoCManager.Resolve<IResourceCache>().GetResource<TextureResource>("/Textures/Interface/Nano/slider_outline.svg.96dpi.png").Texture,
Modulate = color,
PatchMarginLeft = 12,
PatchMarginRight = 12,
PatchMarginTop = 12,
PatchMarginBottom = 12,
};
}


public static Stylesheet Make() {
var sliderFillBox = MakeSliderFill(Color.FromHex("#3E6C45"));
var sliderBackBox = MakeSliderOutline(PanelDark);
var sliderForeBox = MakeSliderOutline(Color.FromHex("#494949"));
var sliderGrabBox = MakeSliderGrab();

var sliderFillGreen = new StyleBoxTexture(sliderFillBox) { Modulate = Color.LimeGreen };
var sliderFillRed = new StyleBoxTexture(sliderFillBox) { Modulate = Color.Red };
var sliderFillBlue = new StyleBoxTexture(sliderFillBox) { Modulate = Color.Blue };
var sliderFillWhite = new StyleBoxTexture(sliderFillBox) { Modulate = Color.White };

var styles = new DefaultStylesheet(IoCManager.Resolve<IResourceCache>(), IoCManager.Resolve<IUserInterfaceManager>()).Stylesheet.Rules.ToList();
var newStyles = new StyleRule[] {
// Slider
new StyleRule(SelectorElement.Type(typeof(Slider)), new []
{
new StyleProperty(Slider.StylePropertyBackground, sliderBackBox),
new StyleProperty(Slider.StylePropertyForeground, sliderForeBox),
new StyleProperty(Slider.StylePropertyGrabber, sliderGrabBox),
new StyleProperty(Slider.StylePropertyFill, sliderFillBox),
}),

new StyleRule(SelectorElement.Type(typeof(ColorableSlider)), new []
{
new StyleProperty(ColorableSlider.StylePropertyFillWhite, sliderFillWhite),
new StyleProperty(ColorableSlider.StylePropertyBackgroundWhite, sliderFillWhite),
}),

new StyleRule(new SelectorElement(typeof(Slider), new []{StyleClassSliderRed}, null, null), new []
{
new StyleProperty(Slider.StylePropertyFill, sliderFillRed),
}),

new StyleRule(new SelectorElement(typeof(Slider), new []{StyleClassSliderGreen}, null, null), new []
{
new StyleProperty(Slider.StylePropertyFill, sliderFillGreen),
}),

new StyleRule(new SelectorElement(typeof(Slider), new []{StyleClassSliderBlue}, null, null), new []
{
new StyleProperty(Slider.StylePropertyFill, sliderFillBlue),
}),

new StyleRule(new SelectorElement(typeof(Slider), new []{StyleClassSliderWhite}, null, null), new []
{
new StyleProperty(Slider.StylePropertyFill, sliderFillWhite),
})
};
styles.AddRange(newStyles);
return new Stylesheet(styles);
}
}
8 changes: 5 additions & 3 deletions OpenDreamRuntime/DreamConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public sealed class DreamConnection {

[ViewVariables] public ICommonSession? Session { get; private set; }
[ViewVariables] public DreamObjectClient? Client { get; private set; }
[ViewVariables] public DreamObjectMob? Mob {
[ViewVariables]
public DreamObjectMob? Mob {
get => _mob;
set {
if (_mob != value) {
Expand Down Expand Up @@ -234,7 +235,7 @@ public void AddStatPanelLine(string name, string value, string? atomRef) {
if (_outputStatPanel == null || !_statPanels.ContainsKey(_outputStatPanel))
SetOutputStatPanel("Stats");

_statPanels[_outputStatPanel].Add( (name, value, atomRef) );
_statPanels[_outputStatPanel].Add((name, value, atomRef));
}

public void HandleMsgSelectStatPanel(MsgSelectStatPanel message) {
Expand All @@ -251,6 +252,7 @@ public void HandleMsgPromptResponse(MsgPromptResponse message) {
DMValueType.Null => DreamValue.Null,
DMValueType.Text or DMValueType.Message => new DreamValue((string)message.Value),
DMValueType.Num => new DreamValue((float)message.Value),
DMValueType.Color => new DreamValue(((Color)message.Value).ToHexNoAlpha()),
_ => throw new Exception("Invalid prompt response '" + message.Type + "'")
};

Expand Down Expand Up @@ -372,7 +374,7 @@ public void HandleCommand(string fullCommand) {
DMValueType argumentType = verb.ArgumentTypes[i];

if (argumentType == DMValueType.Text) {
arguments[i] = new(args[i+1]);
arguments[i] = new(args[i + 1]);
} else {
_sawmill.Error($"Parsing verb args of type {argumentType} is unimplemented; ignoring command ({fullCommand})");
return DreamValue.Null;
Expand Down
17 changes: 13 additions & 4 deletions OpenDreamShared/Network/Messages/MsgPromptResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Lidgren.Network;
using OpenDreamShared.Dream;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Serialization;

Expand All @@ -14,27 +15,35 @@ public sealed class MsgPromptResponse : NetMessage {

public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) {
PromptId = buffer.ReadVariableInt32();
Type = (DMValueType) buffer.ReadUInt16();
Type = (DMValueType)buffer.ReadUInt16();

Value = Type switch {
DMValueType.Null => null,
DMValueType.Text or DMValueType.Message => buffer.ReadString(),
DMValueType.Num => buffer.ReadSingle(),
DMValueType.Color => new Color(buffer.ReadByte(), buffer.ReadByte(), buffer.ReadByte(), buffer.ReadByte()),
_ => throw new ArgumentOutOfRangeException()
};
}

public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) {
buffer.WriteVariableInt32(PromptId);

buffer.Write((ushort) Type);
buffer.Write((ushort)Type);
switch (Type) {
case DMValueType.Null: break;
case DMValueType.Text or DMValueType.Message:
buffer.Write((string) Value!);
buffer.Write((string)Value!);
break;
case DMValueType.Num:
buffer.Write((float) Value!);
buffer.Write((float)Value!);
break;
case DMValueType.Color:
var color = (Color)Value!;
buffer.Write(color.RByte);
buffer.Write(color.GByte);
buffer.Write(color.BByte);
buffer.Write(color.AByte);
break;
default: throw new Exception("Invalid prompt response type '" + Type + "'");
}
Expand Down
Loading

0 comments on commit a143b68

Please sign in to comment.