Improve paper stamping experience (#17135)

This commit is contained in:
eoineoineoin
2023-08-13 19:28:10 +01:00
committed by GitHub
parent ae2dcc8aba
commit 4ccc8a04be
28 changed files with 629 additions and 202 deletions

View File

@@ -1,4 +1,4 @@
using Content.Client.Eui; using Content.Client.Eui;
using Content.Shared.Eui; using Content.Shared.Eui;
using Content.Shared.Fax; using Content.Shared.Fax;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -15,7 +15,8 @@ public sealed class AdminFaxEui : BaseEui
_window = new AdminFaxWindow(); _window = new AdminFaxWindow();
_window.OnClose += () => SendMessage(new AdminFaxEuiMsg.Close()); _window.OnClose += () => SendMessage(new AdminFaxEuiMsg.Close());
_window.OnFollowFax += uid => SendMessage(new AdminFaxEuiMsg.Follow(uid)); _window.OnFollowFax += uid => SendMessage(new AdminFaxEuiMsg.Follow(uid));
_window.OnMessageSend += args => SendMessage(new AdminFaxEuiMsg.Send(args.uid, args.title, args.from, args.message, args.stamp)); _window.OnMessageSend += args => SendMessage(new AdminFaxEuiMsg.Send(args.uid, args.title,
args.stampedBy, args.message, args.stampSprite, args.stampColor));
} }
public override void Opened() public override void Opened()

View File

@@ -1,4 +1,4 @@
<DefaultWindow xmlns="https://spacestation14.io" <DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc admin-fax-title}" Title="{Loc admin-fax-title}"
MinWidth="400"> MinWidth="400">
<BoxContainer Orientation="Vertical" VerticalExpand="True"> <BoxContainer Orientation="Vertical" VerticalExpand="True">
@@ -21,6 +21,8 @@
<Control MinWidth="5" /> <Control MinWidth="5" />
<OptionButton Name="StampSelector" HorizontalExpand="True" /> <OptionButton Name="StampSelector" HorizontalExpand="True" />
</BoxContainer> </BoxContainer>
<Label Text="{Loc admin-fax-stamp-color}" />
<ColorSelectorSliders Margin="12 0 0 0" Name="StampColorSelector" Color="#BB3232"/>
<Control MinHeight="10" /> <Control MinHeight="10" />
<Button Name="SendButton" Text="{Loc admin-fax-send}"></Button> <Button Name="SendButton" Text="{Loc admin-fax-send}"></Button>
</BoxContainer> </BoxContainer>

View File

@@ -1,4 +1,4 @@
using Content.Shared.Fax; using Content.Shared.Fax;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
@@ -13,7 +13,7 @@ public sealed partial class AdminFaxWindow : DefaultWindow
{ {
private const string StampsRsiPath = "/Textures/Objects/Misc/bureaucracy.rsi"; private const string StampsRsiPath = "/Textures/Objects/Misc/bureaucracy.rsi";
public Action<(EntityUid uid, string title, string from, string message, string stamp)>? OnMessageSend; public Action<(EntityUid uid, string title, string stampedBy, string message, string stampSprite, Color stampColor)>? OnMessageSend;
public Action<EntityUid>? OnFollowFax; public Action<EntityUid>? OnFollowFax;
public AdminFaxWindow() public AdminFaxWindow()
@@ -28,6 +28,9 @@ public sealed partial class AdminFaxWindow : DefaultWindow
FollowButton.OnPressed += FollowFax; FollowButton.OnPressed += FollowFax;
SendButton.OnPressed += SendMessage; SendButton.OnPressed += SendMessage;
// Don't use this, but ColorSelectorSliders requires it:
StampColorSelector.OnColorChanged += (Color) => {};
var loc = IoCManager.Resolve<ILocalizationManager>(); var loc = IoCManager.Resolve<ILocalizationManager>();
MessageEdit.Placeholder = new Rope.Leaf(loc.GetString("admin-fax-message-placeholder")); // TextEdit work only with Nodes MessageEdit.Placeholder = new Rope.Leaf(loc.GetString("admin-fax-message-placeholder")); // TextEdit work only with Nodes
} }
@@ -90,6 +93,7 @@ public sealed partial class AdminFaxWindow : DefaultWindow
return; return;
var from = FromEdit.Text; var from = FromEdit.Text;
OnMessageSend?.Invoke((faxUid.Value, title, from, message, stamp)); var stampColor = StampColorSelector.Color;
OnMessageSend?.Invoke((faxUid.Value, title, from, message, stamp, stampColor));
} }
} }

View File

