_window.OnDecalColorChanged += OnDecalColorChanged;
_window.OnDecalAngleChanged += OnDecalAngleChanged;
_window.OnDecalSnapChanged += OnDecalSnapChanged;
+ _window.OnDecalColorPickerToggled += OnDecalColorPickerToggled;
}
var sprayPainter = EntMan.System<SprayPainterSystem>();
_window.SetDecalAngle(sprayPainter.SelectedDecalAngle);
_window.SetDecalColor(sprayPainter.SelectedDecalColor);
_window.SetDecalSnap(sprayPainter.SnapDecals);
+ _window.SetDecalColorPicker(sprayPainter.ColorPickerEnabled);
}
private void OnDecalSnapChanged(bool snap)
var key = _window?.IndexToColorKey(args.ItemIndex);
SendPredictedMessage(new SprayPainterSetPipeColorMessage(key));
}
+
+ private void OnDecalColorPickerToggled(bool toggle)
+ {
+ SendPredictedMessage(new SprayPainterSetDecalColorPickerMessage(toggle));
+ }
}
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.SprayPainter.UI">
<BoxContainer Orientation="Vertical">
- <Label Text="{Loc 'spray-painter-selected-decals'}" />
+ <BoxContainer>
+ <Label Text="{Loc 'spray-painter-selected-decals'}" />
+ <Label Name="SelectedDecalName" StyleClasses="Italic" Margin="4 0" />
+ </BoxContainer>
<ScrollContainer VerticalExpand="True">
<GridContainer Columns="7" Name="DecalsGrid">
<!-- populated by code -->
</GridContainer>
</ScrollContainer>
+ <PanelContainer StyleClasses="LowDivider" />
<BoxContainer Orientation="Vertical">
- <ColorSelectorSliders Name="ColorSelector" IsAlphaVisible="True" />
+ <ColorSelectorSliders Name="ColorSelector" IsAlphaVisible="True">
+ <BoxContainer HorizontalAlignment="Right" VerticalAlignment="Top" SetHeight="29">
+ <Button Name="ColorPalette" Text="Palette" />
+ <Button Name="ColorPicker" ToggleMode="True">
+ <TextureRect TexturePath="/Textures/Interface/eyedropper.svg.png" Stretch="KeepAspectCentered" SetSize="16 16" />
+ </Button>
+ </BoxContainer>
+ </ColorSelectorSliders>
<CheckBox Name="UseCustomColorCheckBox" Text="{Loc 'spray-painter-use-custom-color'}" />
<CheckBox Name="SnapToTileCheckBox" Text="{Loc 'spray-painter-use-snap-to-tile'}" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'spray-painter-angle-rotation'}" />
<SpinBox Name="AngleSpinBox" HorizontalExpand="True" />
- <Button Text="{Loc 'spray-painter-angle-rotation-90-sub'}" Name="SubAngleButton" />
+ <Button Name="AddAngleButton" ToolTip="{Loc 'spray-painter-angle-rotation-90-add'}" SetSize="48 32">
+ <TextureRect TexturePath="/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png" Stretch="KeepAspectCentered" SetSize="32 32" />
+ </Button>
<Button Text="{Loc 'spray-painter-angle-rotation-reset'}" Name="SetZeroAngleButton" />
- <Button Text="{Loc 'spray-painter-angle-rotation-90-add'}" Name="AddAngleButton" />
+ <Button Name="SubAngleButton" ToolTip="{Loc 'spray-painter-angle-rotation-90-sub'}" SetSize="48 32">
+ <TextureRect TexturePath="/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png" Stretch="KeepAspectCentered" SetSize="32 32" />
+ </Button>
</BoxContainer>
</BoxContainer>
</controls:SprayPainterDecals>
-using System.Numerics;
+using Content.Client.Decals.UI;
using Content.Client.Stylesheets;
using Content.Shared.Decals;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
+using System.Linq;
+using System.Numerics;
namespace Content.Client.SprayPainter.UI;
public Action<Color?>? OnColorChanged;
public Action<int>? OnAngleChanged;
public Action<bool>? OnSnapChanged;
+ public Action<bool>? OnColorPickerToggled;
+
+ private PaletteColorPicker? _palette;
private SpriteSystem? _sprite;
private string _selectedDecal = string.Empty;
{
RobustXamlLoader.Load(this);
- AddAngleButton.OnButtonUp += _ => AngleSpinBox.Value += 90;
- SubAngleButton.OnButtonUp += _ => AngleSpinBox.Value -= 90;
+ AddAngleButton.OnButtonUp += _ => AngleSpinBox.Value = (AngleSpinBox.Value + 90) % 360;
+ SubAngleButton.OnButtonUp += _ => AngleSpinBox.Value = (AngleSpinBox.Value - 90) % 360;
SetZeroAngleButton.OnButtonUp += _ => AngleSpinBox.Value = 0;
AngleSpinBox.ValueChanged += args => OnAngleChanged?.Invoke(args.Value);
UseCustomColorCheckBox.OnPressed += UseCustomColorCheckBoxOnOnPressed;
SnapToTileCheckBox.OnPressed += SnapToTileCheckBoxOnOnPressed;
ColorSelector.OnColorChanged += OnColorSelected;
+
+ ColorPalette.OnPressed += ColorPaletteOnPressed;
+ ColorPicker.OnPressed += args => OnColorPickerToggled?.Invoke(args.Button.Pressed);
}
private void UseCustomColorCheckBoxOnOnPressed(BaseButton.ButtonEventArgs _)
public void SetSelectedDecal(string name)
{
_selectedDecal = name;
+ SelectedDecalName.Text = name;
if (_sprite is null)
return;
{
SnapToTileCheckBox.Pressed = snap;
}
+
+ private void ColorPaletteOnPressed(BaseButton.ButtonEventArgs _)
+ {
+ // Code copied from other implementations of `PaletteColorPicker`.
+ if (_palette is null)
+ {
+ _palette = new PaletteColorPicker();
+ _palette.OpenCenteredLeft();
+ _palette.PaletteList.OnItemSelected += args =>
+ {
+ var color = (args.ItemList.GetSelected().First().Metadata as Color?)!.Value;
+ ColorSelector.Color = color;
+ OnColorSelected(color);
+ };
+ return;
+ }
+
+ if (_palette.IsOpen)
+ {
+ _palette.Close();
+ }
+ else
+ {
+ _palette.Open();
+ }
+ }
+
+ public void SetColorPicker(bool enabled)
+ {
+ ColorPicker.Pressed = enabled;
+ }
}
public event Action<Color?>? OnDecalColorChanged;
public event Action<int>? OnDecalAngleChanged;
public event Action<bool>? OnDecalSnapChanged;
+ public event Action<bool>? OnDecalColorPickerToggled;
// Pipe color data
private ItemList _colorList = default!;
_sprayPainterDecals.OnColorChanged += color => OnDecalColorChanged?.Invoke(color);
_sprayPainterDecals.OnAngleChanged += angle => OnDecalAngleChanged?.Invoke(angle);
_sprayPainterDecals.OnSnapChanged += snap => OnDecalSnapChanged?.Invoke(snap);
+ _sprayPainterDecals.OnColorPickerToggled += toggle => OnDecalColorPickerToggled?.Invoke(toggle);
Tabs.AddChild(_sprayPainterDecals);
TabContainer.SetTabTitle(_sprayPainterDecals, Loc.GetString("spray-painter-tab-category-decals"));
if (_sprayPainterDecals != null)
_sprayPainterDecals.SetSnap(snap);
}
- # endregion
+
+ public void SetDecalColorPicker(bool colorPickerEnabled)
+ {
+ _sprayPainterDecals?.SetColorPicker(colorPickerEnabled);
+ }
+ #endregion
}
public record SpriteListData(string Group, string Style, EntProtoId Prototype, int SelectedIndex) : ListData;
using Content.Shared.SprayPainter.Components;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
-using Robust.Shared.Prototypes;
+using System.Linq;
+using System.Numerics;
namespace Content.Server.SprayPainter;
/// </summary>
private void OnFloorAfterInteract(Entity<SprayPainterComponent> ent, ref AfterInteractEvent args)
{
- if (args.Handled || !args.CanReach || args.Target != null)
+ if (args.Handled || args.Target != null)
+ return;
+
+ if (ent.Comp.ColorPickerEnabled)
+ {
+ PickColor(ent, ref args);
+ return;
+ }
+
+ if (!args.CanReach)
return;
// Includes both off and all other don't cares
return;
}
- var decals = _decals.GetDecalsInRange(grid, position.Position, validDelegate: IsDecalRemovable);
+ var decals = _decals.GetDecalsInRange(grid, position.Position, validDelegate: IsDecalValid);
if (decals.Count <= 0)
{
_popup.PopupEntity(Loc.GetString("spray-painter-interact-nothing-to-remove"), args.User, args.User);
}
/// <summary>
- /// Handles drawing decals when a spray painter is used to interact with the floor.
- /// Spray painter must have decal painting enabled and enough charges of paint to paint on the floor.
+ /// Returns whether <paramref name="decal"/> is valid to interact with when a spray painter is used to interact with the floor.
/// </summary>
- private bool IsDecalRemovable(Decal decal)
+ private bool IsDecalValid(Decal decal)
{
if (!Proto.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
return false;
args.Handled = DoAfter.TryStartDoAfter(doAfterEventArgs);
}
+
+ private void PickColor(Entity<SprayPainterComponent> ent, ref AfterInteractEvent args)
+ {
+ if (!args.ClickLocation.IsValid(EntityManager) || _transform.GetGrid(args.ClickLocation) is not { } grid)
+ return;
+
+ var clickPos = args.ClickLocation.Position;
+ var decals = _decals.GetDecalsInRange(grid, clickPos, validDelegate: IsDecalValid);
+ if (decals.Count == 0)
+ {
+ _popup.PopupEntity(Loc.GetString("spray-painter-interact-no-color-pick"), args.User, args.User);
+ return;
+ }
+
+ var closestDecal = decals.MinBy(d => Vector2.Distance(d.Decal.Coordinates, clickPos)).Decal;
+
+ _popup.PopupEntity(Loc.GetString("spray-painter-interact-color-picked", ("id", closestDecal.Id)), args.User, args.User);
+
+ ent.Comp.SelectedDecalColor = closestDecal.Color;
+ ent.Comp.ColorPickerEnabled = false;
+ Dirty(ent);
+ }
}
/// </summary>
[DataField]
public SoundSpecifier SoundSwitchDecalMode = new SoundPathSpecifier("/Audio/Machines/quickbeep.ogg", AudioParams.Default.WithVolume(1.5f));
+
+ /// <summary>
+ /// Whether the decal color picker is currently active.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool ColorPickerEnabled = false;
}
/// <summary>
subs.Event<SprayPainterSetDecalColorMessage>(OnSetDecalColor);
subs.Event<SprayPainterSetDecalAngleMessage>(OnSetDecalAngle);
subs.Event<SprayPainterSetDecalSnapMessage>(OnSetDecalSnap);
+ subs.Event<SprayPainterSetDecalColorPickerMessage>(OnSetDecalColorPicker);
});
}
UpdateUi(ent);
}
+ /// <summary>
+ /// Enables or disables the decal colour picker.
+ /// </summary>
+ private void OnSetDecalColorPicker(Entity<SprayPainterComponent> ent, ref SprayPainterSetDecalColorPickerMessage args)
+ {
+ ent.Comp.ColorPickerEnabled = args.Toggle;
+ Dirty(ent);
+ UpdateUi(ent);
+ }
+
/// <summary>
/// Sets the decal to paint on the ground.
/// </summary>
public readonly string? Key = key;
}
+[Serializable, NetSerializable]
+public sealed class SprayPainterSetDecalColorPickerMessage(bool toggle) : BoundUserInterfaceMessage
+{
+ public bool Toggle = toggle;
+}
+
[Serializable, NetSerializable]
public sealed partial class SprayPainterDoAfterEvent : DoAfterEvent
{
spray-painter-interact-no-charges = Not enough paint left.
spray-painter-interact-nothing-to-remove = Nothing to remove!
+spray-painter-interact-no-color-pick = Can't find a color to pick!
+spray-painter-interact-color-picked = Picked color from '{$id}'.
spray-painter-on-examined-painted-message = It seems to have been freshly painted.
spray-painter-style-not-available = Cannot apply the selected style to this object.