Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions DMCompiler/DMStandard/Defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@
//see mouse handling
#define MOUSE_INACTIVE_POINTER 0
#define MOUSE_ACTIVE_POINTER 1
#define MOUSE_DRAG_POINTER 2
#define MOUSE_DROP_POINTER 3
#define MOUSE_ARROW_POINTER 4
#define MOUSE_CROSSHAIRS_POINTER 5
#define MOUSE_HAND_POINTER 6
#define MOUSE_DRAG_POINTER 3
#define MOUSE_DROP_POINTER 4
#define MOUSE_ARROW_POINTER 5
#define MOUSE_CROSSHAIRS_POINTER 6
#define MOUSE_HAND_POINTER 7

//client.control_freak
#define CONTROL_FREAK_ALL (1<<0)
Expand Down
6 changes: 3 additions & 3 deletions DMCompiler/DMStandard/Types/Atoms/_Atom.dm
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@
var/step_x as opendream_unimplemented
var/step_y as opendream_unimplemented
var/render_source
var/tmp/mouse_drag_pointer as opendream_unimplemented
var/tmp/mouse_drop_pointer as opendream_unimplemented
var/tmp/mouse_over_pointer as opendream_unimplemented
var/tmp/mouse_drag_pointer
var/tmp/mouse_drop_pointer
var/tmp/mouse_over_pointer
var/render_target
var/vis_flags as opendream_unimplemented

Expand Down
2 changes: 1 addition & 1 deletion DMCompiler/DMStandard/Types/Client.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
var/script as opendream_unimplemented
var/color = 0 as opendream_unimplemented
var/control_freak as opendream_unimplemented
var/mouse_pointer_icon as opendream_unimplemented
var/mouse_pointer_icon
var/preload_rsc = 1 as opendream_unimplemented
var/fps = 0 as opendream_unimplemented
var/dir = NORTH as opendream_unimplemented
Expand Down
8 changes: 4 additions & 4 deletions DMCompiler/DMStandard/Types/Image.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
var/maptext_height = 32
var/maptext_x = 0
var/maptext_y = 0
var/mouse_over_pointer = 0 as opendream_unimplemented
var/mouse_drag_pointer = 0 as opendream_unimplemented
var/mouse_drop_pointer = 1 as opendream_unimplemented
var/mouse_drop_zone = 0 as opendream_unimplemented
var/mouse_over_pointer = 0
var/mouse_drag_pointer = 0
var/mouse_drop_pointer = 1
var/mouse_drop_zone = 0
var/mouse_opacity = 1
var/name = "image"
var/opacity = 0 as opendream_unimplemented
Expand Down
50 changes: 47 additions & 3 deletions OpenDreamClient/Input/MouseInputSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly IDreamInterfaceManager _dreamInterfaceManager = default!;
[Dependency] private readonly ClientAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly IClyde _clyde = default!;

public bool IsDragging { get => _selectedEntity?.IsDrag ?? false; }

Check notice

Code scanning / InspectCode

Use preferred body style: Convert into property, indexer, or event with preferred body style Note

Code body does not conform to code style settings: use expression-bodied property

private DreamViewOverlay? _dreamViewOverlay;
private ContextMenuPopup _contextMenu = default!;
Expand Down Expand Up @@ -193,25 +196,66 @@
var clickParams = CreateClickParams(viewport, args, underMouse.Value.IconPosition); // If client.show_popup_menu is disabled, this will handle sending right clicks

_selectedEntity = new(atom, args.PointerLocation, clickParams);
//cursor stuff
if (_appearanceSystem.TryGetAppearance(atom, out var atomAppearance)) {
SetCursorFromDefine(atomAppearance.MouseDragPointer, 2); //2 is drag
}
return true;
}

private bool OnRelease(ScalingViewport viewport, GUIBoundKeyEventArgs args) {
if (_selectedEntity == null)
if (_selectedEntity == null) {
SetCursorFromDefine(0, 0); //default
return false;
}

var overAtom = GetAtomUnderMouse(viewport, args.RelativePixelPosition, args.PointerLocation);
if (overAtom is not null && _appearanceSystem.TryGetAppearance(overAtom.Value.Atom, out var atomAppearance)) {
SetCursorFromDefine(atomAppearance.MouseOverPointer, 1); //1 is over
} else
SetCursorFromDefine(0, 0);

if (!_selectedEntity.IsDrag) {
RaiseNetworkEvent(new AtomClickedEvent(_selectedEntity.Atom, _selectedEntity.ClickParams));
} else {
var overAtom = GetAtomUnderMouse(viewport, args.RelativePixelPosition, args.PointerLocation);

RaiseNetworkEvent(new AtomDraggedEvent(_selectedEntity.Atom, overAtom?.Atom, _selectedEntity.ClickParams));
}

Check notice

Code scanning / InspectCode

Use preferred style of 'new' expression when created type is evident Note

Redundant type specification

_selectedEntity = null;
return true;
}