@@ -5,67 +5,66 @@ using Robust.Shared.Input;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using static Content.Shared.Paper.SharedPaperComponent; using static Content.Shared.Paper.SharedPaperComponent;
namespace Content.Client.Paper.UI namespace Content.Client.Paper.UI;
[UsedImplicitly]
public sealed class PaperBoundUserInterface : BoundUserInterface
{ {
[UsedImplicitly] [ViewVariables]
public sealed class PaperBoundUserInterface : BoundUserInterface private PaperWindow? _window;
public PaperBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{ {
[ViewVariables] }
private PaperWindow? _window;
public PaperBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open()
{
base.Open();
_window = new PaperWindow();
_window.OnClose += Close;
_window.Input.OnKeyBindDown += args => // Solution while TextEdit don't have events
{ {
} if (args.Function == EngineKeyFunctions.TextSubmit)
protected override void Open()
{
base.Open();
_window = new PaperWindow();
_window.OnClose += Close;
_window.Input.OnKeyBindDown += args => // Solution while TextEdit don't have events
{ {
if (args.Function == EngineKeyFunctions.TextSubmit) var text = Rope.Collapse(_window.Input.TextRope);
{ Input_OnTextEntered(text);
var text = Rope.Collapse(_window.Input.TextRope); args.Handle();
Input_OnTextEntered(text);
args.Handle();
}
};
if (EntMan.TryGetComponent<PaperVisualsComponent>(Owner, out var visuals))
{
_window.InitVisuals(visuals);
} }
};
_window.OpenCentered(); if (EntMan.TryGetComponent<PaperVisualsComponent>(Owner, out var visuals))
{
_window.InitVisuals(Owner, visuals);
} }
protected override void UpdateState(BoundUserInterfaceState state) _window.OpenCentered();
{ }
base.UpdateState(state);
_window?.Populate((PaperBoundUserInterfaceState) state);
}
private void Input_OnTextEntered(string text) protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
_window?.Populate((PaperBoundUserInterfaceState) state);
}
private void Input_OnTextEntered(string text)
{
if (!string.IsNullOrEmpty(text))
{ {
if (!string.IsNullOrEmpty(text)) SendMessage(new PaperInputTextMessage(text));
if (_window != null)
{ {
SendMessage(new PaperInputTextMessage(text)); _window.Input.TextRope = Rope.Leaf.Empty;
_window.Input.CursorPosition = new TextEdit.CursorPos(0, TextEdit.LineBreakBias.Top);
if (_window != null)
{
_window.Input.TextRope = Rope.Leaf.Empty;
_window.Input.CursorPosition = new TextEdit.CursorPos(0, TextEdit.LineBreakBias.Top);
}
} }
} }
}
protected override void Dispose(bool disposing)
{ protected override void Dispose(bool disposing)
base.Dispose(disposing); {
if (!disposing) return; base.Dispose(disposing);
_window?.Dispose(); if (!disposing) return;
} _window?.Dispose();
} }
} }

View File

@@ -20,7 +20,8 @@
<TextEdit Name="Input" StyleClasses="PaperLineEdit" Access="Public" /> <TextEdit Name="Input" StyleClasses="PaperLineEdit" Access="Public" />
</PanelContainer> </PanelContainer>
</BoxContainer> </BoxContainer>
<BoxContainer Name="StampDisplay" Orientation="Vertical" VerticalAlignment="Bottom" Margin="6"/> <paper:StampCollection Name="StampDisplay" VerticalAlignment="Bottom" Margin="6"/>
</PanelContainer> </PanelContainer>
</ScrollContainer> </ScrollContainer>
</PanelContainer> </PanelContainer>

View File

@@ -44,8 +44,11 @@ namespace Content.Client.Paper.UI
/// Initialize this UI according to <code>visuals</code> Initializes /// Initialize this UI according to <code>visuals</code> Initializes
/// textures, recalculates sizes, and applies some layout rules. /// textures, recalculates sizes, and applies some layout rules.
/// </summary> /// </summary>
public void InitVisuals(PaperVisualsComponent visuals) public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals)
{ {
// Randomize the placement of any stamps based on the entity UID
// so that there's some variety in different papers.
StampDisplay.PlacementSeed = (int)entity;
var resCache = IoCManager.Resolve<IResourceCache>(); var resCache = IoCManager.Resolve<IResourceCache>();
// Initialize the background: // Initialize the background:
@@ -206,9 +209,10 @@ namespace Content.Client.Paper.UI
BlankPaperIndicator.Visible = !isEditing && state.Text.Length == 0; BlankPaperIndicator.Visible = !isEditing && state.Text.Length == 0;
StampDisplay.RemoveAllChildren(); StampDisplay.RemoveAllChildren();
StampDisplay.RemoveStamps();
foreach(var stamper in state.StampedBy) foreach(var stamper in state.StampedBy)
{ {
StampDisplay.AddChild(new StampWidget{ Stamper = stamper }); StampDisplay.AddStamp(new StampWidget{ StampInfo = stamper });
} }
} }
@@ -220,7 +224,7 @@ namespace Content.Client.Paper.UI
/// </summary> /// </summary>
protected override DragMode GetDragModeFor(Vector2 relativeMousePos) protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
{ {
var mode = DragMode.Move; var mode = DragMode.None;
// Be quite generous with resize margins: // Be quite generous with resize margins:
if (relativeMousePos.Y < DRAG_MARGIN_SIZE) if (relativeMousePos.Y < DRAG_MARGIN_SIZE)
@@ -241,6 +245,10 @@ namespace Content.Client.Paper.UI
mode |= DragMode.Right; mode |= DragMode.Right;
} }
if((mode & _allowedResizeModes) == DragMode.None)
{
return DragMode.Move;
}
return mode & _allowedResizeModes; return mode & _allowedResizeModes;
} }
} }

View File

@@ -0,0 +1,5 @@
<paper:StampCollection xmlns="https://spacestation14.io"
xmlns:paper="clr-namespace:Content.Client.Paper.UI"
MinSize="150 150">
</paper:StampCollection>

View File

