00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "../client.h"
00026 #include "ui_main.h"
00027 #include "ui_internal.h"
00028 #include "ui_nodes.h"
00029 #include "node/ui_node_linechart.h"
00030 #include "node/ui_node_option.h"
00031
00035 static const char *const ui_sharedDataIDNames[] = {
00036 "",
00037 "TEXT_STANDARD",
00038 "TEXT_LIST",
00039 "TEXT_LIST2",
00040 "TEXT_UFOPEDIA",
00041 "TEXT_UFOPEDIA_REQUIREMENT",
00042 "TEXT_BUILDINGS",
00043 "TEXT_BUILDING_INFO",
00044 "TEXT_RESEARCH",
00045 "TEXT_POPUP",
00046 "TEXT_POPUP_INFO",
00047 "TEXT_AIRCRAFT_LIST",
00048 "TEXT_AIRCRAFT_INFO",
00049 "TEXT_CAMPAIGN_LIST",
00050 "TEXT_MULTISELECTION",
00051 "TEXT_PRODUCTION_LIST",
00052 "TEXT_PRODUCTION_AMOUNT",
00053 "TEXT_PRODUCTION_INFO",
00054 "TEXT_EMPLOYEE",
00055 "TEXT_MOUSECURSOR_RIGHT",
00056 "TEXT_PRODUCTION_QUEUED",
00057 "TEXT_STATS_BASESUMMARY",
00058 "TEXT_STATS_MISSION",
00059 "TEXT_STATS_BASES",
00060 "TEXT_STATS_NATIONS",
00061 "TEXT_STATS_EMPLOYEES",
00062 "TEXT_STATS_COSTS",
00063 "TEXT_STATS_INSTALLATIONS",
00064 "TEXT_STATS_7",
00065 "TEXT_BASE_LIST",
00066 "TEXT_BASE_INFO",
00067 "TEXT_TRANSFER_LIST",
00068 "TEXT_TRANSFER_LIST_AMOUNT",
00069 "TEXT_TRANSFER_LIST_TRANSFERED",
00070 "TEXT_MOUSECURSOR_PLAYERNAMES",
00071 "TEXT_CARGO_LIST",
00072 "TEXT_CARGO_LIST_AMOUNT",
00073 "TEXT_UFOPEDIA_MAILHEADER",
00074 "TEXT_UFOPEDIA_MAIL",
00075 "TEXT_MARKET_NAMES",
00076 "TEXT_MARKET_STORAGE",
00077 "TEXT_MARKET_MARKET",
00078 "TEXT_MARKET_PRICES",
00079 "TEXT_CHAT_WINDOW",
00080 "TEXT_AIREQUIP_1",
00081 "TEXT_AIREQUIP_2",
00082 "TEXT_BASEDEFENCE_LIST",
00083 "TEXT_TIPOFTHEDAY",
00084 "TEXT_GENERIC",
00085 "TEXT_XVI",
00086 "TEXT_MOUSECURSOR_TOP",
00087 "TEXT_MOUSECURSOR_BOTTOM",
00088 "TEXT_MOUSECURSOR_LEFT",
00089 "TEXT_MESSAGEOPTIONS",
00090 "TEXT_UFORECOVERY_NATIONS",
00091 "TEXT_UFORECOVERY_UFOYARDS",
00092 "TEXT_UFORECOVERY_CAPACITIES",
00093 "TEXT_MATERIAL_STAGES",
00094 "TEXT_IRCCONTENT",
00095 "TEXT_IRCUSERS",
00096 "TEXT_MULTIPLAYER_USERLIST",
00097 "TEXT_MULTIPLAYER_USERTEAM",
00098 "TEXT_ITEMDESCRIPTION",
00099
00100 "OPTION_LANGUAGES",
00101 "OPTION_JOYSTICKS",
00102 "OPTION_VIDEO_RESOLUTIONS",
00103 "OPTION_SINGLEPLAYER_SKINS",
00104 "OPTION_MULTIPLAYER_SKINS",
00105 "OPTION_UFOPEDIA",
00106 "OPTION_UFOS",
00107 "OPTION_DROPSHIPS",
00108 "OPTION_BASELIST",
00109 "OPTION_TEAMDEFS",
00110
00111 "LINESTRIP_FUNDING",
00112 "LINESTRIP_COLOR"
00113 };
00114 CASSERT(lengthof(ui_sharedDataIDNames) == UI_MAX_DATAID);
00115
00120 int UI_GetDataIDByName (const char* name)
00121 {
00122 int num;
00123 for (num = 0; num < UI_MAX_DATAID; num++)
00124 if (!strcmp(name, ui_sharedDataIDNames[num]))
00125 return num;
00126
00127 return -1;
00128 }
00129
00134 void UI_RegisterText (int dataId, const char *text)
00135 {
00136 UI_ResetData(dataId);
00137
00138 if (!text)
00139 return;
00140
00141 ui_global.sharedData[dataId].type = UI_SHARED_TEXT;
00142 ui_global.sharedData[dataId].data.text = text;
00143 ui_global.sharedData[dataId].versionId++;
00144 }
00145
00150 void UI_RegisterLinkedListText (int dataId, linkedList_t *text)
00151 {
00153 if (ui_global.sharedData[dataId].type == UI_SHARED_LINKEDLISTTEXT && ui_global.sharedData[dataId].data.linkedListText == text) {
00154 ui_global.sharedData[dataId].versionId++;
00155 return;
00156 }
00157 UI_ResetData(dataId);
00158 ui_global.sharedData[dataId].type = UI_SHARED_LINKEDLISTTEXT;
00159 ui_global.sharedData[dataId].data.linkedListText = text;
00160 ui_global.sharedData[dataId].versionId++;
00161 }
00162
00163 const char *UI_GetText (int textId)
00164 {
00165 if (ui_global.sharedData[textId].type != UI_SHARED_TEXT)
00166 return NULL;
00167 return ui_global.sharedData[textId].data.text;
00168 }
00169
00170 int UI_GetDataVersion (int textId)
00171 {
00172 return ui_global.sharedData[textId].versionId;
00173 }
00174
00181 static void UI_InitOption (uiNode_t* option, const char* label, const char* value)
00182 {
00183 assert(option);
00184 assert(option->behaviour == ui_optionBehaviour);
00185 Q_strncpyz(OPTIONEXTRADATA(option).label, label, sizeof(OPTIONEXTRADATA(option).label));
00186 Q_strncpyz(OPTIONEXTRADATA(option).value, value, sizeof(OPTIONEXTRADATA(option).value));
00187 }
00188
00197 uiNode_t* UI_AddOption (uiNode_t** tree, const char* name, const char* label, const char* value)
00198 {
00199 uiNode_t *last;
00200 uiNode_t *option;
00201 assert(tree != NULL);
00202
00203 option = UI_AllocNode(name, "option", qtrue);
00204 UI_InitOption(option, label, value);
00205
00206
00207 last = *tree;
00208 if (last != NULL) {
00209 while (last->next)
00210 last = last->next;
00211 }
00212
00213 if (last)
00214 last->next = option;
00215 else
00216 *tree = option;
00217
00218 return option;
00219 }
00220
00226 static void UI_DeleteOption (uiNode_t* tree)
00227 {
00228 while (tree) {
00229 uiNode_t* del = tree;
00230 tree = tree->next;
00231 UI_DeleteNode(del);
00232 }
00233 }
00234
00238 void UI_ResetData (int dataId)
00239 {
00240 assert(dataId < UI_MAX_DATAID);
00241 assert(dataId >= 0);
00242
00243 switch (ui_global.sharedData[dataId].type) {
00244 case UI_SHARED_LINKEDLISTTEXT:
00245 LIST_Delete(&ui_global.sharedData[dataId].data.linkedListText);
00246 break;
00247 case UI_SHARED_OPTION:
00248 if (_Mem_AllocatedInPool(com_genericPool, ui_global.sharedData[dataId].data.option)) {
00249 UI_DeleteOption(ui_global.sharedData[dataId].data.option);
00250 }
00251 break;
00252 default:
00253 break;
00254 }
00255
00256 ui_global.sharedData[dataId].type = UI_SHARED_NONE;
00257 ui_global.sharedData[dataId].data.text = NULL;
00258 ui_global.sharedData[dataId].versionId++;
00259 }
00260
00266 static uiNode_t *UI_OptionNodeRemoveHigherOption (uiNode_t **option)
00267 {
00268 uiNode_t *prev = *option;
00269 uiNode_t *prevfind = NULL;
00270 uiNode_t *search = (*option)->next;
00271 const char *label = OPTIONEXTRADATA(*option).label;
00272
00273 if (label[0] == '_')
00274 label = _(label + 1);
00275
00276
00277 while (search) {
00278 const char *searchlabel = OPTIONEXTRADATA(search).label;
00279
00280 if (searchlabel[0] == '_')
00281 searchlabel = _(searchlabel + 1);
00282
00283 if (strcmp(label, searchlabel) < 0) {
00284 prevfind = prev;
00285 label = searchlabel;
00286 }
00287 prev = search;
00288 search = search->next;
00289 }
00290
00291
00292 if (prevfind == NULL) {
00293 uiNode_t *tmp = *option;
00294 *option = (*option)->next;
00295 return tmp;
00296 } else {
00297 uiNode_t *tmp = prevfind->next;
00298 prevfind->next = tmp->next;
00299 return tmp;
00300 }
00301 }
00302
00306 void UI_SortOptions (uiNode_t **first)
00307 {
00308 uiNode_t *option;
00309
00310
00311 option = *first;
00312 if (option == NULL)
00313 return;
00314 *first = NULL;
00315
00316
00317 while (option) {
00318 uiNode_t *element;
00319 element = UI_OptionNodeRemoveHigherOption(&option);
00320 element->next = *first;
00321 *first = element;
00322 }
00323 }
00324
00330 void UI_UpdateInvisOptions (uiNode_t *option, const linkedList_t *stringList)
00331 {
00332 if (option == NULL || stringList == NULL)
00333 return;
00334
00335 while (option) {
00336 if (LIST_ContainsString(stringList, option->name))
00337 option->invis = qfalse;
00338 else
00339 option->invis = qtrue;
00340 option = option->next;
00341 }
00342 }
00343
00344 void UI_RegisterOption (int dataId, uiNode_t *option)
00345 {
00347 if (ui_global.sharedData[dataId].type == UI_SHARED_OPTION && ui_global.sharedData[dataId].data.option == option) {
00348 ui_global.sharedData[dataId].versionId++;
00349 return;
00350 }
00351 UI_ResetData(dataId);
00352 ui_global.sharedData[dataId].type = UI_SHARED_OPTION;
00353 ui_global.sharedData[dataId].data.option = option;
00354 ui_global.sharedData[dataId].versionId++;
00355 }
00356
00357 void UI_RegisterLineStrip (int dataId, lineStrip_t *lineStrip)
00358 {
00359 UI_ResetData(dataId);
00360 ui_global.sharedData[dataId].type = UI_SHARED_LINESTRIP;
00361 ui_global.sharedData[dataId].data.lineStrip = lineStrip;
00362 ui_global.sharedData[dataId].versionId++;
00363 }
00364
00365 uiNode_t *UI_GetOption (int dataId)
00366 {
00367 if (ui_global.sharedData[dataId].type == UI_SHARED_OPTION) {
00368 return ui_global.sharedData[dataId].data.option;
00369 }
00370 return NULL;
00371 }
00372
00379 static uiNode_t* UI_FindOptionAtIndex (int index, uiNode_t* option, uiOptionIterator_t* iterator)
00380 {
00381 while (option) {
00382 assert(option->behaviour == ui_optionBehaviour);
00383 if (option->invis) {
00384 option = option->next;
00385 continue;
00386 }
00387
00388
00389 if (index == 0) {
00390 iterator->option = option;
00391 return option;
00392 }
00393
00394
00395 index--;
00396
00397 if (OPTIONEXTRADATA(option).collapsed) {
00398 option = option->next;
00399 continue;
00400 }
00401
00402
00403 if (index < OPTIONEXTRADATA(option).childCount) {
00404 if (iterator->depthPos >= MAX_DEPTH_OPTIONITERATORCACHE)
00405 assert(qfalse);
00406 iterator->depthCache[iterator->depthPos] = option;
00407 iterator->depthPos++;
00408 return UI_FindOptionAtIndex(index, option->firstChild, iterator);
00409 }
00410 index -= OPTIONEXTRADATA(option).childCount;
00411 option = option->next;
00412 }
00413
00414 iterator->option = NULL;
00415 return NULL;
00416 }
00417
00435 uiNode_t* UI_InitOptionIteratorAtIndex (int index, uiNode_t* option, uiOptionIterator_t* iterator)
00436 {
00437 assert(option == NULL || option->behaviour == ui_optionBehaviour);
00438 memset(iterator, 0, sizeof(*iterator));
00439 iterator->skipCollapsed = qtrue;
00440 iterator->skipInvisible = qtrue;
00441 return UI_FindOptionAtIndex(index, option, iterator);
00442 }
00443
00448 uiNode_t* UI_OptionIteratorNextOption (uiOptionIterator_t* iterator)
00449 {
00450 uiNode_t* option;
00451
00452 option = iterator->option;
00453 assert(iterator->depthPos < MAX_DEPTH_OPTIONITERATORCACHE);
00454 iterator->depthCache[iterator->depthPos] = option;
00455 iterator->depthPos++;
00456
00457 if (OPTIONEXTRADATA(option).collapsed && iterator->skipCollapsed)
00458 option = NULL;
00459 else
00460 option = option->firstChild;
00461
00462 while (qtrue) {
00463 while (option) {
00464 if (!option->invis || !iterator->skipInvisible) {
00465 iterator->option = option;
00466 return option;
00467 }
00468 option = option->next;
00469 }
00470 if (iterator->depthPos == 0)
00471 break;
00472 iterator->depthPos--;
00473 option = iterator->depthCache[iterator->depthPos]->next;
00474 }
00475
00476 iterator->option = NULL;
00477 return NULL;
00478 }
00479
00486 uiNode_t* UI_FindOptionByValue (uiOptionIterator_t* iterator, const char* value)
00487 {
00488 while (iterator->option) {
00489 assert(iterator->option->behaviour == ui_optionBehaviour);
00490 if (!strcmp(OPTIONEXTRADATA(iterator->option).value, value))
00491 return iterator->option;
00492 UI_OptionIteratorNextOption(iterator);
00493 }
00494 return NULL;
00495 }
00496
00503 int UI_FindOptionPosition (uiOptionIterator_t* iterator, const uiNode_t* option)
00504 {
00505 int i = 0;
00506 while (iterator->option) {
00507 if (iterator->option == option)
00508 return i;
00509 i++;
00510 UI_OptionIteratorNextOption(iterator);
00511 }
00512 return -1;
00513 }
00514
00520 static void UI_ResetData_f (void)
00521 {
00522 if (Cmd_Argc() == 2) {
00523 const char *dataId = Cmd_Argv(1);
00524 const int id = UI_GetDataIDByName(dataId);
00525 if (id == -1)
00526 Com_Printf("%s: invalid data ID: %s\n", Cmd_Argv(0), dataId);
00527 else
00528 UI_ResetData(id);
00529 } else {
00530 int i;
00531 for (i = 0; i < UI_MAX_DATAID; i++)
00532 UI_ResetData(i);
00533 }
00534 }
00535
00540 void UI_InitData (void)
00541 {
00542 Cmd_AddCommand("mn_datareset", UI_ResetData_f, "Resets memory and data used by a UI data id");
00543 }