mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-18 09:19:17 +01:00
9e79c9d99b
* code cleanup
431 lines
11 KiB
C++
431 lines
11 KiB
C++
/****************************************************************************
|
|
* libwiigui
|
|
*
|
|
* Tantric 2009
|
|
*
|
|
* gui_window.cpp
|
|
*
|
|
* GUI class definitions
|
|
***************************************************************************/
|
|
|
|
#include "gui.h"
|
|
|
|
GuiWindow::GuiWindow()
|
|
{
|
|
width = 0;
|
|
height = 0;
|
|
focus = 0; // allow focus
|
|
}
|
|
|
|
GuiWindow::GuiWindow( int w, int h )
|
|
{
|
|
width = w;
|
|
height = h;
|
|
focus = 0; // allow focus
|
|
}
|
|
|
|
GuiWindow::~GuiWindow()
|
|
{
|
|
}
|
|
|
|
void GuiWindow::Append( GuiElement* e )
|
|
{
|
|
LOCK( this );
|
|
if ( e == NULL )
|
|
return;
|
|
|
|
Remove( e );
|
|
_elements.push_back( e );
|
|
e->SetParent( this );
|
|
}
|
|
|
|
void GuiWindow::Insert( GuiElement* e, u32 index )
|
|
{
|
|
LOCK( this );
|
|
if ( e == NULL || index > ( _elements.size() - 1 ) )
|
|
return;
|
|
|
|
Remove( e );
|
|
_elements.insert( _elements.begin() + index, e );
|
|
e->SetParent( this );
|
|
}
|
|
|
|
void GuiWindow::Remove( GuiElement* e )
|
|
{
|
|
LOCK( this );
|
|
if ( e == NULL )
|
|
return;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
if ( e == _elements.at( i ) )
|
|
{
|
|
_elements.erase( _elements.begin() + i );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GuiWindow::RemoveAll()
|
|
{
|
|
LOCK( this );
|
|
_elements.clear();
|
|
}
|
|
|
|
GuiElement* GuiWindow::GetGuiElementAt( u32 index ) const
|
|
{
|
|
if ( index >= _elements.size() )
|
|
return NULL;
|
|
return _elements.at( index );
|
|
}
|
|
|
|
u32 GuiWindow::GetSize()
|
|
{
|
|
return _elements.size();
|
|
}
|
|
|
|
void GuiWindow::Draw()
|
|
{
|
|
LOCK( this );
|
|
if ( _elements.size() == 0 || !this->IsVisible() )
|
|
return;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try { _elements.at( i )->Draw(); }
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
|
|
this->UpdateEffects();
|
|
|
|
if ( parentElement && state == STATE_DISABLED )
|
|
//Menu_DrawRectangle(0,0,screenwidth,screenheight,(GXColor){0xbe, 0xca, 0xd5, 0x70},1);
|
|
Menu_DrawRectangle( 0, 0, screenwidth, screenheight, ( GXColor ) {0, 0, 0, 0x70}, 1 );
|
|
}
|
|
void GuiWindow::DrawTooltip()
|
|
{
|
|
LOCK( this );
|
|
if ( _elements.size() == 0 || !this->IsVisible() )
|
|
return;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try { _elements.at( i )->DrawTooltip(); }
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
}
|
|
void GuiWindow::ResetState()
|
|
{
|
|
LOCK( this );
|
|
if ( state != STATE_DISABLED )
|
|
state = STATE_DEFAULT;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try { _elements.at( i )->ResetState(); }
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
}
|
|
|
|
void GuiWindow::SetState( int s )
|
|
{
|
|
LOCK( this );
|
|
state = s;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try { _elements.at( i )->SetState( s ); }
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
}
|
|
|
|
void GuiWindow::SetVisible( bool v )
|
|
{
|
|
LOCK( this );
|
|
visible = v;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try { _elements.at( i )->SetVisible( v ); }
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
}
|
|
|
|
void GuiWindow::SetFocus( int f )
|
|
{
|
|
LOCK( this );
|
|
focus = f;
|
|
|
|
if ( f == 1 )
|
|
this->MoveSelectionVert( 1 );
|
|
else
|
|
this->ResetState();
|
|
}
|
|
|
|
void GuiWindow::ChangeFocus( GuiElement* e )
|
|
{
|
|
LOCK( this );
|
|
if ( parentElement )
|
|
return; // this is only intended for the main window
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
if ( e == _elements.at( i ) )
|
|
_elements.at( i )->SetFocus( 1 );
|
|
else if ( _elements.at( i )->IsFocused() == 1 )
|
|
_elements.at( i )->SetFocus( 0 );
|
|
}
|
|
}
|
|
|
|
void GuiWindow::ToggleFocus( GuiTrigger * t )
|
|
{
|
|
LOCK( this );
|
|
if ( parentElement )
|
|
return; // this is only intended for the main window
|
|
|
|
int found = -1;
|
|
int newfocus = -1;
|
|
u8 i;
|
|
|
|
// look for currently in focus element
|
|
for ( i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsFocused() == 1 )
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
|
|
// element with focus not found, try to give focus
|
|
if ( found == -1 )
|
|
{
|
|
for ( i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsFocused() == 0 && _elements.at( i )->GetState() != STATE_DISABLED ) // focus is possible (but not set)
|
|
{
|
|
_elements.at( i )->SetFocus( 1 ); // give this element focus
|
|
break;
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
}
|
|
// change focus
|
|
else if ( t->wpad.btns_d & ( WPAD_BUTTON_1 | WPAD_BUTTON_1 | WPAD_CLASSIC_BUTTON_PLUS )
|
|
|| t->pad.btns_d & PAD_BUTTON_B )
|
|
{
|
|
for ( i = found; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsFocused() == 0 && _elements.at( i )->GetState() != STATE_DISABLED ) // focus is possible (but not set)
|
|
{
|
|
newfocus = i;
|
|
_elements.at( i )->SetFocus( 1 ); // give this element focus
|
|
_elements.at( found )->SetFocus( 0 ); // disable focus on other element
|
|
break;
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
|
|
if ( newfocus == -1 )
|
|
{
|
|
for ( i = 0; i < found; i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsFocused() == 0 && _elements.at( i )->GetState() != STATE_DISABLED ) // focus is possible (but not set)
|
|
{
|
|
_elements.at( i )->SetFocus( 1 ); // give this element focus
|
|
_elements.at( found )->SetFocus( 0 ); // disable focus on other element
|
|
break;
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int GuiWindow::GetSelected()
|
|
{
|
|
// find selected element
|
|
int found = -1;
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->GetState() == STATE_SELECTED )
|
|
{
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
return found;
|
|
}
|
|
|
|
// set element to left/right as selected
|
|
// there's probably a more clever way to do this, but this way works
|
|
void GuiWindow::MoveSelectionHor( int dir )
|
|
{
|
|
LOCK( this );
|
|
int found = -1;
|
|
u16 left = 0;
|
|
u16 top = 0;
|
|
u8 i = 0;
|
|
|
|
int selected = this->GetSelected();
|
|
|
|
if ( selected >= 0 )
|
|
{
|
|
left = _elements.at( selected )->GetLeft();
|
|
top = _elements.at( selected )->GetTop();
|
|
}
|
|
|
|
// look for a button on the same row, to the left/right
|
|
for ( i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsSelectable() )
|
|
{
|
|
if ( _elements.at( i )->GetLeft()*dir > left*dir && _elements.at( i )->GetTop() == top )
|
|
{
|
|
if ( found == -1 )
|
|
found = i;
|
|
else if ( _elements.at( i )->GetLeft()*dir < _elements.at( found )->GetLeft()*dir )
|
|
found = i; // this is a better match
|
|
}
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
if ( found >= 0 )
|
|
goto matchfound;
|
|
|
|
// match still not found, let's try the first button in the next row
|
|
for ( i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsSelectable() )
|
|
{
|
|
if ( _elements.at( i )->GetTop()*dir > top*dir )
|
|
{
|
|
if ( found == -1 )
|
|
found = i;
|
|
else if ( _elements.at( i )->GetTop()*dir < _elements.at( found )->GetTop()*dir )
|
|
found = i; // this is a better match
|
|
else if ( _elements.at( i )->GetTop()*dir == _elements.at( found )->GetTop()*dir
|
|
&&
|
|
_elements.at( i )->GetLeft()*dir < _elements.at( found )->GetLeft()*dir )
|
|
found = i; // this is a better match
|
|
}
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
|
|
// match found
|
|
matchfound:
|
|
if ( found >= 0 )
|
|
{
|
|
_elements.at( found )->SetState( STATE_SELECTED );
|
|
if ( selected >= 0 )
|
|
_elements.at( selected )->ResetState();
|
|
}
|
|
}
|
|
|
|
void GuiWindow::MoveSelectionVert( int dir )
|
|
{
|
|
LOCK( this );
|
|
int found = -1;
|
|
u16 left = 0;
|
|
u16 top = 0;
|
|
u8 i = 0;
|
|
|
|
int selected = this->GetSelected();
|
|
|
|
if ( selected >= 0 )
|
|
{
|
|
left = _elements.at( selected )->GetLeft();
|
|
top = _elements.at( selected )->GetTop();
|
|
}
|
|
|
|
// look for a button above/below, with the least horizontal difference
|
|
for ( i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try
|
|
{
|
|
if ( _elements.at( i )->IsSelectable() )
|
|
{
|
|
if ( _elements.at( i )->GetTop()*dir > top*dir )
|
|
{
|
|
if ( found == -1 )
|
|
found = i;
|
|
else if ( _elements.at( i )->GetTop()*dir < _elements.at( found )->GetTop()*dir )
|
|
found = i; // this is a better match
|
|
else if ( _elements.at( i )->GetTop()*dir == _elements.at( found )->GetTop()*dir
|
|
&&
|
|
abs( _elements.at( i )->GetLeft() - left ) <
|
|
abs( _elements.at( found )->GetLeft() - left ) )
|
|
found = i;
|
|
}
|
|
}
|
|
}
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
if ( found >= 0 )
|
|
goto matchfound;
|
|
|
|
// match found
|
|
matchfound:
|
|
if ( found >= 0 )
|
|
{
|
|
_elements.at( found )->SetState( STATE_SELECTED );
|
|
if ( selected >= 0 )
|
|
_elements.at( selected )->ResetState();
|
|
}
|
|
}
|
|
|
|
void GuiWindow::Update( GuiTrigger * t )
|
|
{
|
|
LOCK( this );
|
|
if ( _elements.size() == 0 || ( state == STATE_DISABLED && parentElement ) )
|
|
return;
|
|
|
|
for ( u8 i = 0; i < _elements.size(); i++ )
|
|
{
|
|
try { _elements.at( i )->Update( t ); }
|
|
catch ( const std::exception& e ) { }
|
|
}
|
|
|
|
this->ToggleFocus( t );
|
|
|
|
if ( focus ) // only send actions to this window if it's in focus
|
|
{
|
|
// pad/joystick navigation
|
|
if ( t->Right() )
|
|
this->MoveSelectionHor( 1 );
|
|
else if ( t->Left() )
|
|
this->MoveSelectionHor( -1 );
|
|
else if ( t->Down() )
|
|
this->MoveSelectionVert( 1 );
|
|
else if ( t->Up() )
|
|
this->MoveSelectionVert( -1 );
|
|
}
|
|
|
|
if ( updateCB )
|
|
updateCB( this );
|
|
}
|