@@ -0,0 +1,98 @@
using System.Numerics;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Random;
namespace Content.Client.Paper.UI;
[GenerateTypedNameReferences]
public sealed partial class StampCollection : Container
{
private List<StampWidget> _stamps = new();
/// Seed for random number generator to place stamps deterministically
public int PlacementSeed;
public StampCollection()
{
RobustXamlLoader.Load(this);
}
/// <summary>
/// Remove any stamps from the page
/// </summary>
public void RemoveStamps()
{
_stamps.Clear();
InvalidateArrange();
}
/// <summary>
/// Adds a stamp to the display; will perform
/// automatic layout.
/// </summary>
public void AddStamp(StampWidget s)
{
_stamps.Add(s);
AddChild(s);
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var random = new Random(PlacementSeed);
var r = (finalSize * 0.5f).Length();
var dtheta = -MathHelper.DegreesToRadians(90);
var theta0 = random.Next(0, 3) * dtheta;
var thisCenter = PixelSizeBox.TopLeft + finalSize * UIScale * 0.5f;
// Here's where we lay out the stamps. The first stamp goes in the
// center of this container; subsequent stamps will chose an angle
// (theta) to place the center of the stamp. The stamp is moved out
// as far as it can in that direction, taking the size and
// orientation of the stamp into account.
for (var i = 0; i < _stamps.Count; i++)
{
var stampOrientation = MathHelper.DegreesToRadians((random.NextFloat() - 0.5f) * 10.0f) ;
_stamps[i].Orientation = stampOrientation;
var theta = theta0 + dtheta * 0.5f + dtheta * i + (i > 4 ? MathF.Log(1 + i / 4) * dtheta : 0); // There is probably a better way to lay these out, to minimize overlaps
var childCenterOnCircle = thisCenter;
if (i > 0)
{
// First stamp can go in the center. Subsequent stamps have to find space.
childCenterOnCircle += new Vector2(MathF.Cos(theta), MathF.Sin(theta)) * r * UIScale;
}
var childHeLocal = _stamps[i].DesiredPixelSize * 0.5f;
var c = childHeLocal * MathF.Abs(MathF.Cos(stampOrientation));
var s = childHeLocal * MathF.Abs(MathF.Sin(stampOrientation));
var childHePage = new Vector2(c.X + s.Y, s.X + c.Y);
var controlBox = new UIBox2(PixelSizeBox.TopLeft, PixelSizeBox.TopLeft + finalSize * UIScale);
var clampedCenter = Clamp(Shrink(controlBox, childHePage), childCenterOnCircle);
var finalPosition = clampedCenter - childHePage;
var finalPositionAsInt = new Vector2i((int)finalPosition.X, (int)finalPosition.Y);
_stamps[i].ArrangePixel(new UIBox2i(finalPositionAsInt, finalPositionAsInt + _stamps[i].DesiredPixelSize));
}
return finalSize;
}
/// <summary>
/// Shrink a UIBox2 by a half extents, moving both the top-left and
/// bottom-right closer together.
/// </summary>
private UIBox2 Shrink(UIBox2 box, Vector2 shrinkHe)
{
return new UIBox2(box.TopLeft + shrinkHe, box.BottomRight - shrinkHe);
}
/// <summary>
/// Returns the input vector clamped to be within the UIBox
/// </summary>
private Vector2 Clamp(UIBox2 box, Vector2 point)
{
return Vector2.Min(box.BottomRight, Vector2.Max(box.TopLeft, point));
}
}

View File

@@ -0,0 +1,2 @@
<paper:StampLabel xmlns="https://spacestation14.io"
xmlns:paper="clr-namespace:Content.Client.Paper.UI" />

View File

@@ -0,0 +1,56 @@
using System.Numerics;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Paper.UI;
[GenerateTypedNameReferences]
public sealed partial class StampLabel : Label
{
/// A scale that's applied to the text to ensure it
/// fits in the allowed space.
private Vector2 _textScaling = Vector2.One;
/// Shader used to draw the stamps
private ShaderInstance? _stampShader;
/// Allows an additional orientation to be applied to
/// this control.
public float Orientation = 0.0f;
public StampLabel()
{
RobustXamlLoader.Load(this);
var prototypes = IoCManager.Resolve<IPrototypeManager>();
_stampShader = prototypes.Index<ShaderPrototype>("PaperStamp").InstanceUnique();
}
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var desiredTextSize = base.MeasureOverride(availableSize);
var clampedScale = Vector2.Min(availableSize / desiredTextSize, Vector2.One);
var keepAspectRatio = MathF.Min(clampedScale.X, clampedScale.Y);
const float shimmerReduction = 0.1f;
_textScaling = Vector2.One * MathF.Round(keepAspectRatio / shimmerReduction) * shimmerReduction;
return desiredTextSize;
}
protected override void Draw(DrawingHandleScreen handle)
{
var offset = new Vector2(PixelPosition.X * MathF.Cos(Orientation) - PixelPosition.Y * MathF.Sin(Orientation),
PixelPosition.Y * MathF.Cos(Orientation) + PixelPosition.X * MathF.Sin(Orientation));
_stampShader?.SetParameter("objCoord", GlobalPosition * UIScale * new Vector2(1, -1));
handle.UseShader(_stampShader);
handle.SetTransform(GlobalPixelPosition - PixelPosition + offset, Orientation, _textScaling);
base.Draw(handle);
// Restore a sane transform+shader
handle.SetTransform(Matrix3.Identity);
handle.UseShader(null);
}
}

View File

@@ -4,22 +4,7 @@
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client" xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:paper="clr-namespace:Content.Client.Paper.UI" HorizontalAlignment="Center" Margin="6"> xmlns:paper="clr-namespace:Content.Client.Paper.UI" HorizontalAlignment="Center" Margin="6">
<BoxContainer Orientation="Vertical"> <paper:StampLabel Name="StampedByLabel" StyleClasses="LabelHeadingBigger"
<PanelContainer> FontColorOverride="{x:Static style:StyleNano.DangerousRedFore}"
<PanelContainer.PanelOverride> Margin="12 6 12 6"/>
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.DangerousRedFore}" />
</PanelContainer.PanelOverride>
<Control MinSize="3 3" />
</PanelContainer>
<Label Name="StampedByLabel" StyleClasses="LabelHeadingBigger" FontColorOverride="{x:Static style:StyleNano.DangerousRedFore}" Margin="12 6 12 6"/>
<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.DangerousRedFore}" />
</PanelContainer.PanelOverride>
<Control MinSize="3 3" />
</PanelContainer>
</BoxContainer>
</paper:StampWidget> </paper:StampWidget>

