DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

MenuWidget_List.cpp (12412B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 #pragma hdrstop
     29 #include "../../idLib/precompiled.h"
     30 #include "../Game_local.h"
     31 
     32 /*
     33 ================================================================================================
     34 idMenuWidget_List
     35 
     36 Provides a paged view of this widgets children.  Each child is expected to take on the following
     37 naming scheme.  Children outside of the given window size (NumVisibleOptions) are not rendered,
     38 and will affect which type of arrow indicators are shown.
     39 
     40 Future work:
     41 - Make upIndicator another kind of widget (Image widget?)
     42 ================================================================================================
     43 */
     44 
     45 /*
     46 ========================
     47 idMenuWidget_List::Update
     48 ========================
     49 */
     50 void idMenuWidget_List::Update() {
     51 
     52 	if ( GetSWFObject() == NULL ) {
     53 		return;
     54 	}
     55 
     56 	idSWFScriptObject & root = GetSWFObject()->GetRootObject();
     57 
     58 	if ( !BindSprite( root ) ) {
     59 		return;
     60 	}
     61 
     62 	for ( int optionIndex = 0; optionIndex < GetNumVisibleOptions(); ++optionIndex ) {
     63 		const int childIndex = GetViewOffset() + optionIndex;
     64 		bool shown = false;
     65 
     66 		if ( optionIndex < GetChildren().Num() ) {
     67 			idMenuWidget & child = GetChildByIndex( optionIndex );
     68 			const int controlIndex = GetNumVisibleOptions() - Min( GetNumVisibleOptions(), GetTotalNumberOfOptions() ) + optionIndex;
     69 			child.SetSpritePath( GetSpritePath(), va( "item%d", controlIndex ) );
     70 			if ( child.BindSprite( root ) ) {
     71 				PrepareListElement( child, childIndex );
     72 				child.Update();
     73 				shown = true;
     74 			}
     75 		}
     76 
     77 		if ( !shown ) {
     78 			// hide the item
     79 			idSWFSpriteInstance * const sprite = GetSprite()->GetScriptObject()->GetSprite( va( "item%d", optionIndex - GetTotalNumberOfOptions() ) );
     80 			if ( sprite != NULL ) {
     81 				sprite->SetVisible( false );
     82 			}
     83 		}
     84 	}
     85 
     86 	idSWFSpriteInstance * const upSprite = GetSprite()->GetScriptObject()->GetSprite( "upIndicator" );
     87 	if ( upSprite != NULL ) {
     88 		upSprite->SetVisible( GetViewOffset() > 0 );
     89 	}
     90 
     91 	idSWFSpriteInstance * const downSprite = GetSprite()->GetScriptObject()->GetSprite( "downIndicator" );
     92 	if ( downSprite != NULL ) {
     93 		downSprite->SetVisible( GetViewOffset() + GetNumVisibleOptions() < GetTotalNumberOfOptions() );
     94 	}
     95 }
     96 
     97 /*
     98 ========================
     99 idMenuWidget_List::HandleAction
    100 ========================
    101 */
    102 bool idMenuWidget_List::HandleAction( idWidgetAction & action, const idWidgetEvent & event, idMenuWidget * widget, bool forceHandled ) {
    103 
    104 	const idSWFParmList & parms = action.GetParms();
    105 
    106 	if ( action.GetType() == WIDGET_ACTION_SCROLL_VERTICAL ) {
    107 		const scrollType_t scrollType = static_cast< scrollType_t >( event.arg );
    108 		if ( scrollType == SCROLL_SINGLE ) {
    109 			Scroll( parms[ 0 ].ToInteger() );
    110 		} else if ( scrollType == SCROLL_PAGE ) {
    111 			ScrollOffset( parms[ 0 ].ToInteger() * ( GetNumVisibleOptions() - 1 ) );
    112 		} else if ( scrollType == SCROLL_FULL ) {
    113 			ScrollOffset( parms[ 0 ].ToInteger() * 999 );
    114 		}
    115 		return true;
    116 	}
    117 
    118 	return idMenuWidget::HandleAction( action, event, widget, forceHandled );
    119 }
    120 
    121 /*
    122 ========================
    123 idMenuWidget_List::ObserveEvent
    124 ========================
    125 */
    126 void idMenuWidget_List::ObserveEvent( const idMenuWidget & widget, const idWidgetEvent & event ) {
    127 	ExecuteEvent( event );
    128 }
    129 
    130 /*
    131 ========================
    132 idMenuWidget_List::CalculatePositionFromIndexDelta
    133 
    134 Pure functional encapsulation of how to calculate a new index and offset based on how the user
    135 chose to move through the list.
    136 ========================
    137 */
    138 void idMenuWidget_List::CalculatePositionFromIndexDelta( int & outIndex, int & outOffset, const int currentIndex, const int currentOffset, const int windowSize, const int maxSize, const int indexDelta, const bool allowWrapping, const bool wrapAround ) const {
    139 	assert( indexDelta != 0 );
    140 	
    141 	int newIndex = currentIndex + indexDelta;
    142 	bool wrapped = false;
    143 
    144 	if ( indexDelta > 0 ) {
    145 		// moving down the list
    146 		if ( newIndex > maxSize - 1 ) {
    147 			if ( allowWrapping ) {
    148 				if ( wrapAround ) {
    149 					wrapped = true;
    150 					newIndex = 0 + ( newIndex - maxSize );
    151 				} else {
    152 					newIndex = 0;
    153 				}
    154 			} else {
    155 				newIndex = maxSize - 1;
    156 			}
    157 		}
    158 	} else {
    159 		// moving up the list
    160 		if ( newIndex < 0 ) {
    161 			if ( allowWrapping ) {
    162 				if ( wrapAround ) {
    163 					newIndex = maxSize + newIndex;
    164 				} else {
    165 					newIndex = maxSize - 1;
    166 				}
    167 			} else {
    168 				newIndex = 0;
    169 			}
    170 		}
    171 	}
    172 
    173 	// calculate the offset
    174 	if ( newIndex - currentOffset >= windowSize ) {
    175 		outOffset = newIndex - windowSize + 1;
    176 	} else if ( currentOffset > newIndex ) {
    177 		if ( wrapped ) {
    178 			outOffset = 0;
    179 		} else {
    180 			outOffset = newIndex;
    181 		}
    182 	} else {
    183 		outOffset = currentOffset;
    184 	}
    185 
    186 	outIndex = newIndex;
    187 
    188 	// the intended behavior is that outOffset and outIndex are always within maxSize of each
    189 	// other, as they are meant to model a window of items that should be visible in the list.
    190 	assert( outIndex - outOffset < windowSize );
    191 	assert( outIndex >= outOffset && outIndex >= 0 && outOffset >= 0 );
    192 }
    193 
    194 /*
    195 ========================
    196 idMenuWidget_List::CalculatePositionFromOffsetDelta
    197 ========================
    198 */
    199 void idMenuWidget_List::CalculatePositionFromOffsetDelta( int & outIndex, int & outOffset, const int currentIndex, const int currentOffset, const int windowSize, const int maxSize, const int offsetDelta ) const {
    200 	// shouldn't be setting both indexDelta AND offsetDelta
    201 	// FIXME: make this simpler code - just pass a boolean to control it?
    202 	assert( offsetDelta != 0 );
    203 	
    204 	const int newOffset = Max( currentIndex + offsetDelta, 0 );
    205 		
    206 	if ( newOffset >= maxSize ) {
    207 		// scrolling past the end - just scroll all the way to the end
    208 		outIndex = maxSize - 1;
    209 		outOffset = Max( maxSize - windowSize, 0 );
    210 	} else if ( newOffset >= maxSize - windowSize ) {
    211 		// scrolled to the last window
    212 		outIndex = newOffset;
    213 		outOffset = Max( maxSize - windowSize, 0 );
    214 	} else {
    215 		outIndex = outOffset = newOffset;
    216 	}
    217 
    218 	// the intended behavior is that outOffset and outIndex are always within maxSize of each
    219 	// other, as they are meant to model a window of items that should be visible in the list.
    220 	assert( outIndex - outOffset < windowSize );
    221 	assert( outIndex >= outOffset && outIndex >= 0 && outOffset >= 0 );
    222 }
    223 
    224 /*
    225 ========================
    226 idMenuWidget_List::Scroll
    227 ========================
    228 */
    229 void idMenuWidget_List::Scroll( const int scrollAmount, const bool wrapAround ) {
    230 
    231 	if ( GetTotalNumberOfOptions() == 0 ) {
    232 		return;
    233 	}
    234 
    235 	int newIndex, newOffset;
    236 
    237 	CalculatePositionFromIndexDelta( newIndex, newOffset, GetViewIndex(), GetViewOffset(), GetNumVisibleOptions(), GetTotalNumberOfOptions(), scrollAmount, IsWrappingAllowed(), wrapAround );
    238 	if ( newOffset != GetViewOffset() ) {
    239 		SetViewOffset( newOffset );
    240 		if ( menuData != NULL ) {
    241 			menuData->PlaySound( GUI_SOUND_FOCUS );	
    242 		}
    243 		Update();
    244 	}
    245 
    246 	if ( newIndex != GetViewIndex() ) {
    247 		SetViewIndex( newIndex );
    248 		SetFocusIndex( newIndex - newOffset );
    249 	}
    250 }
    251 
    252 /*
    253 ========================
    254 idMenuWidget_List::ScrollOffset
    255 ========================
    256 */
    257 void idMenuWidget_List::ScrollOffset( const int scrollAmount ) {
    258 
    259 	if ( GetTotalNumberOfOptions() == 0 ) {
    260 		return;
    261 	}
    262 
    263 	int newIndex, newOffset;
    264 
    265 	CalculatePositionFromOffsetDelta( newIndex, newOffset, GetViewIndex(), GetViewOffset(), GetNumVisibleOptions(), GetTotalNumberOfOptions(), scrollAmount );
    266 	if ( newOffset != GetViewOffset() ) {
    267 		SetViewOffset( newOffset );
    268 		Update();
    269 	}
    270 
    271 	if ( newIndex != GetViewIndex() ) {
    272 		SetViewIndex( newIndex );
    273 		SetFocusIndex( newIndex - newOffset );
    274 	}
    275 }
    276 
    277 //*********************************************************************************
    278 // GAME BROWSER LIST
    279 //********************************************************************************
    280 
    281 /*
    282 ========================
    283 idMenuWidget_GameBrowserList::Update
    284 ========================
    285 */
    286 void idMenuWidget_GameBrowserList::Update() {
    287 
    288 	if ( GetSWFObject() == NULL ) {
    289 		return;
    290 	}
    291 
    292 	idSWFScriptObject & root = GetSWFObject()->GetRootObject();
    293 
    294 	if ( !BindSprite( root ) ) {
    295 		return;
    296 	}
    297 
    298 	for ( int optionIndex = 0; optionIndex < GetNumVisibleOptions(); ++optionIndex ) {		
    299 		const int childIndex = GetViewOffset() + optionIndex;
    300 		bool shown = false;
    301 		if ( optionIndex < GetChildren().Num() ) {
    302 			idMenuWidget & child = GetChildByIndex( optionIndex );
    303 			child.SetSpritePath( GetSpritePath(), va( "item%d", optionIndex ) );
    304 			if ( child.BindSprite( root ) ) {
    305 				shown = PrepareListElement( child, childIndex );
    306 				if ( shown ) {
    307 					child.SetState( WIDGET_STATE_NORMAL );
    308 					child.GetSprite()->SetVisible( true );
    309 					child.Update();
    310 				} else {
    311 					child.GetSprite()->SetVisible( false );
    312 				}
    313 			}
    314 		}
    315 	}
    316 
    317 	idSWFSpriteInstance * const upSprite = GetSprite()->GetScriptObject()->GetSprite( "upIndicator" );
    318 	if ( upSprite != NULL ) {
    319 		upSprite->SetVisible( GetViewOffset() > 0 );
    320 	}
    321 
    322 	idSWFSpriteInstance * const downSprite = GetSprite()->GetScriptObject()->GetSprite( "downIndicator" );
    323 	if ( downSprite != NULL ) {
    324 		downSprite->SetVisible( GetViewOffset() + GetNumVisibleOptions() < GetTotalNumberOfOptions() );
    325 	}
    326 }
    327 
    328 /*
    329 ========================
    330 idMenuWidget_GameBrowserList::PrepareListElement
    331 ========================
    332 */
    333 bool idMenuWidget_GameBrowserList::PrepareListElement( idMenuWidget & widget, const int childIndex ) {
    334 
    335 	if ( childIndex >= games.Num() ) {
    336 		return false;
    337 	}
    338 
    339 	idMenuWidget_ServerButton * const button = dynamic_cast< idMenuWidget_ServerButton * >( &widget );
    340 	if ( button == NULL ) {
    341 		return false;
    342 	}
    343 
    344 	if ( games[childIndex].serverName.IsEmpty() ) {
    345 		return false;
    346 	}
    347 
    348 	const idBrowserEntry_t entry = games[childIndex];
    349 
    350 	button->SetButtonInfo( entry.serverName, entry.mapName, entry.modeName, entry.index, entry.players, entry.maxPlayers, entry.joinable, entry.validMap );
    351 
    352 	return true;
    353 
    354 }
    355 
    356 /*
    357 ========================
    358 idMenuWidget_GameBrowserList::PrepareListElement
    359 ========================
    360 */
    361 void idMenuWidget_GameBrowserList::ClearGames() {
    362 	games.Clear();
    363 }
    364 
    365 /*
    366 ========================
    367 idMenuWidget_GameBrowserList::PrepareListElement
    368 ========================
    369 */
    370 void idMenuWidget_GameBrowserList::AddGame( idStr name_, idStrId mapName_, idStr modeName_, int index_, int players_, int maxPlayers_, bool joinable_, bool validMap_ ) {
    371 
    372 	idBrowserEntry_t entry;
    373 
    374 	entry.serverName = name_;
    375 	entry.index = index_;
    376 	entry.players = players_;
    377 	entry.maxPlayers = maxPlayers_;
    378 	entry.joinable = joinable_;
    379 	entry.validMap = validMap_;
    380 	entry.mapName = mapName_;
    381 	entry.modeName = modeName_;
    382 
    383 	games.Append( entry );
    384 }
    385 
    386 /*
    387 ========================
    388 idMenuWidget_GameBrowserList::GetTotalNumberOfOptions
    389 ========================
    390 */
    391 int idMenuWidget_GameBrowserList::GetTotalNumberOfOptions() const {
    392 	return games.Num();
    393 }
    394 
    395 /*
    396 ========================
    397 idMenuWidget_GameBrowserList::PrepareListElement
    398 ========================
    399 */
    400 int idMenuWidget_GameBrowserList::GetServerIndex() {
    401 
    402 	if ( GetViewIndex() < games.Num() ) {
    403 		return games[ GetViewIndex() ].index;
    404 	}
    405 
    406 	return -1;
    407 
    408 }