DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

ChoiceWindow.cpp (10271B)


      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 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "DeviceContext.h"
     33 #include "Window.h"
     34 #include "UserInterfaceLocal.h"
     35 #include "ChoiceWindow.h"
     36 
     37 /*
     38 ============
     39 idChoiceWindow::InitVars
     40 ============
     41 */
     42 void idChoiceWindow::InitVars( ) {
     43 	if ( cvarStr.Length() ) {
     44 		cvar = cvarSystem->Find( cvarStr );
     45 		if ( !cvar ) {
     46 			common->Warning( "idChoiceWindow::InitVars: gui '%s' window '%s' references undefined cvar '%s'", gui->GetSourceFile(), name.c_str(), cvarStr.c_str() );
     47 			return;
     48 		}
     49 		updateStr.Append( &cvarStr );
     50 	}
     51 	if ( guiStr.Length() ) {
     52 		updateStr.Append( &guiStr );
     53 	}
     54 	updateStr.SetGuiInfo( gui->GetStateDict() );
     55 	updateStr.Update();
     56 }
     57 
     58 /*
     59 ============
     60 idChoiceWindow::CommonInit
     61 ============
     62 */
     63 void idChoiceWindow::CommonInit() {
     64 	currentChoice = 0;
     65 	choiceType = 0;
     66 	cvar = NULL;
     67 	liveUpdate = true;
     68 	choices.Clear();
     69 }
     70 
     71 idChoiceWindow::idChoiceWindow(idUserInterfaceLocal *g) : idWindow(g) {
     72 	gui = g;
     73 	CommonInit();
     74 }
     75 
     76 idChoiceWindow::~idChoiceWindow() {
     77 
     78 }
     79 
     80 void idChoiceWindow::RunNamedEvent( const char* eventName ) {
     81 	idStr event, group;
     82 	
     83 	if ( !idStr::Cmpn( eventName, "cvar read ", 10 ) ) {
     84 		event = eventName;
     85 		group = event.Mid( 10, event.Length() - 10 );
     86 		if ( !group.Cmp( updateGroup ) ) {
     87 			UpdateVars( true, true );
     88 		}
     89 	} else if ( !idStr::Cmpn( eventName, "cvar write ", 11 ) ) {
     90 		event = eventName;
     91 		group = event.Mid( 11, event.Length() - 11 );
     92 		if ( !group.Cmp( updateGroup ) ) {
     93 			UpdateVars( false, true );
     94 		}
     95 	}
     96 }
     97 
     98 void idChoiceWindow::UpdateVars( bool read, bool force ) {
     99 	if ( force || liveUpdate ) {
    100 		if ( cvar && cvarStr.NeedsUpdate() ) {
    101 			if ( read ) {
    102 				cvarStr.Set( cvar->GetString() );
    103 			} else {
    104 				cvar->SetString( cvarStr.c_str() );
    105 			}	
    106 		}
    107 		if ( !read && guiStr.NeedsUpdate() ) {
    108 			guiStr.Set( va( "%i", currentChoice ) );
    109 		}
    110 	}
    111 }
    112 
    113 const char *idChoiceWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
    114 	int key;
    115 	bool runAction = false;
    116 	bool runAction2 = false;
    117 
    118 	if ( event->evType == SE_KEY ) {
    119 		key = event->evValue;
    120 
    121 		if ( key == K_RIGHTARROW || key == K_KP_6 || key == K_MOUSE1)  {
    122 			// never affects the state, but we want to execute script handlers anyway
    123 			if ( !event->evValue2 ) {
    124 				RunScript( ON_ACTIONRELEASE );
    125 				return cmd;
    126 			}
    127 			currentChoice++;
    128 			if (currentChoice >= choices.Num()) {
    129 				currentChoice = 0;
    130 			}
    131 			runAction = true;
    132 		}
    133 
    134 		if ( key == K_LEFTARROW || key == K_KP_4 || key == K_MOUSE2) {
    135 			// never affects the state, but we want to execute script handlers anyway
    136 			if ( !event->evValue2 ) {
    137 				RunScript( ON_ACTIONRELEASE );
    138 				return cmd;
    139 			}
    140 			currentChoice--;
    141 			if (currentChoice < 0) {
    142 				currentChoice = choices.Num() - 1;
    143 			}
    144 			runAction = true;
    145 		}
    146 
    147 		if ( !event->evValue2 ) {
    148 			// is a key release with no action catch
    149 			return "";
    150 		}
    151 
    152 	} else if ( event->evType == SE_CHAR ) {
    153 
    154 		key = event->evValue;
    155 
    156 		int potentialChoice = -1;
    157 		for ( int i = 0; i < choices.Num(); i++ ) {
    158 			if ( toupper(key) == toupper(choices[i][0]) ) {
    159 				if ( i < currentChoice && potentialChoice < 0 ) {
    160 					potentialChoice = i;
    161 				} else if ( i > currentChoice ) {
    162 					potentialChoice = -1;
    163 					currentChoice = i;
    164 					break;
    165 				}
    166 			}
    167 		}
    168 		if ( potentialChoice >= 0 ) {
    169 			currentChoice = potentialChoice;
    170 		}
    171 
    172 		runAction = true;
    173 		runAction2 = true;
    174 
    175 	} else {
    176 		return "";
    177 	}
    178 
    179 	if ( runAction ) {
    180 		RunScript( ON_ACTION );
    181 	}
    182 
    183 	if ( choiceType == 0 ) {
    184 		cvarStr.Set( va( "%i", currentChoice ) );
    185 	} else if ( values.Num() ) {
    186 		cvarStr.Set( values[ currentChoice ] );
    187 	} else {
    188 		cvarStr.Set( choices[ currentChoice ] );
    189 	}
    190 
    191 	UpdateVars( false );
    192 
    193 	if ( runAction2 ) {
    194 		RunScript( ON_ACTIONRELEASE );
    195 	}
    196 	
    197 	return cmd;
    198 }
    199 
    200 void idChoiceWindow::ValidateChoice() {
    201 	if ( currentChoice < 0 || currentChoice >= choices.Num() ) {
    202 		currentChoice = 0;
    203 	}
    204 	if ( choices.Num() == 0 ) {
    205 		choices.Append( "No Choices Defined" );
    206 	}
    207 }
    208 
    209 void idChoiceWindow::UpdateChoice() {
    210 	if ( !updateStr.Num() ) {
    211 		return;
    212 	}
    213 	UpdateVars( true );	
    214 	updateStr.Update();
    215 	if ( choiceType == 0 ) {
    216 		// ChoiceType 0 stores current as an integer in either cvar or gui
    217 		// If both cvar and gui are defined then cvar wins, but they are both updated
    218 		if ( updateStr[ 0 ]->NeedsUpdate() ) {
    219 			currentChoice = atoi( updateStr[ 0 ]->c_str() );
    220 		}
    221 		ValidateChoice();
    222 	} else {
    223 		// ChoiceType 1 stores current as a cvar string
    224 		int c = ( values.Num() ) ? values.Num() : choices.Num();
    225 		int i;
    226 		for ( i = 0; i < c; i++ ) {
    227 			if ( idStr::Icmp( cvarStr.c_str(), ( values.Num() ) ? values[i] : choices[i] ) == 0 ) {
    228 				break;
    229 			}
    230 		}
    231 		if (i == c) {
    232 			i = 0;
    233 		}
    234 		currentChoice = i;
    235 		ValidateChoice();
    236 	}
    237 }
    238 
    239 bool idChoiceWindow::ParseInternalVar(const char *_name, idTokenParser *src) {
    240 	if (idStr::Icmp(_name, "choicetype") == 0) {
    241 		choiceType = src->ParseInt();
    242 		return true;
    243 	}
    244 	if (idStr::Icmp(_name, "currentchoice") == 0) {
    245 		currentChoice = src->ParseInt();
    246 		return true;
    247 	}
    248 	return idWindow::ParseInternalVar(_name, src);
    249 }
    250 
    251 
    252 idWinVar *idChoiceWindow::GetWinVarByName(const char *_name, bool fixup, drawWin_t** owner) {
    253 	if ( idStr::Icmp( _name, "choices" ) == 0 ) {
    254 		return &choicesStr;
    255 	}
    256 	if ( idStr::Icmp( _name, "values" ) == 0 ) {
    257 		return &choiceVals;
    258 	}
    259 	if ( idStr::Icmp( _name, "cvar" ) == 0 ) {
    260 		return &cvarStr;
    261 	}
    262 	if ( idStr::Icmp( _name, "gui" ) == 0 ) {
    263 		return &guiStr;
    264 	}
    265 	if ( idStr::Icmp( _name, "liveUpdate" ) == 0 ) {
    266 		return &liveUpdate;
    267 	}
    268 	if ( idStr::Icmp( _name, "updateGroup" ) == 0 ) {
    269 		return &updateGroup;
    270 	}
    271 	
    272 	return idWindow::GetWinVarByName(_name, fixup, owner);
    273 }
    274 
    275 // update the lists whenever the WinVar have changed
    276 void idChoiceWindow::UpdateChoicesAndVals() {
    277 	idToken token;
    278 	idStr str2, str3;
    279 	idLexer src;
    280 
    281 	if ( latchedChoices.Icmp( choicesStr ) ) {
    282 		choices.Clear();
    283 		src.FreeSource();
    284 		src.SetFlags( LEXFL_NOFATALERRORS | LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
    285 		src.LoadMemory( choicesStr, choicesStr.Length(), "<ChoiceList>" );
    286 		if ( src.IsLoaded() ) {
    287 			while( src.ReadToken( &token ) ) {
    288 				if ( token == ";" ) {
    289 					if ( str2.Length() ) {
    290 						str2.StripTrailingWhitespace();
    291 						str2 = idLocalization::GetString( str2 );
    292 						choices.Append(str2);
    293 						str2 = "";
    294 					}
    295 					continue;
    296 				}
    297 				str2 += token;
    298 				str2 += " ";
    299 			}
    300 			if ( str2.Length() ) {
    301 				str2.StripTrailingWhitespace();
    302 				choices.Append( str2 );
    303 			}
    304 		}
    305 		latchedChoices = choicesStr.c_str();
    306 	}
    307 	if ( choiceVals.Length() && latchedVals.Icmp( choiceVals ) ) {
    308 		values.Clear();
    309 		src.FreeSource();
    310 		src.SetFlags( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
    311 		src.LoadMemory( choiceVals, choiceVals.Length(), "<ChoiceVals>" );
    312 		str2 = "";
    313 		bool negNum = false;
    314 		if ( src.IsLoaded() ) {
    315 			while( src.ReadToken( &token ) ) {
    316 				if (token == "-") {
    317 					negNum = true;
    318 					continue;
    319 				} 
    320 				if (token == ";") {
    321 					if (str2.Length()) {
    322 						str2.StripTrailingWhitespace();
    323 						values.Append( str2 );
    324 						str2 = "";
    325 					}
    326 					continue;
    327 				}
    328 				if ( negNum ) {
    329 					str2 += "-";
    330 					negNum = false;
    331 				}
    332 				str2 += token;
    333 				str2 += " ";
    334 			}
    335 			if ( str2.Length() ) {
    336 				str2.StripTrailingWhitespace();
    337 				values.Append( str2 );
    338 			}
    339 		}
    340 		if ( choices.Num() != values.Num() ) {
    341 			common->Warning( "idChoiceWindow:: gui '%s' window '%s' has value count unequal to choices count", gui->GetSourceFile(), name.c_str());
    342 		}
    343 		latchedVals = choiceVals.c_str();
    344 	}
    345 }
    346 
    347 void idChoiceWindow::PostParse() {
    348 	idWindow::PostParse();
    349 	UpdateChoicesAndVals();
    350 
    351 	InitVars();
    352 	UpdateChoice();
    353 	UpdateVars(false);
    354 
    355 	flags |= WIN_CANFOCUS;
    356 }
    357 
    358 void idChoiceWindow::Draw(int time, float x, float y) {
    359 	idVec4 color = foreColor;
    360 
    361 	UpdateChoicesAndVals();
    362 	UpdateChoice();
    363 
    364 	// FIXME: It'd be really cool if textAlign worked, but a lot of the guis have it set wrong because it used to not work
    365 	textAlign = 0;
    366 
    367 	if ( textShadow ) {
    368 		idStr shadowText = choices[currentChoice];
    369 		idRectangle shadowRect = textRect;
    370 
    371 		shadowText.RemoveColors();
    372 		shadowRect.x += textShadow;
    373 		shadowRect.y += textShadow;
    374 
    375 		dc->DrawText( shadowText, textScale, textAlign, colorBlack, shadowRect, false, -1 );
    376 	}
    377 
    378 	if ( hover && !noEvents && Contains(gui->CursorX(), gui->CursorY()) ) {
    379 		color = hoverColor;
    380 	} else {
    381 		hover = false;
    382 	}
    383 	if ( flags & WIN_FOCUS ) {
    384 		color = hoverColor;
    385 	}
    386 
    387 	dc->DrawText( choices[currentChoice], textScale, textAlign, color, textRect, false, -1 );
    388 }
    389 
    390 void idChoiceWindow::Activate( bool activate, idStr &act ) {
    391 	idWindow::Activate( activate, act );
    392 	if ( activate ) {
    393 		// sets the gui state based on the current choice the window contains
    394 		UpdateChoice();
    395 	}
    396 }