View File

@@ -1,23 +1,59 @@
using System.Numerics;
using Content.Shared.Paper; using Content.Shared.Paper;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility; using Robust.Shared.Prototypes;
namespace Content.Client.Paper.UI namespace Content.Client.Paper.UI;
[GenerateTypedNameReferences]
public sealed partial class StampWidget : PanelContainer
{ {
[GenerateTypedNameReferences] private StyleBoxTexture _borderTexture;
public sealed partial class StampWidget : Container private ShaderInstance? _stampShader;
{
public string? Stamper {
get => StampedByLabel.Text;
set => StampedByLabel.Text = value;
}
public StampWidget() public float Orientation
{ {
RobustXamlLoader.Load(this); get => StampedByLabel.Orientation;
set => StampedByLabel.Orientation = value;
}
public StampDisplayInfo StampInfo {
set {
StampedByLabel.Text = Loc.GetString(value.StampedName);
StampedByLabel.FontColorOverride = value.StampedColor;
ModulateSelfOverride = value.StampedColor;
} }
} }
public StampWidget()
{
RobustXamlLoader.Load(this);
var resCache = IoCManager.Resolve<IResourceCache>();
var borderImage = resCache.GetResource<TextureResource>(
"/Textures/Interface/Paper/paper_stamp_border.svg.96dpi.png");
_borderTexture = new StyleBoxTexture {
Texture = borderImage,
};
_borderTexture.SetPatchMargin(StyleBoxTexture.Margin.All, 7.0f);
PanelOverride = _borderTexture;
var prototypes = IoCManager.Resolve<IPrototypeManager>();
_stampShader = prototypes.Index<ShaderPrototype>("PaperStamp").InstanceUnique();
}
protected override void Draw(DrawingHandleScreen handle)
{
_stampShader?.SetParameter("objCoord", GlobalPosition * UIScale * new Vector2(1, -1));
handle.UseShader(_stampShader);
handle.SetTransform(GlobalPosition * UIScale, Orientation, Vector2.One);
base.Draw(handle);
// Restore a sane transform+shader
handle.SetTransform(Matrix3.Identity);
handle.UseShader(null);
}
} }

View File

@@ -1,9 +1,10 @@
using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Components;
using Content.Server.EUI; using Content.Server.EUI;
using Content.Server.Ghost.Components; using Content.Server.Ghost.Components;
using Content.Shared.Eui; using Content.Shared.Eui;
using Content.Shared.Fax; using Content.Shared.Fax;
using Content.Shared.Follower; using Content.Shared.Follower;
using Content.Shared.Paper;
namespace Content.Server.Fax.AdminUI; namespace Content.Server.Fax.AdminUI;
@@ -53,7 +54,8 @@ public sealed class AdminFaxEui : BaseEui
} }
case AdminFaxEuiMsg.Send sendData: case AdminFaxEuiMsg.Send sendData:
{ {
var printout = new FaxPrintout(sendData.Content, sendData.Title, null, sendData.StampState, new() { sendData.From }); var printout = new FaxPrintout(sendData.Content, sendData.Title, null, sendData.StampState,
new() { new StampDisplayInfo { StampedName = sendData.From, StampedColor = sendData.StampColor } });
_faxSystem.Receive(sendData.Target, printout); _faxSystem.Receive(sendData.Target, printout);
break; break;
} }

View File

@@ -1,4 +1,5 @@
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.Paper;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -136,18 +137,18 @@ public sealed class FaxPrintout
public string? StampState { get; } public string? StampState { get; }
[DataField("stampedBy")] [DataField("stampedBy")]
public List<string> StampedBy { get; } = new(); public List<StampDisplayInfo> StampedBy { get; } = new();
private FaxPrintout() private FaxPrintout()
{ {
} }
public FaxPrintout(string content, string name, string? prototypeId = null, string? stampState = null, List<string>? stampedBy = null) public FaxPrintout(string content, string name, string? prototypeId = null, string? stampState = null, List<StampDisplayInfo>? stampedBy = null)
{ {
Content = content; Content = content;
Name = name; Name = name;
PrototypeId = prototypeId ?? ""; PrototypeId = prototypeId ?? "";
StampState = stampState; StampState = stampState;
StampedBy = stampedBy ?? new List<string>(); StampedBy = stampedBy ?? new List<StampDisplayInfo>();
} }
} }

View File

@@ -16,6 +16,7 @@ using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems; using Content.Shared.Emag.Systems;
using Content.Shared.Fax; using Content.Shared.Fax;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Paper;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -272,7 +273,7 @@ public sealed class FaxSystem : EntitySystem
return; return;
args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState); args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState);
args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List<string>? stampedBy); args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List<StampDisplayInfo>? stampedBy);
args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId); args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId);
var printout = new FaxPrintout(content, name, prototypeId, stampState, stampedBy); var printout = new FaxPrintout(content, name, prototypeId, stampState, stampedBy);
@@ -461,9 +462,9 @@ public sealed class FaxSystem : EntitySystem
// Apply stamps // Apply stamps
if (printout.StampState != null) if (printout.StampState != null)
{ {
foreach (var stampedBy in printout.StampedBy) foreach (var stamp in printout.StampedBy)
{ {
_paperSystem.TryStamp(printed, stampedBy, printout.StampState); _paperSystem.TryStamp(printed, stamp, printout.StampState);
} }
} }
} }

View File