public void SetCursorFromDefine(int define, int activePos) {
switch (define) {

Check warning

Code scanning / InspectCode

Incorrect blank lines: Blank lines are missing elsewhere Warning

Blank lines are missing, expected minimum 1 instead of 0
case 0: //MOUSE_INACTIVE_POINTER
_clyde.SetCursor(_dreamInterfaceManager.Cursors[0]);
break;
case 1: //MOUSE_ACTIVE_POINTER
_clyde.SetCursor(_dreamInterfaceManager.Cursors[activePos]);
break;
//skipping 2 is intentional, it's what byond does
case 3: //MOUSE_DRAG_POINTER
_clyde.SetCursor(_clyde.GetStandardCursor(StandardCursorShape.Move));
break;
case 4: //MOUSE_DROP_POINTER
_clyde.SetCursor(_clyde.GetStandardCursor(StandardCursorShape.NotAllowed));
break;
case 5: //MOUSE_ARROW_POINTER
_clyde.SetCursor(_clyde.GetStandardCursor(StandardCursorShape.Arrow));
break;
case 6: //MOUSE_CROSSHAIRS_POINTER
_clyde.SetCursor(_clyde.GetStandardCursor(StandardCursorShape.Crosshair));
break;
case 7: //MOUSE_HAND_POINTER
_clyde.SetCursor(_clyde.GetStandardCursor(StandardCursorShape.Hand));
break;
default: //invalid
_clyde.SetCursor(null); //default cursor
break;
}
}
private ClickParams CreateClickParams(ScalingViewport viewport, GUIBoundKeyEventArgs args, Vector2i iconPos) {
bool right = args.Function == EngineKeyFunctions.UIRightClick;
bool middle = args.Function == OpenDreamKeyFunctions.MouseMiddle;
Expand All @@ -221,7 +265,7 @@
UIBox2i viewportBox = viewport.GetDrawBox();
Vector2 screenLocPos = (args.RelativePixelPosition - viewportBox.TopLeft) / viewportBox.Size * viewport.ViewportSize;
float screenLocY = viewport.ViewportSize.Y - screenLocPos.Y; // Flip the Y
ScreenLocation screenLoc = new ScreenLocation((int) screenLocPos.X, (int) screenLocY, 32); // TODO: icon_size other than 32
ScreenLocation screenLoc = new ScreenLocation((int)screenLocPos.X, (int)screenLocY, 32); // TODO: icon_size other than 32

// TODO: Take icon transformations into account for iconPos
return new(screenLoc, right, middle, shift, ctrl, alt, iconPos.X, iconPos.Y);
Expand Down
19 changes: 15 additions & 4 deletions OpenDreamClient/Interface/Controls/ControlMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,30 @@
}

private void UpdateAtomUnderMouse(ClientObjectReference? atom, Vector2 relativePos, Vector2i iconPos) {
//if dragging and atom drop pointer: set drop pointer
//if atom over pointer: set over pointer
//else set pointer to default state
if (!_atomUnderMouse.Equals(atom)) {
_entitySystemManager.Resolve(ref _appearanceSystem);

var name = (atom != null) ? _appearanceSystem.GetName(atom.Value) : string.Empty;
Window?.SetStatus(name);

if (_atomUnderMouse != null)
_mouseInput?.HandleAtomMouseExited(Viewport, _atomUnderMouse.Value);
if (atom != null)
if (atom != null) {
_mouseInput?.HandleAtomMouseEntered(Viewport, relativePos, atom.Value, iconPos);
if ( _appearanceSystem.TryGetAppearance(atom.Value, out var atomAppearance)) {
if((_mouseInput?.IsDragging ?? false) && atomAppearance.MouseDropZone)
_mouseInput?.SetCursorFromDefine(atomAppearance.MouseDropPointer, 3); //3 is drop
else
_mouseInput?.SetCursorFromDefine(atomAppearance.MouseOverPointer, 1); //1 is over
} else
_mouseInput?.SetCursorFromDefine(0, 0);

}

Check warning

Code scanning / InspectCode

Incorrect blank lines: Incorrect number of blank lines near braces Warning

Incorrect number of blank lines near braces, expected maximum 0 instead of 1
} else if (atom.HasValue) {
_mouseInput?.HandleAtomMouseMove(Viewport, relativePos, atom.Value, iconPos);
}
_mouseInput?.HandleAtomMouseMove(Viewport, relativePos, atom.Value, iconPos);
}

Check notice

Code scanning / InspectCode

Incorrect indent: Around statement braces Note

Line indent is not restored to the previous level around statement braces

