1
- using System ;
2
- using System . Collections . Generic ;
3
1
using System . Threading ;
2
+ using Content . Client . Gameplay ;
4
3
using Robust . Client . UserInterface ;
5
- using Robust . Shared . Log ;
6
- using Robust . Shared . Maths ;
4
+ using Robust . Client . UserInterface . Controllers ;
7
5
using Timer = Robust . Shared . Timing . Timer ;
8
6
namespace Content . Client . ContextMenu . UI
9
7
{
10
8
/// <summary>
11
- /// This class handles all the logic associated with showing a context menu.
9
+ /// This class handles all the logic associated with showing a context menu, as well as all the state for the
10
+ /// entire context menu stack, including verb and entity menus. It does not currently support multiple
11
+ /// open context menus.
12
12
/// </summary>
13
13
/// <remarks>
14
14
/// This largely involves setting up timers to open and close sub-menus when hovering over other menu elements.
15
15
/// </remarks>
16
- [ Virtual ]
17
- public class ContextMenuPresenter : IDisposable
16
+ public sealed class ContextMenuUIController : UIController , IOnStateEntered < GameplayState > , IOnStateExited < GameplayState >
18
17
{
19
18
public static readonly TimeSpan HoverDelay = TimeSpan . FromSeconds ( 0.2 ) ;
20
19
21
- public ContextMenuPopup RootMenu ;
20
+ /// <summary>
21
+ /// Root menu of the entire context menu.
22
+ /// </summary>
23
+ public ContextMenuPopup RootMenu = default ! ;
22
24
public Stack < ContextMenuPopup > Menus { get ; } = new ( ) ;
23
25
24
26
/// <summary>
@@ -31,30 +33,35 @@ public class ContextMenuPresenter : IDisposable
31
33
/// </summary>
32
34
public CancellationTokenSource ? CancelClose ;
33
35
34
- public ContextMenuPresenter ( )
36
+ public Action ? OnContextClosed ;
37
+ public Action < ContextMenuElement > ? OnContextMouseEntered ;
38
+ public Action < ContextMenuElement > ? OnContextMouseExited ;
39
+ public Action < ContextMenuElement > ? OnSubMenuOpened ;
40
+ public Action < ContextMenuElement , GUIBoundKeyEventArgs > ? OnContextKeyEvent ;
41
+
42
+ public void OnStateEntered ( GameplayState state )
35
43
{
36
44
RootMenu = new ( this , null ) ;
37
- RootMenu . OnPopupHide += RootMenu . MenuBody . DisposeAllChildren ;
45
+ RootMenu . OnPopupHide += Close ;
38
46
Menus . Push ( RootMenu ) ;
39
47
}
40
48
41
- /// <summary>
42
- /// Dispose of all UI elements.
43
- /// </summary>
44
- public virtual void Dispose ( )
49
+ public void OnStateExited ( GameplayState state )
45
50
{
46
- RootMenu . OnPopupHide -= RootMenu . MenuBody . DisposeAllChildren ;
51
+ Close ( ) ;
52
+ RootMenu . OnPopupHide -= Close ;
47
53
RootMenu . Dispose ( ) ;
48
54
}
49
55
50
56
/// <summary>
51
57
/// Close and clear the root menu. This will also dispose any sub-menus.
52
58
/// </summary>
53
- public virtual void Close ( )
59
+ public void Close ( )
54
60
{
55
- RootMenu . Close ( ) ;
61
+ RootMenu . MenuBody . DisposeAllChildren ( ) ;
56
62
CancelOpen ? . Cancel ( ) ;
57
63
CancelClose ? . Cancel ( ) ;
64
+ OnContextClosed ? . Invoke ( ) ;
58
65
}
59
66
60
67
/// <summary>
@@ -82,7 +89,7 @@ public void CloseSubMenus(ContextMenuPopup? menu)
82
89
/// <summary>
83
90
/// Start a timer to open this element's sub-menu.
84
91
/// </summary>
85
- public virtual void OnMouseEntered ( ContextMenuElement element )
92
+ private void OnMouseEntered ( ContextMenuElement element )
86
93
{
87
94
if ( ! Menus . TryPeek ( out var topMenu ) )
88
95
{
@@ -100,6 +107,7 @@ public virtual void OnMouseEntered(ContextMenuElement element)
100
107
CancelOpen ? . Cancel ( ) ;
101
108
CancelOpen = new ( ) ;
102
109
Timer . Spawn ( HoverDelay , ( ) => OpenSubMenu ( element ) , CancelOpen . Token ) ;
110
+ OnContextMouseEntered ? . Invoke ( element ) ;
103
111
}
104
112
105
113
/// <summary>
@@ -108,7 +116,7 @@ public virtual void OnMouseEntered(ContextMenuElement element)
108
116
/// <remarks>
109
117
/// Note that this timer will be aborted when entering the actual sub-menu itself.
110
118
/// </remarks>
111
- public virtual void OnMouseExited ( ContextMenuElement element )
119
+ private void OnMouseExited ( ContextMenuElement element )
112
120
{
113
121
CancelOpen ? . Cancel ( ) ;
114
122
@@ -118,17 +126,21 @@ public virtual void OnMouseExited(ContextMenuElement element)
118
126
CancelClose ? . Cancel ( ) ;
119
127
CancelClose = new ( ) ;
120
128
Timer . Spawn ( HoverDelay , ( ) => CloseSubMenus ( element . ParentMenu ) , CancelClose . Token ) ;
129
+ OnContextMouseExited ? . Invoke ( element ) ;
121
130
}
122
131
123
- public virtual void OnKeyBindDown ( ContextMenuElement element , GUIBoundKeyEventArgs args ) { }
132
+ private void OnKeyBindDown ( ContextMenuElement element , GUIBoundKeyEventArgs args )
133
+ {
134
+ OnContextKeyEvent ? . Invoke ( element , args ) ;
135
+ }
124
136
125
137
/// <summary>
126
138
/// Opens a new sub menu, and close the old one.
127
139
/// </summary>
128
140
/// <remarks>
129
141
/// If the given element has no sub-menu, just close the current one.
130
142
/// </remarks>
131
- public virtual void OpenSubMenu ( ContextMenuElement element )
143
+ public void OpenSubMenu ( ContextMenuElement element )
132
144
{
133
145
if ( ! Menus . TryPeek ( out var topMenu ) )
134
146
{
@@ -164,6 +176,7 @@ public virtual void OpenSubMenu(ContextMenuElement element)
164
176
element . SubMenu . SetPositionLast ( ) ;
165
177
166
178
Menus . Push ( element . SubMenu ) ;
179
+ OnSubMenuOpened ? . Invoke ( element ) ;
167
180
}
168
181
169
182
/// <summary>
0 commit comments