@@ -5,6 +5,7 @@ using Content.Server.Fax;
using Content.Server.Paper; using Content.Server.Paper;
using Content.Server.Station.Components; using Content.Server.Station.Components;
using Content.Server.Station.Systems; using Content.Server.Station.Systems;
using Content.Shared.Paper;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -66,7 +67,11 @@ namespace Content.Server.Nuke
Loc.GetString("nuke-codes-fax-paper-name"), Loc.GetString("nuke-codes-fax-paper-name"),
null, null,
"paper_stamp-centcom", "paper_stamp-centcom",
new() { Loc.GetString("stamp-component-stamped-name-centcom") }); new List<StampDisplayInfo>
{
new StampDisplayInfo { StampedName = Loc.GetString("stamp-component-stamped-name-centcom"), StampedColor = Color.FromHex("#BB3232") },
}
);
_faxSystem.Receive(faxEnt, printout, null, fax); _faxSystem.Receive(faxEnt, printout, null, fax);
wasSent = true; wasSent = true;

View File

@@ -1,24 +1,24 @@
using Content.Shared.Paper; using Content.Shared.Paper;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
namespace Content.Server.Paper namespace Content.Server.Paper;
[NetworkedComponent, RegisterComponent]
public sealed class PaperComponent : SharedPaperComponent
{ {
[NetworkedComponent, RegisterComponent] public PaperAction Mode;
public sealed class PaperComponent : SharedPaperComponent [DataField("content")]
{ public string Content { get; set; } = "";
public PaperAction Mode;
[DataField("content")]
public string Content { get; set; } = "";
[DataField("contentSize")] [DataField("contentSize")]
public int ContentSize { get; set; } = 6000; public int ContentSize { get; set; } = 6000;
[DataField("stampedBy")] [DataField("stampedBy")]
public List<string> StampedBy { get; set; } = new(); public List<StampDisplayInfo> StampedBy { get; set; } = new();
/// <summary>
/// Stamp to be displayed on the paper, state from beauracracy.rsi /// <summary>
/// </summary> /// Stamp to be displayed on the paper, state from beauracracy.rsi
[DataField("stampState")] /// </summary>
public string? StampState { get; set; } [DataField("stampState")]
} public string? StampState { get; set; }
} }

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.UserInterface; using Content.Server.UserInterface;
@@ -90,7 +91,7 @@ namespace Content.Server.Paper
if (paperComp.StampedBy.Count > 0) if (paperComp.StampedBy.Count > 0)
{ {
var commaSeparated = string.Join(", ", paperComp.StampedBy); var commaSeparated = string.Join(", ", paperComp.StampedBy.Select(s => Loc.GetString(s.StampedName)));
args.PushMarkup( args.PushMarkup(
Loc.GetString( Loc.GetString(
"paper-component-examine-detail-stamped-by", ("paper", uid), ("stamps", commaSeparated)) "paper-component-examine-detail-stamped-by", ("paper", uid), ("stamps", commaSeparated))
@@ -114,13 +115,15 @@ namespace Content.Server.Paper
} }
// If a stamp, attempt to stamp paper // If a stamp, attempt to stamp paper
if (TryComp<StampComponent>(args.Used, out var stampComp) && TryStamp(uid, stampComp.StampedName, stampComp.StampState, paperComp)) if (TryComp<StampComponent>(args.Used, out var stampComp) && TryStamp(uid, GetStampInfo(stampComp), stampComp.StampState, paperComp))
{ {
// successfully stamped, play popup // successfully stamped, play popup
var stampPaperOtherMessage = Loc.GetString("paper-component-action-stamp-paper-other", ("user", Identity.Entity(args.User, EntityManager)), ("target", Identity.Entity(args.Target, EntityManager)), ("stamp", args.Used)); var stampPaperOtherMessage = Loc.GetString("paper-component-action-stamp-paper-other",
_popupSystem.PopupEntity(stampPaperOtherMessage, args.User, Filter.PvsExcept(args.User, entityManager: EntityManager), true); ("user", args.User), ("target", args.Target), ("stamp", args.Used));
var stampPaperSelfMessage = Loc.GetString("paper-component-action-stamp-paper-self", ("target", Identity.Entity(args.Target, EntityManager)), ("stamp", args.Used)); _popupSystem.PopupEntity(stampPaperOtherMessage, args.User, Filter.PvsExcept(args.User, entityManager: EntityManager), true);
var stampPaperSelfMessage = Loc.GetString("paper-component-action-stamp-paper-self",
("target", args.Target), ("stamp", args.Used));
_popupSystem.PopupEntity(stampPaperSelfMessage, args.User, args.User); _popupSystem.PopupEntity(stampPaperSelfMessage, args.User, args.User);
_audio.PlayPvs(stampComp.Sound, uid); _audio.PlayPvs(stampComp.Sound, uid);
@@ -129,6 +132,14 @@ namespace Content.Server.Paper
} }
} }
private StampDisplayInfo GetStampInfo(StampComponent stamp)
{
return new StampDisplayInfo {
StampedName = stamp.StampedName,
StampedColor = stamp.StampedColor
};
}
private void OnInputTextMessage(EntityUid uid, PaperComponent paperComp, PaperInputTextMessage args) private void OnInputTextMessage(EntityUid uid, PaperComponent paperComp, PaperInputTextMessage args)
{ {
if (string.IsNullOrEmpty(args.Text)) if (string.IsNullOrEmpty(args.Text))
@@ -161,17 +172,19 @@ namespace Content.Server.Paper
/// <summary> /// <summary>
/// Accepts the name and state to be stamped onto the paper, returns true if successful. /// Accepts the name and state to be stamped onto the paper, returns true if successful.
/// </summary> /// </summary>
public bool TryStamp(EntityUid uid, string stampName, string stampState, PaperComponent? paperComp = null) public bool TryStamp(EntityUid uid, StampDisplayInfo stampInfo, string spriteStampState, PaperComponent? paperComp = null)
{ {
if (!Resolve(uid, ref paperComp)) if (!Resolve(uid, ref paperComp))
return false; return false;
if (!paperComp.StampedBy.Contains(Loc.GetString(stampName))) if (!paperComp.StampedBy.Contains(stampInfo))
{ {
paperComp.StampedBy.Add(Loc.GetString(stampName)); paperComp.StampedBy.Add(stampInfo);
if (paperComp.StampState == null && TryComp<AppearanceComponent>(uid, out var appearance)) if (paperComp.StampState == null && TryComp<AppearanceComponent>(uid, out var appearance))
{ {
paperComp.StampState = stampState; paperComp.StampState = spriteStampState;
// Would be nice to be able to display multiple sprites on the paper
// but most of the existing images overlap
_appearance.SetData(uid, PaperVisuals.Stamp, paperComp.StampState, appearance); _appearance.SetData(uid, PaperVisuals.Stamp, paperComp.StampState, appearance);
} }
} }

View File

@@ -1,4 +1,4 @@
using Content.Shared.Eui; using Content.Shared.Eui;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Fax; namespace Content.Shared.Fax;
@@ -55,14 +55,16 @@ public static class AdminFaxEuiMsg
public string From { get; } public string From { get; }
public string Content { get; } public string Content { get; }
public string StampState { get; } public string StampState { get; }
public Color StampColor { get; }
public Send(EntityUid target, string title, string from, string content, string stamp) public Send(EntityUid target, string title, string from, string content, string stamp, Color stampColor)
{ {
Target = target; Target = target;
Title = title; Title = title;
From = from; From = from;
Content = content; Content = content;
StampState = stamp; StampState = stamp;
StampColor = stampColor;
} }
} }
} }

