OpenBarnyard
 
Loading...
Searching...
No Matches
AGUI2Menu.cpp
Go to the documentation of this file.
1#include "pch.h"
2#include "AGUI2Menu.h"
3#include "AGUI2.h"
4
6#include "SoundBank/ui.h"
7
8//-----------------------------------------------------------------------------
9// Enables memory debugging.
10// Note: Should be the last include!
11//-----------------------------------------------------------------------------
12#include <Core/TMemoryDebugOn.h>
13
14#define EAT_ALL_INPUT_EVENTS TFALSE
15
17
19{
20 m_fItemSpacing = 0.0f;
21 m_pDefaultFocusElement = TNULL;
22 m_pCancelItem = TNULL;
23 m_pLastMenuItem = TNULL;
24 m_pFocusedMenuItem = TNULL;
25 m_eFocusSound = soundbank::UI_MENUCLICK;
26 m_eSelectSound = soundbank::UI_MENUOK;
27 m_eBackSound = soundbank::UI_MENUBACK;
28 m_eNegativeSound = soundbank::UI_NEGATIVE;
29 m_eActionFlags = 0;
30 m_Unk3 = 0;
31 m_Unk4 = 0;
32 m_fnActivateCallback = TNULL;
33 m_fnFocusCallback = TNULL;
34 m_pCallbackUserData = TNULL;
35 m_fTime = 0.0f;
36 m_bHorizontalFlow = TFALSE;
37 m_iNumMenuItems = 0;
38 m_bMouseStateDirty = TFALSE;
39 m_pHoveredMenuItem = TNULL;
40 m_eActionFlags = 0;
41 m_bFlag1 = TTRUE;
42}
43
47
48void AGUI2Menu::Update( TFLOAT a_fDeltaTime )
49{
50 if ( m_bMouseStateDirty )
51 {
52 AGUI2Transform oElementInvTransform;
53
54 if ( m_pLastMenuItem != TNULL )
55 {
57 m_pHoveredMenuItem = TNULL;
58
59 AGUI2MenuItem* pItem = m_pLastMenuItem;
60
61 while ( TTRUE )
62 {
63 if ( pItem->IsVisible() )
64 {
65 // Get inverse transform of the current UI element
66 pItem->GetInvScreenTransform( oElementInvTransform );
67
68 // Get cursor position that is relative to the UI element
69 TVector2 vecElementRelCursorPos;
70 oElementInvTransform.Transform( vecElementRelCursorPos, vecCursorPos );
71
72 if ( pItem->IsPointInside( vecElementRelCursorPos.x, vecElementRelCursorPos.y ) )
73 {
74 if ( m_pFocusedMenuItem != pItem )
75 {
76 SetFocusAt( *pItem );
77 ASoundManager::GetSingleton()->PlayCue( m_eFocusSound );
78 }
79
80 m_pHoveredMenuItem = pItem;
81 break;
82 }
83 }
84
85 pItem = pItem->m_pPrevMenuItem;
86 if ( pItem == m_pLastMenuItem ) break;
87 }
88 }
89
90 m_bMouseStateDirty = TFALSE;
91 }
92
93 if ( m_pLastMenuItem != TNULL )
94 {
95 AGUI2MenuItem* pItem = m_pLastMenuItem;
96
97 while ( TTRUE )
98 {
99 if ( pItem->IsVisible() )
100 {
101 pItem->OnUpdate( a_fDeltaTime );
102 }
103
104 pItem = pItem->m_pPrevMenuItem;
105 if ( pItem == m_pLastMenuItem ) break;
106 }
107 }
108
109 m_fTime += a_fDeltaTime;
110}
111
112TBOOL AGUI2Menu::ProcessInputEvent( const Toshi::TInputInterface::InputEvent* a_pEvent )
113{
114 if ( a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_MOVED )
115 {
116 // Make sure menu updates mouse state
118 }
119 else if ( a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_GONE_DOWN && a_pEvent->GetDoodad() == TInputDeviceMouse::BUTTON_1 && GetHoveredMenuItem() != TNULL )
120 {
121 // LMB was pressed and the menu has a hovered item
123 }
124
125 return TFALSE;
126}
127
128TBOOL AGUI2Menu::ProcessInputCommand( AInputCommand a_eCommand, const Toshi::TInputInterface::InputEvent* a_pEvent )
129{
130 TBOOL bHandled = TFALSE;
131
132 if ( a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_GONE_DOWN ||
133 a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_REPEAT ||
135 {
136 bHandled = TTRUE;
137
138 switch ( a_eCommand )
139 {
140 case AInputCommand_OK:
142 m_eActionFlags |= ACTIONFLAGS_OK;
143 break;
145 m_eActionFlags |= ACTIONFLAGS_CANCEL;
146 break;
147 case AInputCommand_Up:
149 m_eActionFlags |= ACTIONFLAGS_UP;
150 a_pEvent->StartRepeat( 0.5f, 0.1f );
151 break;
154 m_eActionFlags |= ACTIONFLAGS_DOWN;
155 a_pEvent->StartRepeat( 0.5f, 0.1f );
156 break;
158 m_eActionFlags |= ACTIONFLAGS_LEFT;
159 a_pEvent->StartRepeat( 0.5f, 0.1f );
160 break;
162 m_eActionFlags |= ACTIONFLAGS_RIGHT;
163 a_pEvent->StartRepeat( 0.5f, 0.1f );
164 break;
165 default:
166 bHandled = EAT_ALL_INPUT_EVENTS;
167 break;
168 }
169 }
170
171 if ( m_pFocusedMenuItem )
172 {
173 AGUI2MenuItem::COMMANDRESULT eCommandResult = m_pFocusedMenuItem->OnInputCommand( m_eActionFlags );
174
175 if ( eCommandResult == AGUI2MenuItem::COMMANDRESULT_CANCEL )
176 {
177 if ( m_pCancelItem )
178 {
179 // Can cancel, play back sound
180 ASoundManager::GetSingleton()->PlayCue( m_eBackSound );
181
182 // Call handler if it's specified
183 if ( m_fnActivateCallback )
184 m_fnActivateCallback( m_pCallbackUserData, m_pCancelItem );
185 }
186 else
187 {
188 // Can't cancel, play negative sound
189 ASoundManager::GetSingleton()->PlayCue( m_eNegativeSound );
190 }
191 }
192 else if ( eCommandResult == AGUI2MenuItem::COMMANDRESULT_OK )
193 {
194 ActivateFocusedButton();
195 }
196 else if ( eCommandResult == AGUI2MenuItem::COMMANDRESULT_NONE )
197 {
198 // If element didn't process the command, check if the menu can handle this
199
200 if ( ( !m_bHorizontalFlow && m_eActionFlags & ACTIONFLAGS_UP ) ||
201 ( m_bHorizontalFlow && m_eActionFlags & ACTIONFLAGS_LEFT ) )
202 {
203 // Focus on next element
204 AGUI2MenuItem* pNewFocused = m_pFocusedMenuItem->m_pNextMenuItem;
205
206 // Skip elements that cannot be focused/activated
207 while ( pNewFocused->m_pNextMenuItem && !pNewFocused->CanFocus() )
208 pNewFocused = pNewFocused->m_pNextMenuItem;
209
210 if ( pNewFocused != m_pFocusedMenuItem )
211 {
212 // Focus changed, play audio and call handler
213
214 ASoundManager::GetSingleton()->PlayCue( m_eFocusSound );
215
216 if ( m_fnFocusCallback )
217 m_fnFocusCallback( m_pCallbackUserData, m_pFocusedMenuItem, pNewFocused );
218
219 SetFocusAt( *pNewFocused );
220 bHandled = TTRUE;
221 }
222 }
223 else if ( ( !m_bHorizontalFlow && m_eActionFlags & ACTIONFLAGS_DOWN ) || ( m_bHorizontalFlow && m_eActionFlags & ACTIONFLAGS_RIGHT ) )
224 {
225 // Focus on previous element
226 AGUI2MenuItem* pNewFocused = m_pFocusedMenuItem->m_pPrevMenuItem;
227
228 // Skip elements that cannot be focused/activated
229 while ( pNewFocused->m_pPrevMenuItem && !pNewFocused->CanFocus() )
230 pNewFocused = pNewFocused->m_pPrevMenuItem;
231
232 if ( pNewFocused != m_pFocusedMenuItem )
233 {
234 // Focus changed, play audio and call handler
235
236 ASoundManager::GetSingleton()->PlayCue( m_eFocusSound );
237
238 if ( m_fnFocusCallback )
239 m_fnFocusCallback( m_pCallbackUserData, m_pFocusedMenuItem, pNewFocused );
240
241 SetFocusAt( *pNewFocused );
242 bHandled = TTRUE;
243 }
244 }
245 }
246 }
247
248 m_eActionFlags = ACTIONFLAGS_NONE;
249 return bHandled;
250}
251
253{
254 if ( m_pLastMenuItem )
255 a_rMenuItem.LinkMenuItemBefore( *m_pLastMenuItem );
256 else
257 m_pLastMenuItem = &a_rMenuItem;
258
259 AddChildTail( a_rMenuItem );
260 m_iNumMenuItems++;
261}
262
264{
265 if ( a_rMenuItem.IsVisible() )
266 {
267 if ( m_pFocusedMenuItem )
268 m_pFocusedMenuItem->OnFocusLost();
269
270 m_pFocusedMenuItem = &a_rMenuItem;
271 a_rMenuItem.OnFocus();
272 }
273}
274
276{
277 m_fWidth = 0.0f;
278 m_fHeight = 0.0f;
279
280 TFLOAT fOffsetY = 0.0f;
281 AGUI2MenuItem* pMenuItem = m_pLastMenuItem;
282
283 if ( pMenuItem )
284 {
285 while ( TTRUE )
286 {
287 if ( pMenuItem->IsVisible() )
288 {
289 TFLOAT fItemWidth, fItemHeight;
290 pMenuItem->GetDimensions( fItemWidth, fItemHeight );
291
292 TFLOAT fItemPosY = fItemHeight * 0.5f + pMenuItem->GetFlowVisualOffset() + fOffsetY;
293 pMenuItem->GetTransform().SetTranslation( 0.0f, fItemPosY );
295
296 m_fWidth = TMath::Max( m_fWidth, fItemWidth );
297 fOffsetY = fItemHeight * 0.5f + pMenuItem->GetFlowOffset() + fItemPosY + m_fItemSpacing;
298 }
299
300 pMenuItem = pMenuItem->m_pPrevMenuItem;
301 if ( pMenuItem == m_pLastMenuItem ) break;
302 }
303
304 // Set focus at the last added item
305 SetFocusAt( *m_pLastMenuItem );
306 }
307
308 // Update height
309 m_fHeight = fOffsetY;
310
311 // Set focus at default item if it's specified
312 if ( m_pFocusedMenuItem )
313 SetFocusAt( *m_pFocusedMenuItem );
314
315 m_bHorizontalFlow = TFALSE;
316}
317
319{
320 m_eActionFlags |= ACTIONFLAGS_OK;
321 AGUI2MenuItem::COMMANDRESULT eCommandResult = a_rMenuItem.OnInputCommand( m_eActionFlags );
322 m_eActionFlags = ACTIONFLAGS_NONE;
323
324 if ( eCommandResult == AGUI2MenuItem::COMMANDRESULT_OK )
325 {
326 ActivateFocusedButton();
327 return TTRUE;
328 }
329
330 return TFALSE;
331}
332
333void AGUI2Menu::SetMenuAlpha( TFLOAT a_fAlpha, TFLOAT a_fShadowAlpha /* = -1.0f*/ )
334{
335 if ( m_pLastMenuItem != TNULL )
336 {
337 AGUI2MenuItem* pItem = m_pLastMenuItem;
338
339 while ( TTRUE )
340 {
341 if ( pItem->IsVisible() )
342 {
343 pItem->SetAlpha( a_fAlpha );
344 pItem->SetShadowAlpha( ( a_fShadowAlpha == -1.0f ) ? a_fAlpha : a_fShadowAlpha );
345 }
346
347 pItem = pItem->m_pPrevMenuItem;
348 if ( pItem == m_pLastMenuItem ) break;
349 }
350 }
351
352 AGUI2Element::SetAlpha( a_fAlpha );
353}
354
355void AGUI2Menu::ActivateFocusedButton()
356{
357 if ( m_fnActivateCallback && m_pFocusedMenuItem )
358 {
359 // Can activate
360 ASoundManager::GetSingleton()->PlayCue( m_eSelectSound );
361
362 if ( m_fnActivateCallback )
363 m_fnActivateCallback( m_pCallbackUserData, m_pFocusedMenuItem );
364 }
365}
#define TOSHI_NAMESPACE_USING
Definition Defines.h:46
float TFLOAT
Definition Typedefs.h:4
#define TNULL
Definition Typedefs.h:23
#define TFALSE
Definition Typedefs.h:24
#define TTRUE
Definition Typedefs.h:25
bool TBOOL
Definition Typedefs.h:6
@ AGUI2ATTACHMENT_MIDDLECENTER
@ AGUI2ATTACHMENT_TOPCENTER
#define EAT_ALL_INPUT_EVENTS
Definition AGUI2Menu.cpp:14
AInputCommand
Definition AInputMap.h:12
@ AInputCommand_Forward
Definition AInputMap.h:35
@ AInputCommand_Backward
Definition AInputMap.h:43
@ AInputCommand_Right
Definition AInputMap.h:34
@ AInputCommand_Down
Definition AInputMap.h:30
@ AInputCommand_Left
Definition AInputMap.h:33
@ AInputCommand_OK
Definition AInputMap.h:15
@ AInputCommand_Up
Definition AInputMap.h:29
@ AInputCommand_Cancel
Definition AInputMap.h:16
@ AInputCommand_Shoot
Definition AInputMap.h:65
TFORCEINLINE const T & Max(const T &a, const T &b)
@ UI_MENUCLICK
Definition ui.h:28
@ UI_MENUOK
Definition ui.h:34
@ UI_MENUBACK
Definition ui.h:31
@ UI_NEGATIVE
Definition ui.h:19
TFLOAT y
Definition TVector2.h:139
TFLOAT x
Definition TVector2.h:139
static AGUI2MouseCursor & GetMouseCursor()
Definition AGUI2.h:30
AGUI2Transform & GetTransform()
void AddChildTail(AGUI2Element &a_rElement)
TBOOL IsVisible() const
void SetAttachment(AGUI2ATTACHMENT a_eAnchor, AGUI2ATTACHMENT a_ePivot)
virtual void GetDimensions(TFLOAT &a_rWidth, TFLOAT &a_rHeight)
virtual void SetShadowAlpha(TFLOAT a_fAlpha)
void GetInvScreenTransform(AGUI2Transform &a_rOutTransform)
virtual TBOOL IsPointInside(TFLOAT a_fX, TFLOAT a_fY)
virtual void SetAlpha(TFLOAT a_fAlpha)
void SetMouseStateDirty()
Definition AGUI2Menu.h:44
void SetMenuAlpha(TFLOAT a_fAlpha, TFLOAT a_fShadowAlpha=-1.0f)
AGUI2MenuItem * GetHoveredMenuItem() const
Definition AGUI2Menu.h:47
TBOOL ProcessInputCommand(AInputCommand a_eCommand, const Toshi::TInputInterface::InputEvent *a_pEvent)
void Update(TFLOAT a_fDeltaTime)
Definition AGUI2Menu.cpp:48
TBOOL TriggerButtonPress(AGUI2MenuItem &a_rMenuItem)
void AddMenuItem(AGUI2MenuItem &a_rMenuItem)
@ ACTIONFLAGS_UP
Definition AGUI2Menu.h:15
@ ACTIONFLAGS_RIGHT
Definition AGUI2Menu.h:18
@ ACTIONFLAGS_LEFT
Definition AGUI2Menu.h:17
@ ACTIONFLAGS_OK
Definition AGUI2Menu.h:19
@ ACTIONFLAGS_CANCEL
Definition AGUI2Menu.h:20
@ ACTIONFLAGS_DOWN
Definition AGUI2Menu.h:16
@ ACTIONFLAGS_NONE
Definition AGUI2Menu.h:14
void SetFocusAt(AGUI2MenuItem &a_rMenuItem)
void ReflowChildrenVertically()
TBOOL ProcessInputEvent(const Toshi::TInputInterface::InputEvent *a_pEvent)
@ COMMANDRESULT_CANCEL
Definition AGUI2Menu.h:95
virtual COMMANDRESULT OnInputCommand(AGUI2Menu::ACTIONFLAGS &a_rActionFlags)
virtual void SetAlpha(TFLOAT a_fAlpha) override
virtual void OnFocus()
void LinkMenuItemBefore(AGUI2MenuItem &a_rLinkAfter)
TBOOL CanFocus() const
Definition AGUI2Menu.h:106
virtual TFLOAT GetFlowVisualOffset()
virtual TFLOAT GetFlowOffset()
virtual void OnUpdate(TFLOAT a_fDeltaTime)
const Toshi::TVector2 & GetCursorPos() const
void Transform(Toshi::TVector2 &a_rOutVec, const Toshi::TVector2 &a_rTransformVec) const
constexpr void SetTranslation(TFLOAT a_fX, TFLOAT a_fY)