OpenBarnyard
 
Loading...
Searching...
No Matches
AGUI2MenuGrid.cpp
Go to the documentation of this file.
1#include "pch.h"
2#include "AGUI2MenuGrid.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
15
16#define EAT_ALL_INPUT_EVENTS TFALSE
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_eActionFlags = ACTIONFLAGS_NONE;
29 m_vecMousePos = TVector2::VEC_ZERO;
30 m_fnActivateCallback = TNULL;
31 m_fnFocusCallback = TNULL;
32 m_pCallbackUserData = TNULL;
33 m_fTime = 0.0f;
34 m_iNumRows = 0;
35 m_iNumColumns = 0;
36 m_bFlag1 = TTRUE;
37 m_vecMaxItemDimensions = TVector2::VEC_ZERO;
38 m_fColumnGap = 0.0f;
39 m_fRowGap = 0.0f;
40 m_pColumnsData = TNULL;
41 m_pRowsData = TNULL;
42 m_fPaddingLeft = 0.0f;
43 m_fMaxItemWidth = 0.0f;
44 m_bBlockActivation = TFALSE;
45 m_pHoveredMenuItem = TNULL;
46 m_eActionFlags = ACTIONFLAGS_NONE;
47}
48
50{
51 delete[] m_pColumnsData;
52 delete[] m_pRowsData;
53}
54
56{
57 if ( m_pLastMenuItem )
58 a_rMenuItem.LinkMenuItemBefore( *m_pLastMenuItem );
59 else
60 m_pLastMenuItem = &a_rMenuItem;
61
62 AddChildTail( a_rMenuItem );
63
64 // Update max item dimensions
65 TFLOAT fItemWidth, fItemHeight;
66 a_rMenuItem.GetDimensions( fItemWidth, fItemHeight );
67
68 if ( m_vecMaxItemDimensions.x < fItemWidth )
69 m_vecMaxItemDimensions.x = fItemWidth;
70
71 if ( m_vecMaxItemDimensions.y < fItemHeight )
72 m_vecMaxItemDimensions.y = fItemHeight;
73
75}
76
78{
79 if ( m_pFocusedMenuItem )
80 m_pFocusedMenuItem->OnFocusLost();
81
82 m_pFocusedMenuItem = a_pMenuItem;
83
84 if ( a_pMenuItem )
85 a_pMenuItem->OnFocus();
86}
87
89{
90 TASSERT( m_pLastMenuItem != TNULL );
91
92 const TFLOAT fMaxItemWidth = ( m_fMaxItemWidth <= 0.0f ) ? m_vecMaxItemDimensions.x : m_fMaxItemWidth;
93 const TFLOAT fMaxItemHeight = m_vecMaxItemDimensions.y;
94
95 TFLOAT fX = m_fPaddingLeft;
96 TFLOAT fY = 0.0f;
97 TINT iColumn = 0;
98 TINT iRow = 0;
99
100 AGUI2MenuGridItem* pMenuItem = m_pLastMenuItem;
101 while ( TTRUE )
102 {
103 // Update position of the menu item
104 pMenuItem->SetTranslation( fX, fY );
105
106 // Update size of the item
107 TFLOAT fColumnSize = m_pColumnsData[ iColumn++ ];
108 pMenuItem->SetDimensions( fMaxItemWidth * fColumnSize, fMaxItemHeight );
109
110 // Offset the coordinate
111 fX += fMaxItemWidth * fColumnSize + m_fColumnGap;
112
113 if ( iColumn >= m_iNumColumns )
114 {
115 // Switch to the next row
116 iColumn = 0;
117
118 fX = m_fPaddingLeft;
119 fY += fMaxItemHeight * m_pRowsData[ iRow++ ] + m_fRowGap;
120 }
121
122 // Go to the next item if it exists
123 if ( pMenuItem->m_pPrevMenuGridItem == m_pLastMenuItem ) break;
124 pMenuItem = pMenuItem->m_pPrevMenuGridItem;
125 }
126
127 // Calculate menu dimensions
128 AGUI2Element::SetDimensions( 0.0f, 0.0f );
129
130 // Width
131 for ( TINT i = 0; i < m_iNumColumns; i++ )
132 AGUI2Element::SetWidth( fMaxItemWidth * m_pColumnsData[ i ] + AGUI2Element::GetWidth() + m_fColumnGap );
133
134 // Height
135 for ( TINT i = 0; i < m_iNumRows; i++ )
136 AGUI2Element::SetHeight( fMaxItemHeight * m_pRowsData[ i ] + AGUI2Element::GetHeight() + m_fRowGap );
137
140}
141
143{
144 m_eActionFlags |= ACTIONFLAGS_OK;
145 AGUI2MenuGridItem::COMMANDRESULT eCommandResult = a_rMenuItem.OnInputCommand( m_eActionFlags );
146 m_eActionFlags = ACTIONFLAGS_NONE;
147
148 if ( eCommandResult == AGUI2MenuGridItem::COMMANDRESULT_OK )
149 {
150 if ( m_fnActivateCallback && m_pFocusedMenuItem && !m_bBlockActivation )
151 {
152 // Can activate
153 ASoundManager::GetSingleton()->PlayCue( m_eSelectSound );
154
155 if ( m_fnActivateCallback )
156 m_fnActivateCallback( m_pCallbackUserData, m_pFocusedMenuItem );
157 }
158
159 return TTRUE;
160 }
161
162 return TFALSE;
163}
164
165TBOOL AGUI2MenuGrid::CreateGrid( TINT a_iNumRows, TINT a_iNumColumns, TFLOAT a_fColumnGap, TFLOAT a_fRowGap )
166{
167 m_iNumRows = a_iNumRows;
168 m_iNumColumns = a_iNumColumns;
169 m_fColumnGap = a_fColumnGap;
170 m_fRowGap = a_fRowGap;
171
172 // Create columns data
173 m_pColumnsData = new TFLOAT[ a_iNumColumns ];
174 TUtil::Fill( m_pColumnsData, m_pColumnsData + a_iNumColumns, 1.0f );
175
176 // Create rows data
177 m_pRowsData = new TFLOAT[ a_iNumRows ];
178 TUtil::Fill( m_pRowsData, m_pRowsData + a_iNumRows, 1.0f );
179
180 return TTRUE;
181}
182
183void AGUI2MenuGrid::Update( TFLOAT a_fDeltaTime )
184{
185 if ( m_bMouseStateDirty )
186 {
187 AGUI2Transform oElementInvTransform;
188
189 if ( m_pLastMenuItem != TNULL )
190 {
192 m_pHoveredMenuItem = TNULL;
193
194 AGUI2MenuGridItem* pItem = m_pLastMenuItem;
195
196 while ( TTRUE )
197 {
198 if ( pItem->IsVisible() )
199 {
200 // Get inverse transform of the current UI element
201 pItem->GetInvScreenTransform( oElementInvTransform );
202
203 // Get cursor position that is relative to the UI element
204 TVector2 vecElementRelCursorPos;
205 oElementInvTransform.Transform( vecElementRelCursorPos, vecCursorPos );
206
207 if ( pItem->IsPointInside( vecElementRelCursorPos.x, vecElementRelCursorPos.y ) )
208 {
209 if ( m_pFocusedMenuItem != pItem )
210 {
211 ASoundManager::GetSingleton()->PlayCue( m_eFocusSound );
212
213 if ( m_fnFocusCallback )
214 m_fnFocusCallback( m_pCallbackUserData, m_pFocusedMenuItem, pItem );
215
216 SetFocusAt( pItem );
217 }
218
219 m_pHoveredMenuItem = pItem;
220 break;
221 }
222 }
223
224 pItem = pItem->m_pPrevMenuGridItem;
225 if ( pItem == m_pLastMenuItem ) break;
226 }
227 }
228
229 m_bMouseStateDirty = TFALSE;
230 }
231
232 if ( m_pLastMenuItem != TNULL )
233 {
234 AGUI2MenuGridItem* pItem = m_pLastMenuItem;
235
236 while ( TTRUE )
237 {
238 pItem->OnUpdate( a_fDeltaTime );
239
240 pItem = pItem->m_pPrevMenuGridItem;
241 if ( pItem == m_pLastMenuItem ) break;
242 }
243 }
244
245 m_fTime += a_fDeltaTime;
246}
247
248TBOOL AGUI2MenuGrid::ProcessInputEvent( const Toshi::TInputInterface::InputEvent* a_pEvent )
249{
250 if ( a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_MOVED )
251 {
252 // Make sure menu updates mouse state
254 }
255 else if ( a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_GONE_DOWN && a_pEvent->GetDoodad() == TInputDeviceMouse::BUTTON_1 && GetHoveredMenuItem() != TNULL )
256 {
257 // LMB was pressed and the menu has a hovered item
259 }
260
261 return TFALSE;
262}
263
264TBOOL AGUI2MenuGrid::ProcessInputCommand( AInputCommand a_eCommand, const Toshi::TInputInterface::InputEvent* a_pEvent )
265{
266 TBOOL bHandled = TFALSE;
267
268 if ( !TStringManager::String8Compare( a_pEvent->GetSource()->GetClass()->GetName(), "TInputDeviceMouse" ) )
269 {
270 m_eActionFlags |= ACTIONFLAGS_MOUSEUPDATED;
271 m_vecMousePos.x = a_pEvent->GetMagnitudeFloat( 0 );
272 m_vecMousePos.y = a_pEvent->GetMagnitudeFloat( 1 );
273 }
274
275 if ( a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_GONE_DOWN ||
276 a_pEvent->GetEventType() == TInputInterface::EVENT_TYPE_REPEAT ||
278 {
279 bHandled = TTRUE;
280
281 switch ( a_eCommand )
282 {
283 case AInputCommand_OK:
285 m_eActionFlags |= ACTIONFLAGS_OK;
286 break;
288 m_eActionFlags |= ACTIONFLAGS_CANCEL;
289 break;
290 case AInputCommand_Up:
292 m_eActionFlags |= ACTIONFLAGS_UP;
293 a_pEvent->StartRepeat( 0.5f, 0.1f );
294 break;
297 m_eActionFlags |= ACTIONFLAGS_DOWN;
298 a_pEvent->StartRepeat( 0.5f, 0.1f );
299 break;
301 m_eActionFlags |= ACTIONFLAGS_LEFT;
302 a_pEvent->StartRepeat( 0.5f, 0.1f );
303 break;
305 m_eActionFlags |= ACTIONFLAGS_RIGHT;
306 a_pEvent->StartRepeat( 0.5f, 0.1f );
307 break;
308 default:
309 bHandled = EAT_ALL_INPUT_EVENTS;
310 break;
311 }
312 }
313
314 if ( m_eActionFlags & ACTIONFLAGS_MOUSEUPDATED )
315 {
316 AGUI2Transform oElementInvTransform;
317
318 AGUI2MenuGridItem* pItem = m_pLastMenuItem;
319 while ( TTRUE )
320 {
321 // Get inverse transform of the current UI element
322 pItem->GetInvScreenTransform( oElementInvTransform );
323
324 // Get cursor position that is relative to the UI element
325 TVector2 vecElementRelCursorPos;
326 oElementInvTransform.Transform( vecElementRelCursorPos, m_vecMousePos );
327
328 if ( pItem->IsPointInside( vecElementRelCursorPos.x, vecElementRelCursorPos.y ) )
329 {
330 ASoundManager::GetSingleton()->PlayCue( m_eFocusSound );
331
332 if ( m_fnFocusCallback )
333 m_fnFocusCallback( m_pCallbackUserData, m_pFocusedMenuItem, pItem );
334
335 SetFocusAt( pItem );
336 break;
337 }
338
339 // Go to the next item if it exists
340 if ( pItem->m_pPrevMenuGridItem == m_pLastMenuItem ) break;
341 pItem = pItem->m_pPrevMenuGridItem;
342 }
343 }
344
345 TASSERT( m_pFocusedMenuItem != TNULL );
346
347 AGUI2MenuGridItem::COMMANDRESULT eCommandResult = m_pFocusedMenuItem->OnInputCommand( m_eActionFlags );
348
349 if ( eCommandResult == AGUI2MenuGridItem::COMMANDRESULT_CANCEL )
350 {
351 if ( m_pCancelItem )
352 {
353 // Can cancel, play back sound
354 ASoundManager::GetSingleton()->PlayCue( m_eBackSound );
355
356 // Call handler if it's specified
357 if ( m_fnActivateCallback )
358 m_fnActivateCallback( m_pCallbackUserData, m_pCancelItem );
359 }
360 }
361 else if ( eCommandResult == AGUI2MenuGridItem::COMMANDRESULT_OK )
362 {
363 if ( m_fnActivateCallback && m_pFocusedMenuItem )
364 {
365 // Can activate
366 ASoundManager::GetSingleton()->PlayCue( m_eSelectSound );
367
368 if ( m_fnActivateCallback )
369 m_fnActivateCallback( m_pCallbackUserData, m_pFocusedMenuItem );
370 }
371 }
372 else if ( eCommandResult == AGUI2MenuGridItem::COMMANDRESULT_NONE )
373 {
374 // If element didn't process the command, check if the menu can handle this
375
376 AGUI2MenuGridItem* pNewFocused;
377 if ( m_eActionFlags & ACTIONFLAGS_UP )
378 {
379 pNewFocused = m_pFocusedMenuItem->m_pTopElement;
380
381 while ( pNewFocused != TNULL && pNewFocused != m_pFocusedMenuItem && !pNewFocused->IsEnabled() )
382 pNewFocused = pNewFocused->m_pTopElement;
383 }
384 else if ( m_eActionFlags & ACTIONFLAGS_DOWN )
385 {
386 pNewFocused = m_pFocusedMenuItem->m_pBottomElement;
387
388 while ( pNewFocused != TNULL && pNewFocused != m_pFocusedMenuItem && !pNewFocused->IsEnabled() )
389 pNewFocused = pNewFocused->m_pBottomElement;
390 }
391 else if ( m_eActionFlags & ACTIONFLAGS_LEFT )
392 {
393 pNewFocused = m_pFocusedMenuItem->m_pLeftElement;
394
395 while ( pNewFocused != TNULL && pNewFocused != m_pFocusedMenuItem && !pNewFocused->IsEnabled() )
396 pNewFocused = pNewFocused->m_pLeftElement;
397 }
398 else if ( m_eActionFlags & ACTIONFLAGS_RIGHT )
399 {
400 pNewFocused = m_pFocusedMenuItem->m_pRightElement;
401
402 while ( pNewFocused != TNULL && pNewFocused != m_pFocusedMenuItem && !pNewFocused->IsEnabled() )
403 pNewFocused = pNewFocused->m_pRightElement;
404 }
405 else
406 {
407 m_eActionFlags = ACTIONFLAGS_NONE;
408 return bHandled;
409 }
410
411 // Change focus
412 ASoundManager::GetSingleton()->PlayCue( m_eFocusSound );
413
414 if ( m_fnFocusCallback )
415 m_fnFocusCallback( m_pCallbackUserData, m_pFocusedMenuItem, pNewFocused );
416
417 SetFocusAt( pNewFocused );
418 bHandled = TTRUE;
419 }
420
421 m_eActionFlags = ACTIONFLAGS_NONE;
422 return bHandled;
423}
#define TASSERT(X,...)
Definition Defines.h:138
#define TOSHI_NAMESPACE_USING
Definition Defines.h:46
float TFLOAT
Definition Typedefs.h:4
#define TNULL
Definition Typedefs.h:23
int TINT
Definition Typedefs.h:7
#define TFALSE
Definition Typedefs.h:24
#define TTRUE
Definition Typedefs.h:25
bool TBOOL
Definition Typedefs.h:6
@ AGUI2ATTACHMENT_TOPLEFT
#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
@ UI_MENUCLICK
Definition ui.h:28
@ UI_MENUOK
Definition ui.h:34
@ UI_MENUBACK
Definition ui.h:31
TFLOAT y
Definition TVector2.h:139
constinit static const TVector2 VEC_ZERO
Definition TVector2.h:132
TFLOAT x
Definition TVector2.h:139
static TINT String8Compare(const TCHAR *str1, const TCHAR *str2, TSIZE size=-1)
static void Fill(T *a_pStart, T *a_pEnd, const T &a_rcValue=T())
Definition TUtil.h:96
static AGUI2MouseCursor & GetMouseCursor()
Definition AGUI2.h:30
void SetTranslation(TFLOAT a_fX, TFLOAT a_fY)
void AddChildTail(AGUI2Element &a_rElement)
TBOOL IsVisible() const
virtual void SetWidth(TFLOAT a_fWidth)
void SetAttachment(AGUI2ATTACHMENT a_eAnchor, AGUI2ATTACHMENT a_ePivot)
virtual TFLOAT GetHeight()
virtual TFLOAT GetWidth()
virtual void GetDimensions(TFLOAT &a_rWidth, TFLOAT &a_rHeight)
void GetInvScreenTransform(AGUI2Transform &a_rOutTransform)
virtual TBOOL IsPointInside(TFLOAT a_fX, TFLOAT a_fY)
virtual void SetDimensions(TFLOAT a_fWidth, TFLOAT a_fHeight)
virtual void SetHeight(TFLOAT a_fHeight)
TBOOL ProcessInputCommand(AInputCommand a_eCommand, const Toshi::TInputInterface::InputEvent *a_pEvent)
AGUI2MenuGridItem * GetHoveredMenuItem() const
void Update(TFLOAT a_fDeltaTime)
void SetFocusAt(AGUI2MenuGridItem *a_pMenuItem)
TBOOL ProcessInputEvent(const Toshi::TInputInterface::InputEvent *a_pEvent)
void AddMenuGridItem(AGUI2MenuGridItem &a_rMenuItem)
TBOOL CreateGrid(TINT a_iNumColumns, TINT a_iNumRows, TFLOAT a_fColumnGap, TFLOAT a_fRowGap)
void SetMouseStateDirty()
TBOOL TriggerButtonPress(AGUI2MenuGridItem &a_rMenuItem)
TBOOL IsEnabled() const
void LinkMenuItemBefore(AGUI2MenuGridItem &a_rLinkAfter)
virtual COMMANDRESULT OnInputCommand(AGUI2MenuGrid::ACTIONFLAGS &a_rActionFlags)
virtual void OnUpdate(TFLOAT a_fDeltaTime)
const Toshi::TVector2 & GetCursorPos() const
void Transform(Toshi::TVector2 &a_rOutVec, const Toshi::TVector2 &a_rTransformVec) const