View File

@@ -1,60 +1,59 @@
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Paper namespace Content.Shared.Paper;
public abstract class SharedPaperComponent : Component
{ {
public abstract class SharedPaperComponent : Component [Serializable, NetSerializable]
public sealed class PaperBoundUserInterfaceState : BoundUserInterfaceState
{ {
[Serializable, NetSerializable] public readonly string Text;
public sealed class PaperBoundUserInterfaceState : BoundUserInterfaceState public readonly List<StampDisplayInfo> StampedBy;
public readonly PaperAction Mode;
public PaperBoundUserInterfaceState(string text, List<StampDisplayInfo> stampedBy, PaperAction mode = PaperAction.Read)
{ {
public readonly string Text; Text = text;
public readonly List<string> StampedBy; StampedBy = stampedBy;
public readonly PaperAction Mode; Mode = mode;
public PaperBoundUserInterfaceState(string text, List<string> stampedBy, PaperAction mode = PaperAction.Read)
{
Text = text;
StampedBy = stampedBy;
Mode = mode;
}
}
[Serializable, NetSerializable]
public sealed class PaperInputTextMessage : BoundUserInterfaceMessage
{
public readonly string Text;
public PaperInputTextMessage(string text)
{
Text = text;
}
}
[Serializable, NetSerializable]
public enum PaperUiKey
{
Key
}
[Serializable, NetSerializable]
public enum PaperAction
{
Read,
Write,
}
[Serializable, NetSerializable]
public enum PaperVisuals : byte
{
Status,
Stamp
}
[Serializable, NetSerializable]
public enum PaperStatus : byte
{
Blank,
Written
} }
} }
[Serializable, NetSerializable]
public sealed class PaperInputTextMessage : BoundUserInterfaceMessage
{
public readonly string Text;
public PaperInputTextMessage(string text)
{
Text = text;
}
}
[Serializable, NetSerializable]
public enum PaperUiKey
{
Key
}
[Serializable, NetSerializable]
public enum PaperAction
{
Read,
Write,
}
[Serializable, NetSerializable]
public enum PaperVisuals : byte
{
Status,
Stamp
}
[Serializable, NetSerializable]
public enum PaperStatus : byte
{
Blank,
Written
}
} }

View File

@@ -1,25 +1,52 @@
using Robust.Shared.Serialization;
using Robust.Shared.Audio; using Robust.Shared.Audio;
namespace Content.Shared.Paper namespace Content.Shared.Paper;
{
[RegisterComponent]
public sealed class StampComponent : Component
{
/// <summary>
/// The loc string name that will be stamped to the piece of paper on examine.
/// </summary>
[DataField("stampedName")]
public string StampedName { get; set; } = "stamp-component-stamped-name-default";
/// <summary>
/// Tne sprite state of the stamp to display on the paper from bureacracy.rsi.
/// </summary>
[DataField("stampState")]
public string StampState { get; set; } = "paper_stamp-generic";
[DataField("sound")] /// <summary>
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Items/Stamp/thick_stamp_sub.ogg") /// Set of required information to draw a stamp in UIs, where
{ /// representing the state of the stamp at the point in time
Params = AudioParams.Default.WithVolume(-2f).WithMaxDistance(5f) /// when it was applied to a paper. These fields mirror the
}; /// equivalent in the component.
/// </summary>
[DataDefinition, Serializable, NetSerializable]
public struct StampDisplayInfo
{
StampDisplayInfo(string s)
{
StampedName = s;
} }
[DataField("stampedName")]
public string StampedName;
[DataField("stampedColor")]
public Color StampedColor;
};
[RegisterComponent]
public sealed class StampComponent : Component
{
/// <summary>
/// The loc string name that will be stamped to the piece of paper on examine.
/// </summary>
[DataField("stampedName")]
public string StampedName { get; set; } = "stamp-component-stamped-name-default";
/// <summary>
/// Tne sprite state of the stamp to display on the paper from bureacracy.rsi.
/// </summary>
[DataField("stampState")]
public string StampState { get; set; } = "paper_stamp-generic";
/// <summary>
/// The color of the ink used by the stamp in UIs
/// </summary>
[DataField("stampedColor")]
public Color StampedColor = Color.FromHex("#BB3232"); // StyleNano.DangerousRedFore
[DataField("sound")]
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Items/Stamp/thick_stamp_sub.ogg")
{
Params = AudioParams.Default.WithVolume(-2f).WithMaxDistance(5f)
};
} }