_atomUnderMouse = atom;
}
Expand Down
33 changes: 33 additions & 0 deletions OpenDreamClient/Interface/DreamInterfaceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
using SixLabors.ImageSharp;
using System.Linq;
using Robust.Shared.Map;
using SixLabors.ImageSharp.PixelFormats;

Check warning

Code scanning / InspectCode

Redundant using directive Warning

Using directive is not required by the code and can be safely removed
using OpenToolkit.GraphicsLibraryFramework;

Check warning

Code scanning / InspectCode

Redundant using directive Warning

Using directive is not required by the code and can be safely removed
using Robust.Client.Utility;

Check warning

Code scanning / InspectCode

Redundant using directive Warning

Using directive is not required by the code and can be safely removed

namespace OpenDreamClient.Interface;

Expand Down Expand Up @@ -58,6 +61,7 @@
public Dictionary<string, InterfaceMenu> Menus { get; } = new();
public Dictionary<string, InterfaceMacroSet> MacroSets { get; } = new();
private Dictionary<WindowId, ControlWindow> ClydeWindowIdToControl { get; } = new();
public ICursor?[] Cursors { get; private set; } = new ICursor?[4];

public ViewRange View {
get => _view;
Expand All @@ -75,6 +79,7 @@
public bool ShowPopupMenus { get; private set; } = true;
public int IconSize { get; private set; }


private ViewRange _view = new(5);

public void LoadInterfaceFromSource(string source) {
Expand Down Expand Up @@ -326,6 +331,33 @@
IconSize = msg.IconSize;
View = msg.View;
ShowPopupMenus = msg.ShowPopupMenus;
if (msg.CursorResource != 0)
_dreamResource.LoadResourceAsync<DMIResource>(msg.CursorResource, resource => {
var allState = resource.GetStateAsImage("all", AtomDirection.South);
if (allState is not null) { //all overrides all possible states
Cursors[0] = _clyde.CreateCursor(allState!, new(32, 32));
Cursors[1] = Cursors[0];
Cursors[2] = Cursors[0];
Cursors[3] = Cursors[0];
} else {
var baseState = resource.GetStateAsImage("", AtomDirection.South);
var overState = resource.GetStateAsImage("over", AtomDirection.South);
var dragState = resource.GetStateAsImage("drag", AtomDirection.South);
var dropState = resource.GetStateAsImage("drop", AtomDirection.South);
Cursors[0] = baseState is null ? null : _clyde.CreateCursor(baseState, new(32, 32));
Cursors[1] = overState is null ? null : _clyde.CreateCursor(overState, new(32, 32));
Cursors[2] = dragState is null ? null : _clyde.CreateCursor(dragState, new(32, 32));
Cursors[3] = dropState is null ? null : _clyde.CreateCursor(dropState, new(32, 32));
}
//TODO should trigger a cursor update immediately
});
else {
Cursors[0] = null;
Cursors[1] = null;
Cursors[2] = null;
Cursors[3] = null;
}

}

private void ShowPrompt(PromptWindow prompt) {
Expand Down Expand Up @@ -1035,6 +1067,7 @@
public ViewRange View { get; }
public bool ShowPopupMenus { get; }
public int IconSize { get; }
public ICursor?[] Cursors { get; }

void Initialize();
void FrameUpdate(FrameEventArgs frameEventArgs);
Expand Down
2 changes: 2 additions & 0 deletions OpenDreamClient/Interface/DummyDreamInterfaceManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using OpenDreamClient.Interface.Controls;
using OpenDreamShared.Dream;
using OpenDreamShared.Network.Messages;
using Robust.Client.Graphics;

Check warning

Code scanning / InspectCode

Redundant using directive Warning

Using directive is not required by the code and can be safely removed
using Robust.Shared.Network;
using Robust.Shared.Timing;

Expand All @@ -20,6 +21,7 @@ public sealed class DummyDreamInterfaceManager : IDreamInterfaceManager {
public ViewRange View => new(5);
public bool ShowPopupMenus => true;
public int IconSize => 32;
public ICursor?[] Cursors => new ICursor?[4];

[Dependency] private readonly IClientNetManager _netManager = default!;

Expand Down
21 changes: 20 additions & 1 deletion OpenDreamClient/Resources/ResourceTypes/DMIResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Robust.Client.Graphics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;

namespace OpenDreamClient.Resources.ResourceTypes;

Expand Down Expand Up @@ -54,10 +55,28 @@ private void ProcessDMIData() {
return _states[stateName];
}

public Image<Rgba32>? GetStateAsImage(string? stateName, AtomDirection dir) {
using Stream dmiStream = new MemoryStream(Data);
DMIParser.ParsedDMIDescription description = DMIParser.ParseDMI(dmiStream);

dmiStream.Seek(0, SeekOrigin.Begin);

Image<Rgba32> image = Image.Load<Rgba32>(dmiStream);
if (!(description.GetStateOrDefault(stateName)?.Directions.TryGetValue(dir, out var state) ?? false))
return null;

var result = image.Clone();
result.Mutate(clone => {
clone.Resize(new Size(description.Width, description.Height));
clone.Crop(new Rectangle(state[0].X, state[0].Y, state[0].X + description.Width, state[0].Y + description.Height));
});
return result;
}

private bool IsValidPNG() {
if (Data.Length < PngHeader.Length) return false;

for (int i=0; i<PngHeader.Length; i++) {
for (int i = 0; i < PngHeader.Length; i++) {
if (Data[i] != PngHeader[i]) return false;
}

Expand Down
24 changes: 24 additions & 0 deletions OpenDreamRuntime/AtomManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ public bool IsValidAppearanceVar(string name) {
case "maptext_height":
case "maptext_x":
case "maptext_y":
case "mouse_drag_pointer":
case "mouse_drop_pointer":
case "mouse_drop_zone":
case "mouse_over_pointer":
return true;

// Get/SetAppearanceVar doesn't handle filters right now
Expand Down Expand Up @@ -422,6 +426,18 @@ public void SetAppearanceVar(MutableAppearance appearance, string varName, Dream
case "maptext_y":
value.TryGetValueAsInteger(out appearance.MaptextOffset.Y);
break;
case "mouse_drag_pointer":
value.TryGetValueAsInteger(out appearance.MouseDragPointer);
break;
case "mouse_drop_pointer":
value.TryGetValueAsInteger(out appearance.MouseDropPointer);
break;
case "mouse_drop_zone":
appearance.MouseDropZone = value.IsTruthy();
break;
case "mouse_over_pointer":
value.TryGetValueAsInteger(out appearance.MouseOverPointer);
break;
case "appearance":
throw new Exception("Cannot assign the appearance var on an appearance");

Expand Down Expand Up @@ -530,6 +546,14 @@ public DreamValue GetAppearanceVar(ImmutableAppearance appearance, string varNam
return new(appearance.MaptextOffset.X);
case "maptext_y":
return new(appearance.MaptextOffset.Y);
case "mouse_drag_pointer":
return new(appearance.MouseDragPointer);
case "mouse_drop_pointer":
return new(appearance.MouseDropPointer);
case "mouse_drop_zone":
return appearance.MouseDropZone ? DreamValue.True : DreamValue.False;
case "mouse_over_pointer":
return new(appearance.MouseOverPointer);
case "appearance":
MutableAppearance appearanceCopy = appearance.ToMutable(); // Return a copy
return new(appearanceCopy);
Expand Down
3 changes: 2 additions & 1 deletion OpenDreamRuntime/DreamConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ public void SendClientInfoUpdate() {
MsgUpdateClientInfo msg = new() {
IconSize = _dreamManager.WorldInstance.IconSize,
View = Client!.View,
ShowPopupMenus = Client!.ShowPopupMenus
ShowPopupMenus = Client!.ShowPopupMenus,
CursorResource = Client!.CursorIcon?.Id ?? 0
};

Session?.Channel.SendMessage(msg);
Expand Down
13 changes: 13 additions & 0 deletions OpenDreamRuntime/Objects/Types/DreamObjectClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using OpenDreamRuntime.Procs.Native;
using OpenDreamRuntime.Rendering;
using OpenDreamRuntime.Resources;
using OpenDreamShared.Dream;

namespace OpenDreamRuntime.Objects.Types;
Expand All @@ -13,6 +14,7 @@
public readonly ClientVerbsList ClientVerbs;
public ViewRange View { get; private set; }
public bool ShowPopupMenus { get; private set; } = true;
public IconResource? CursorIcon = null;

Check warning

Code scanning / InspectCode

Redundant member initializer Warning

Initializing field by default value is redundant

public DreamObjectClient(DreamObjectDefinition objectDefinition, DreamConnection connection, ServerScreenOverlaySystem? screenOverlaySystem, ServerClientImagesSystem? clientImagesSystem) : base(objectDefinition) {
Connection = connection;
Expand Down Expand Up @@ -101,6 +103,9 @@
case "images":
value = new(Images);
return true;
case "mouse_pointer_icon":
value = CursorIcon is null ? DreamValue.Null : new(CursorIcon);
return true;
default:
return base.TryGetVar(varName, out value);
}
Expand Down Expand Up @@ -194,6 +199,14 @@

Connection.SelectedStatPanel = statPanel;
break;
case "mouse_pointer_icon":
//resolve the value to an icon file
if (value.TryGetValueAsDreamResource(out var iconResource) && iconResource is IconResource)

Check notice

Code scanning / InspectCode

Type check and casts can be merged Note

Merge cast with type check
CursorIcon = (IconResource)iconResource;
else
CursorIcon = null;
Connection.SendClientInfoUpdate();
break;
default:
base.SetVar(varName, value);
break;
Expand Down
Loading
Loading