View File

@@ -1,4 +1,4 @@
# Command # Command
cmd-faxui-desc = Open admin window for sending faxes cmd-faxui-desc = Open admin window for sending faxes
cmd-faxui-help = Usage: faxui cmd-faxui-help = Usage: faxui
@@ -7,7 +7,8 @@ admin-fax-title = Admin Fax Manager
admin-fax-fax = Fax: admin-fax-fax = Fax:
admin-fax-follow = Follow admin-fax-follow = Follow
admin-fax-title-placeholder = Paper name... admin-fax-title-placeholder = Paper name...
admin-fax-from-placeholder = From who... admin-fax-from-placeholder = Stamped by...
admin-fax-message-placeholder = Your message here... admin-fax-message-placeholder = Your message here...
admin-fax-stamp = Stamp: admin-fax-stamp = Stamp icon:
admin-fax-stamp-color = Stamp color:
admin-fax-send = Send admin-fax-send = Send

View File

@@ -91310,7 +91310,8 @@ entities:
type: Transform type: Transform
- stampState: paper_stamp-syndicate - stampState: paper_stamp-syndicate
stampedBy: stampedBy:
- Syndicate - stampedName: stamp-component-stamped-name-syndicate
stampedColor: '#850000'
content: >- content: >-
Operative, i have succeeded in the mission and this is the remainder of the evidence. I am hiding it behind this wall and escaping ASAP. Operative, i have succeeded in the mission and this is the remainder of the evidence. I am hiding it behind this wall and escaping ASAP.

View File

@@ -421,6 +421,7 @@
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-default stampedName: stamp-component-stamped-name-default
stampState: "paper_stamp-generic" stampState: "paper_stamp-generic"
stampedColor: "#a23e3e"
sound: sound:
path: /Audio/Items/Stamp/thick_stamp_sub.ogg path: /Audio/Items/Stamp/thick_stamp_sub.ogg
params: params:
@@ -454,6 +455,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-captain stampedName: stamp-component-stamped-name-captain
stampedColor: "#3681bb"
stampState: "paper_stamp-cap" stampState: "paper_stamp-cap"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -466,6 +468,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-centcom stampedName: stamp-component-stamped-name-centcom
stampedColor: "#006600"
stampState: "paper_stamp-centcom" stampState: "paper_stamp-centcom"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -478,6 +481,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-chaplain stampedName: stamp-component-stamped-name-chaplain
stampedColor: "#d70601"
stampState: "paper_stamp-chaplain" stampState: "paper_stamp-chaplain"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -490,6 +494,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-clown stampedName: stamp-component-stamped-name-clown
stampedColor: "#ff33cc"
stampState: "paper_stamp-clown" stampState: "paper_stamp-clown"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -505,6 +510,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-ce stampedName: stamp-component-stamped-name-ce
stampedColor: "#c69b17"
stampState: "paper_stamp-ce" stampState: "paper_stamp-ce"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -517,6 +523,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-cmo stampedName: stamp-component-stamped-name-cmo
stampedColor: "#33ccff"
stampState: "paper_stamp-cmo" stampState: "paper_stamp-cmo"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -529,6 +536,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-hop stampedName: stamp-component-stamped-name-hop
stampedColor: "#6ec0ea"
stampState: "paper_stamp-hop" stampState: "paper_stamp-hop"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -541,6 +549,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-hos stampedName: stamp-component-stamped-name-hos
stampedColor: "#cc0000"
stampState: "paper_stamp-hos" stampState: "paper_stamp-hos"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -553,6 +562,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-mime stampedName: stamp-component-stamped-name-mime
stampedColor: "#777777"
stampState: "paper_stamp-mime" stampState: "paper_stamp-mime"
# TODO remove sound from mime's rubber stamp # TODO remove sound from mime's rubber stamp
- type: Sprite - type: Sprite
@@ -566,6 +576,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-qm stampedName: stamp-component-stamped-name-qm
stampedColor: "#a23e3e"
stampState: "paper_stamp-qm" stampState: "paper_stamp-qm"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -578,6 +589,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-rd stampedName: stamp-component-stamped-name-rd
stampedColor: "#1f66a0"
stampState: "paper_stamp-rd" stampState: "paper_stamp-rd"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -590,6 +602,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-trader stampedName: stamp-component-stamped-name-trader
stampedColor: "#000000"
stampState: "paper_stamp-trader" stampState: "paper_stamp-trader"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -602,6 +615,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-syndicate stampedName: stamp-component-stamped-name-syndicate
stampedColor: "#850000"
stampState: "paper_stamp-syndicate" stampState: "paper_stamp-syndicate"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -614,6 +628,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-warden stampedName: stamp-component-stamped-name-warden
stampedColor: "#5b0000"
stampState: "paper_stamp-warden" stampState: "paper_stamp-warden"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -626,6 +641,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-approved stampedName: stamp-component-stamped-name-approved
stampedColor: "#00be00"
stampState: "paper_stamp-ok" stampState: "paper_stamp-ok"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi
@@ -638,6 +654,7 @@
components: components:
- type: Stamp - type: Stamp
stampedName: stamp-component-stamped-name-denied stampedName: stamp-component-stamped-name-denied
stampedColor: "#a23e3e"
stampState: "paper_stamp-deny" stampState: "paper_stamp-deny"
- type: Sprite - type: Sprite
sprite: Objects/Misc/bureaucracy.rsi sprite: Objects/Misc/bureaucracy.rsi

View File

@@ -71,3 +71,8 @@
id: Stealth id: Stealth
kind: source kind: source
path: "/Textures/Shaders/stealth.swsl" path: "/Textures/Shaders/stealth.swsl"
- type: shader
id: PaperStamp
kind: source
path: "/Textures/Shaders/paperstamp.swsl"

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="35.0625"
height="34"
viewBox="0 0 35.0625 34"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="paper_stamp_border.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
inkscape:export-filename="paper_stamp_border.svg.96dpi.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8">
<inkscape:path-effect
effect="powerclip"
id="path-effect302"
is_visible="true"
lpeversion="1"
inverse="true"
flatten="false"
hide_clip="false"
message="Use fill-rule evenodd on &lt;b&gt;fill and stroke&lt;/b&gt; dialog if no flatten result after convert clip to paths." />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath298">
<rect
x="2.6084003"
y="2.5943766"
width="26.783199"
height="26.811247"
rx="4.1848745"
fill="#ffffff"
id="rect300"
style="display:none;stroke-width:0.837413"
d="M 6.7932749,2.5943766 H 25.206725 c 2.318421,0 4.184875,1.866454 4.184875,4.1848745 V 25.220749 c 0,2.31842 -1.866454,4.184874 -4.184875,4.184874 H 6.7932749 c -2.3184205,0 -4.1848746,-1.866454 -4.1848746,-4.184874 V 6.7792511 c 0,-2.3184205 1.8664541,-4.1848745 4.1848746,-4.1848745 z" />
<path
id="lpe_path-effect302"
style="stroke-width:0.837413"
class="powerclip"
d="M -5,-5 H 37 V 37 H -5 Z M 6.7932749,2.5943766 c -2.3184205,0 -4.1848746,1.866454 -4.1848746,4.1848745 V 25.220749 c 0,2.31842 1.8664541,4.184874 4.1848746,4.184874 H 25.206725 c 2.318421,0 4.184875,-1.866454 4.184875,-4.184874 V 6.7792511 c 0,-2.3184205 -1.866454,-4.1848745 -4.184875,-4.1848745 z" />
</clipPath>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1916"
inkscape:window-height="1034"
id="namedview6"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="15.527471"
inkscape:cx="6.7300077"
inkscape:cy="17.16313"
inkscape:window-x="0"
inkscape:window-y="44"
inkscape:window-maximized="0"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1" />
<path
x="0"
y="0"
width="32"
height="32"
rx="5"
fill="#ffffff"
id="rect2"
clip-path="url(#clipPath298)"
inkscape:path-effect="#path-effect302"
d="m 5,0 h 22 c 2.77,0 5,2.23 5,5 v 22 c 0,2.77 -2.23,5 -5,5 H 5 C 2.23,32 0,29.77 0,27 V 5 C 0,2.23 2.23,0 5,0 Z"
sodipodi:type="rect"
transform="translate(1,1)" />
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

View File

@@ -0,0 +1,53 @@
// Object position in screen space. Allows the noise to
// have a constant screen-space size, without being
// affected by the widget layout/position.
uniform highp vec2 objCoord;
// Magic, well-known 2d random function; makes perlin-like noise
highp vec2 random(highp vec2 uv){
uv = vec2( dot(uv, vec2(127.1,311.7) ),
dot(uv, vec2(269.5,183.3) ) );
return -1.0 + 2.0 * fract(sin(uv) * 43758.5453123);
}
highp float noise(highp vec2 uv) {
highp vec2 uv_i = floor(uv);
highp vec2 uv_f = fract(uv);
highp vec2 t = smoothstep(0.0, 1.0, uv_f);
// Sample the random function and run a bilinear filter to smooth it out
highp float tl = dot( random(uv_i + vec2(0.0,0.0) ), uv_f - vec2(0.0,0.0) );
highp float tr = dot( random(uv_i + vec2(1.0,0.0) ), uv_f - vec2(1.0,0.0) );
highp float bl = dot( random(uv_i + vec2(0.0,1.0) ), uv_f - vec2(0.0,1.0) );
highp float br = dot( random(uv_i + vec2(1.0,1.0) ), uv_f - vec2(1.0,1.0) );
highp float tA = mix( tl, tr, t.x );
highp float tB = mix( bl, br, t.x );
return mix( tA, tB, t.y ) + 0.5;
}
void fragment() {
// Stamps have orientation, and the texture sampling is nearest
// pixel, so run a bilinear filter to smooth out the edges.
{
highp vec4 tl = texture2D(TEXTURE, UV);
highp vec4 tr = texture2D(TEXTURE, UV + vec2(TEXTURE_PIXEL_SIZE.x, 0.0));
highp vec4 bl = texture2D(TEXTURE, UV + vec2(0.0, TEXTURE_PIXEL_SIZE.y));
highp vec4 br = texture2D(TEXTURE, UV + TEXTURE_PIXEL_SIZE);
highp vec2 textureSize = 1.0 / TEXTURE_PIXEL_SIZE;
highp vec2 f = fract( UV * textureSize );
highp vec4 tA = mix( tl, tr, f.x );
highp vec4 tB = mix( bl, br, f.x );
COLOR = mix( tA, tB, f.y );
}
// Add a bit of noise to mimic imperfect contact with the paper
{
float stampNoise = noise((FRAGCOORD.xy - objCoord) * vec2(0.03, 0.03)) *
noise((FRAGCOORD.xy - objCoord) * vec2(0.08, 0.08));
COLOR.a *= min(0.9, 0.4 + smoothstep(0.05, 0.3, stampNoise));
}
}