|
Atrinik Client 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00038 #include <global.h> 00039 00040 static int load_interface_file(char *filename); 00041 static void process_widget(widgetdata *widget); 00042 00044 static widgetdata def_widget[TOTAL_SUBWIDGETS]; 00045 00047 /* {name, x1, y1, wd, ht, moveable?, show?, redraw?, unique?, no_kill?, visible?, delete_inv?, save?, save_width_height? 00048 * * the next members are used internally * 00049 * next(NULL), prev(NULL), inv(NULL), inv_rev(NULL), env(NULL), type_next(NULL), type_prev(NULL), 00050 * subwidget(NULL), widgetSF(NULL), WidgetTypeID(0), WidgetSubtypeID(0), WidgetObjID(0)} */ 00051 static const widgetdata con_widget[TOTAL_SUBWIDGETS] = 00052 { 00053 /* base widgets */ 00054 {"MAP", 0, 10, 850, 600, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 1}, 00055 {"STATS", 227, 0, 172, 102, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00056 {"RESIST", 497, 0, 198, 79, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00057 {"MAIN_LVL", 399, 39, 98, 62, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00058 {"SKILL_EXP", 497, 79, 198, 22, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00059 {"REGEN", 399, 0, 98, 39, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00060 {"SKILL_LVL", 695, 0, 52, 101, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00061 {"MENUBUTTONS", 747, 0, 47, 101, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00062 {"QUICKSLOTS", 735, 489, 282, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00063 {"CHATWIN", 631, 540, 392, 226, 1, 1, 1, 0, 1, 1, 1, 1, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 1, 80, 80, 0, 0}, 00064 {"MSGWIN", 1, 540, 308, 226, 1, 1, 1, 0, 1, 1, 1, 1, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 1, 80, 80, 0, 0}, 00065 {"PLAYERDOLL", 0, 41, 219, 243, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00066 {"BELOWINV", 331, 713, 274, 55, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00067 {"PLAYERINFO", 0, 0, 219, 41, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00068 {"RANGEBOX", 6, 51, 94, 60, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00069 {"TARGET", 336, 681, 264, 31, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00070 {"MAININV", 1, 508, 271, 32, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00071 {"MAPNAME", 228, 106, 36, 16, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00072 {"CONSOLE", 339, 655, 256, 25, 1, 0, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00073 {"NUMBER", 340, 637, 256, 43, 1, 0, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00074 {"FPS", 123, 47, 70, 22, 1, 1, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00075 {"MPLAYER", 474, 101, 320, 190, 1, 0, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00076 {"SPELLS", 474, 101, 320, 190, 1, 0, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00077 {"SKILLS", 474, 101, 320, 190, 1, 0, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00078 {"PARTY", 474, 101, 320, 190, 1, 0, 1, 1, 1, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00079 {"CONTAINER", 0, 0, 128, 128, 1, 0, 1, 0, 1, 1, 0, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00080 {"LABEL", 0, 0, 5, 5, 1, 1, 1, 0, 0, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00081 {"BITMAP", 0, 0, 5, 5, 1, 1, 1, 0, 0, 1, 1, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00082 /* subwidgets */ 00083 {"CONTAINER_STRIP", 0, 0, 128, 128, 1, 0, 1, 0, 1, 1, 0, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00084 {"MENU", 0, 0, 5, 5, 0, 1, 1, 0, 0, 1, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00085 {"MENUITEM", 0, 0, 5, 5, 0, 1, 1, 0, 0, 0, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}, 00086 }; 00087 00088 00089 /* Default overall priority tree. Will change during runtime. 00090 * Widget at the top (head) of the tree has highest priority. 00091 * Events go to the top (head) of the tree first. 00092 * Displaying goes to the right (foot) of the tree first. */ 00094 static widgetdata *widget_list_head; 00096 static widgetdata *widget_list_foot; 00097 00101 /* TODO: change cur_widget to type_list_head */ 00102 widgetdata *cur_widget[TOTAL_SUBWIDGETS]; 00103 static widgetdata *type_list_foot[TOTAL_SUBWIDGETS]; 00104 00108 widgetevent widget_mouse_event = 00109 { 00110 NULL, 0, 0 00111 }; 00112 00114 static widgetmove widget_event_move = 00115 { 00116 0, NULL, 0, 0 00117 }; 00118 00120 static widgetresize widget_event_resize = 00121 { 00122 0, NULL 00123 }; 00124 00128 static int IsMouseExclusive = 0; 00129 00133 static void init_widgets_fromDefault() 00134 { 00135 int lp; 00136 00137 /* Exit, if there are no widget IDs */ 00138 if (!TOTAL_SUBWIDGETS) 00139 { 00140 return; 00141 } 00142 00143 /* Store the constant default widget lookup in the current lookup(s) */ 00144 for (lp = 0; lp < TOTAL_SUBWIDGETS; ++lp) 00145 { 00146 def_widget[lp] = con_widget[lp]; 00147 } 00148 00149 /* Initiate the linked lists for the widgets. */ 00150 init_widgets(); 00151 } 00152 00156 void init_widgets_fromCurrent() 00157 { 00158 /* Exit, if there are no widgets */ 00159 if (!TOTAL_SUBWIDGETS) 00160 { 00161 return; 00162 } 00163 00164 /* If can't open/load the interface file load defaults and create file */ 00165 if (!load_interface_file(INTERFACE_FILE)) 00166 { 00167 /* Inform user */ 00168 LOG(llevInfo, "Can't open/load the interface file - %s. Resetting\n", INTERFACE_FILE); 00169 00170 /* Load the defaults - this also allocates priority list */ 00171 init_widgets_fromDefault(); 00172 00173 /* Create the interface file */ 00174 save_interface_file(); 00175 } 00176 } 00177 00179 widgetdata *create_widget_object(int widget_subtype_id) 00180 { 00181 widgetdata *widget; 00182 textwin_struct *textwin; 00183 _widget_container *container; 00184 _widget_container_strip *container_strip; 00185 _menu *menu; 00186 _menuitem *menuitem; 00187 _widget_label *label; 00188 _widget_bitmap *bitmap; 00189 int widget_type_id = widget_subtype_id; 00190 00191 /* map the widget subtype to widget type */ 00192 if (widget_subtype_id >= TOTAL_WIDGETS) 00193 { 00194 switch (widget_subtype_id) 00195 { 00196 case CONTAINER_STRIP_ID: 00197 case MENU_ID: 00198 case MENUITEM_ID: 00199 widget_type_id = CONTAINER_ID; 00200 break; 00201 00202 /* no subtype was found, so get out of here */ 00203 default: 00204 return NULL; 00205 } 00206 } 00207 00208 /* sanity check */ 00209 if (widget_subtype_id < 0 || widget_subtype_id >= TOTAL_SUBWIDGETS) 00210 { 00211 return NULL; 00212 } 00213 00214 /* don't create more than one widget if it is a unique widget */ 00215 if (con_widget[widget_subtype_id].unique && cur_widget[widget_subtype_id]) 00216 { 00217 return NULL; 00218 } 00219 00220 /* allocate the widget node, this should always be the first function called in here */ 00221 widget = create_widget(widget_subtype_id); 00222 widget->WidgetTypeID = widget_type_id; 00223 00224 /* allocate the custom attributes for the widget if applicable */ 00225 switch (widget->WidgetTypeID) 00226 { 00227 case CHATWIN_ID: 00228 case MSGWIN_ID: 00229 textwin = calloc(1, sizeof(textwin_struct)); 00230 00231 if (!textwin) 00232 { 00233 exit(0); 00234 } 00235 00236 textwin->font = FONT_ARIAL11; 00237 textwin->selection_start = -1; 00238 textwin->selection_end = -1; 00239 /* that's right, a void * cast to _textwin *. 00240 * usually it's not a nice thing to do, but in this case it's an excellent way of extending a struct */ 00241 widget->subwidget = (textwin_struct *) textwin; 00242 break; 00243 00244 case MAPNAME_ID: 00245 /* set the bounding box to another one that exists, otherwise it can be wrong initially */ 00246 if (cur_widget[MAPNAME_ID]) 00247 { 00248 widget->wd = cur_widget[MAPNAME_ID]->wd; 00249 widget->ht = cur_widget[MAPNAME_ID]->ht; 00250 } 00251 00252 break; 00253 00254 case CONTAINER_ID: 00255 container = malloc(sizeof(_widget_container)); 00256 00257 if (!container) 00258 { 00259 exit(0); 00260 } 00261 00262 /* begin initializing the members */ 00263 container->widget_type = -1; 00264 container->outer_padding_top = 10; 00265 container->outer_padding_bottom = 10; 00266 container->outer_padding_left = 10; 00267 container->outer_padding_right = 10; 00268 container->x_left_buf1 = 0; 00269 container->x_left_buf2 = 0; 00270 container->x_right_buf1 = 0; 00271 container->x_right_buf2 = 0; 00272 container->y_top_buf1 = 0; 00273 container->y_top_buf2 = 0; 00274 container->y_bottom_buf1 = 0; 00275 container->y_bottom_buf2 = 0; 00276 /* have the subwidget point to it */ 00277 widget->subwidget = (_widget_container *) container; 00278 00279 /* allocate the custom attributes for the container if applicable */ 00280 switch (widget->WidgetSubtypeID) 00281 { 00282 case CONTAINER_STRIP_ID: 00283 case MENU_ID: 00284 case MENUITEM_ID: 00285 container_strip = malloc(sizeof(_widget_container_strip)); 00286 00287 if (!container_strip) 00288 { 00289 exit(0); 00290 } 00291 00292 /* Begin initializing the members. */ 00293 container_strip->inner_padding = 10; 00294 container_strip->horizontal = 0; 00295 container_strip->size = 0; 00296 /* Have the subcontainer point to it. */ 00297 container->subcontainer = (_widget_container_strip *) container_strip; 00298 00299 /* Allocate the custom attributes for the strip container if applicable. */ 00300 switch (widget->WidgetSubtypeID) 00301 { 00302 case MENU_ID: 00303 menu = malloc(sizeof(_menu)); 00304 00305 if (!menu) 00306 { 00307 exit(0); 00308 } 00309 00310 /* Begin initializing the members. */ 00311 menu->submenu = NULL; 00312 menu->owner = NULL; 00313 /* Have the sub strip container point to it. */ 00314 container_strip->subcontainer_strip = (_menu *) menu; 00315 break; 00316 00317 case MENUITEM_ID: 00318 menuitem = malloc(sizeof(_menuitem)); 00319 00320 if (!menuitem) 00321 { 00322 exit(0); 00323 } 00324 00325 /* Begin initializing the members. */ 00326 menuitem->menu_func_ptr = NULL; 00327 menuitem->menu_type = MENU_NORMAL; 00328 /* Have the sub strip container point to it. */ 00329 container_strip->subcontainer_strip = (_menuitem *) menuitem; 00330 break; 00331 } 00332 00333 break; 00334 } 00335 00336 break; 00337 00338 case LABEL_ID: 00339 label = malloc(sizeof(_widget_label)); 00340 00341 if (!label) 00342 { 00343 exit(0); 00344 } 00345 00346 /* begin initializing the members */ 00347 label->text = ""; 00348 label->font = FONT_ARIAL10; 00349 label->color = COLOR_WHITE; 00350 /* have the subwidget point to it */ 00351 widget->subwidget = (_widget_label *) label; 00352 break; 00353 00354 case BITMAP_ID: 00355 bitmap = malloc(sizeof(_widget_bitmap)); 00356 00357 if (!bitmap) 00358 { 00359 exit(0); 00360 } 00361 00362 /* begin initializing the members */ 00363 bitmap->bitmap_id = 0; 00364 /* have the subwidget point to it */ 00365 widget->subwidget = (_widget_bitmap *) bitmap; 00366 break; 00367 } 00368 00369 return widget; 00370 } 00371 00373 void remove_widget_object(widgetdata *widget) 00374 { 00375 /* don't delete the last widget if there needs to be at least one of this widget type */ 00376 if (widget->no_kill && cur_widget[widget->WidgetSubtypeID] == type_list_foot[widget->WidgetSubtypeID]) 00377 { 00378 return; 00379 } 00380 00381 remove_widget_object_intern(widget); 00382 } 00383 00388 void remove_widget_object_intern(widgetdata *widget) 00389 { 00390 widgetdata *tmp; 00391 _widget_container *container; 00392 _widget_container_strip *container_strip; 00393 int widget_subtype_id = widget->WidgetSubtypeID; 00394 00395 /* If this flag is enabled, we need to delete all contents of the widget too, which calls for some recursion. */ 00396 if (widget->delete_inv) 00397 { 00398 remove_widget_inv(widget); 00399 } 00400 00401 /* If this widget happens to be the owner of an event, keeping them pointed to it is a bad idea. */ 00402 if (widget_mouse_event.owner == widget) 00403 { 00404 widget_mouse_event.owner = NULL; 00405 } 00406 00407 if (widget_event_move.owner == widget) 00408 { 00409 widget_event_move.owner = NULL; 00410 } 00411 00412 if (widget_event_resize.owner == widget) 00413 { 00414 widget_event_resize.owner = NULL; 00415 } 00416 00417 /* If any menu is open and this widget is the owner, bad things could happen here too. Clear the pointers. */ 00418 if (cur_widget[MENU_ID] && (MENU(cur_widget[MENU_ID]))->owner == widget) 00419 { 00420 for (tmp = cur_widget[MENU_ID]; tmp; tmp = tmp->type_next) 00421 { 00422 (MENU(cur_widget[MENU_ID]))->owner = NULL; 00423 } 00424 } 00425 00426 /* Get the environment if it exists, this is used to make containers auto-resize when the widget is deleted. */ 00427 tmp = widget->env; 00428 00429 /* remove the custom attribute nodes if they exist */ 00430 if (widget->subwidget) 00431 { 00432 switch (widget_subtype_id) 00433 { 00434 case CONTAINER_STRIP_ID: 00435 case MENU_ID: 00436 case MENUITEM_ID: 00437 if (widget_subtype_id == MENUITEM_ID) 00438 { 00439 container_strip = CONTAINER_STRIP(widget); 00440 00441 if (container_strip->subcontainer_strip) 00442 { 00443 free(container_strip->subcontainer_strip); 00444 container_strip->subcontainer_strip = NULL; 00445 } 00446 } 00447 00448 container = CONTAINER(widget); 00449 00450 if (container->subcontainer) 00451 { 00452 free(container->subcontainer); 00453 container->subcontainer = NULL; 00454 } 00455 00456 break; 00457 00458 case CHATWIN_ID: 00459 case MSGWIN_ID: 00460 { 00461 textwin_struct *textwin = TEXTWIN(widget); 00462 00463 if (textwin->entries) 00464 { 00465 free(textwin->entries); 00466 } 00467 00468 break; 00469 } 00470 } 00471 00472 free(widget->subwidget); 00473 widget->subwidget = NULL; 00474 } 00475 00476 switch (widget_subtype_id) 00477 { 00478 case MPLAYER_ID: 00479 widget_mplayer_deinit(widget); 00480 break; 00481 } 00482 00483 /* finally de-allocate the widget node, this should always be the last node removed in here */ 00484 remove_widget(widget); 00485 00486 /* resize the container that used to contain this widget, if it exists */ 00487 if (tmp) 00488 { 00489 /* if something else exists in its inventory, make it auto-resize to fit the widgets inside */ 00490 if (tmp->inv) 00491 { 00492 resize_widget(tmp->inv, RESIZE_RIGHT, tmp->inv->wd); 00493 resize_widget(tmp->inv, RESIZE_BOTTOM, tmp->inv->ht); 00494 } 00495 /* otherwise if its inventory is empty, resize it to its default size */ 00496 else 00497 { 00498 resize_widget(tmp, RESIZE_RIGHT, con_widget[tmp->WidgetSubtypeID].wd); 00499 resize_widget(tmp, RESIZE_BOTTOM, con_widget[tmp->WidgetSubtypeID].ht); 00500 } 00501 } 00502 } 00503 00509 void remove_widget_inv(widgetdata *widget) 00510 { 00511 widgetdata *tmp; 00512 00513 for (widget = widget->inv; widget; widget = tmp) 00514 { 00515 /* call this function recursively to get to the first child node deep down inside the widget */ 00516 remove_widget_inv(widget); 00517 /* we need a temp pointer for the next node, as the current node is about to be no more */ 00518 tmp = widget->next; 00519 /* then remove the widget, and slowly work our way up the tree deleting widgets until we get to the original widget again */ 00520 remove_widget_object(widget); 00521 } 00522 } 00523 00525 /* TODO: this is looking more and more like a function to simply initiate all the widgets with their default attributes, 00526 * as loading from a file now creates nodes dynamically instead, so this function is now doomed to that role */ 00527 void init_widgets() 00528 { 00529 int i; 00530 00531 /* exit, if there're no widgets */ 00532 if (!TOTAL_SUBWIDGETS) 00533 { 00534 return; 00535 } 00536 00537 /* in all cases should reset */ 00538 kill_widgets(); 00539 00540 /* initiate the widget tree and everything else that links to it. */ 00541 for (i = 0; i < TOTAL_SUBWIDGETS; ++i) 00542 { 00543 if (!con_widget[i].no_kill) 00544 { 00545 continue; 00546 } 00547 00548 create_widget_object(i); 00549 } 00550 00551 LOG(llevDebug, "..Allocated %d nodes!\n", i); 00552 } 00553 00556 void kill_widgets() 00557 { 00558 /* get rid of the pointer to the widgets first */ 00559 widget_mouse_event.owner = NULL; 00560 widget_event_move.owner = NULL; 00561 widget_event_resize.owner = NULL; 00562 00563 /* kick off the chain reaction, there's no turning back now :) */ 00564 if (widget_list_head) 00565 { 00566 kill_widget_tree(widget_list_head); 00567 } 00568 } 00569 00573 void reset_widget(const char *name) 00574 { 00575 widgetdata *tmp; 00576 00577 for (tmp = widget_list_head; tmp; tmp = tmp->next) 00578 { 00579 if (!tmp->moveable) 00580 { 00581 continue; 00582 } 00583 00584 if (!name || !strcasecmp(tmp->name, name)) 00585 { 00586 tmp->x1 = con_widget[tmp->WidgetTypeID].x1; 00587 tmp->y1 = con_widget[tmp->WidgetTypeID].y1; 00588 tmp->wd = con_widget[tmp->WidgetTypeID].wd; 00589 tmp->ht = con_widget[tmp->WidgetTypeID].ht; 00590 tmp->show = con_widget[tmp->WidgetTypeID].show; 00591 WIDGET_REDRAW(tmp); 00592 } 00593 } 00594 } 00595 00599 static void widget_ensure_onscreen(widgetdata *widget) 00600 { 00601 int dx = 0, dy = 0; 00602 00603 if (widget->x1 < 0) 00604 { 00605 dx = -widget->x1; 00606 } 00607 else if (widget->x1 + widget->wd > setting_get_int(OPT_CAT_CLIENT, OPT_RESOLUTION_X)) 00608 { 00609 dx = setting_get_int(OPT_CAT_CLIENT, OPT_RESOLUTION_X) - widget->wd - widget->x1; 00610 } 00611 00612 if (widget->y1 < 0) 00613 { 00614 dy = -widget->y1; 00615 } 00616 else if (widget->y1 + widget->ht > setting_get_int(OPT_CAT_CLIENT, OPT_RESOLUTION_Y)) 00617 { 00618 dy = setting_get_int(OPT_CAT_CLIENT, OPT_RESOLUTION_Y) - widget->ht - widget->y1; 00619 } 00620 00621 move_widget_rec(widget, dx, dy); 00622 } 00623 00626 void widgets_ensure_onscreen() 00627 { 00628 widgetdata *tmp; 00629 00630 for (tmp = widget_list_head; tmp; tmp = tmp->next) 00631 { 00632 widget_ensure_onscreen(tmp); 00633 } 00634 } 00635 00637 void kill_widget_tree(widgetdata *widget) 00638 { 00639 widgetdata *tmp; 00640 00641 do 00642 { 00643 /* we want to process the widgets starting from the left hand side of the tree first */ 00644 if (widget->inv) 00645 { 00646 kill_widget_tree(widget->inv); 00647 } 00648 00649 /* store the next sibling in a tmp variable, as widget is about to be zapped from existence */ 00650 tmp = widget->next; 00651 00652 /* here we call our widget kill function, and force removal by using the internal one */ 00653 remove_widget_object_intern(widget); 00654 00655 /* get the next sibling for our next loop */ 00656 widget = tmp; 00657 } 00658 while (widget); 00659 } 00660 00665 widgetdata *create_widget(int widget_id) 00666 { 00667 widgetdata *node; 00668 /* our unique widget count variable */ 00669 static int widget_uid = 0; 00670 00671 #ifdef DEBUG_WIDGET 00672 LOG(llevInfo, "Entering create_widget()..\n"); 00673 #endif 00674 00675 /* allocate it */ 00676 node = malloc(sizeof(widgetdata)); 00677 00678 if (!node) 00679 { 00680 exit(0); 00681 } 00682 00683 /* set the members */ 00684 /* this also sets all pointers in the struct to NULL */ 00685 *node = con_widget[widget_id]; 00686 node->WidgetSubtypeID = widget_id; 00687 /* give it a unique ID */ 00688 node->WidgetObjID = widget_uid; 00689 00690 /* link it up to the tree if the root exists */ 00691 if (widget_list_head) 00692 { 00693 node->next = widget_list_head; 00694 widget_list_head->prev = node; 00695 } 00696 00697 /* set the foot if it doesn't exist */ 00698 if (!widget_list_foot) 00699 { 00700 widget_list_foot = node; 00701 } 00702 00703 /* the new node becomes the new root node, which also automatically brings it to the front */ 00704 widget_list_head = node; 00705 00706 /* if head of widget type linked list doesn't exist, set the head and foot */ 00707 if (!cur_widget[widget_id]) 00708 { 00709 cur_widget[widget_id] = type_list_foot[widget_id] = node; 00710 } 00711 /* otherwise, link the node in to the existing type list */ 00712 else 00713 { 00714 type_list_foot[widget_id]->type_next = node; 00715 node->type_prev = type_list_foot[widget_id]; 00716 type_list_foot[widget_id] = node; 00717 } 00718 00719 /* increment the unique ID counter */ 00720 ++widget_uid; 00721 00722 #ifdef DEBUG_WIDGET 00723 LOG(llevDebug, "..ALLOCATED: %s, WidgetObjID: %d\n", node->name, node->WidgetObjID); 00724 debug_count_nodes(1); 00725 00726 LOG(llevInfo, "..create_widget(): Done.\n"); 00727 #endif 00728 00729 return node; 00730 } 00731 00733 void remove_widget(widgetdata *widget) 00734 { 00735 widgetdata *tmp = NULL; 00736 00737 #ifdef DEBUG_WIDGET 00738 LOG(llevInfo, "Entering remove_widget()..\n"); 00739 #endif 00740 00741 /* node to delete is the only node in the tree, bye-bye binary tree :) */ 00742 if (!widget_list_head->next && !widget_list_head->inv) 00743 { 00744 widget_list_head = NULL; 00745 widget_list_foot = NULL; 00746 cur_widget[widget->WidgetSubtypeID] = NULL; 00747 type_list_foot[widget->WidgetSubtypeID] = NULL; 00748 } 00749 else 00750 { 00751 /* node to delete is the head, move the pointer to next node */ 00752 if (widget == widget_list_head) 00753 { 00754 widget_list_head = widget_list_head->next; 00755 widget_list_head->prev = NULL; 00756 } 00757 /* node to delete is the foot, move the pointer to the previous node */ 00758 else if (widget == widget_list_foot) 00759 { 00760 widget_list_foot = widget_list_foot->prev; 00761 widget_list_foot->next = NULL; 00762 } 00763 /* node is first sibling, and should have a parent since it is not the root node */ 00764 else if (!widget->prev) 00765 { 00766 /* node is also the last sibling, so NULL the parent's inventory */ 00767 if (!widget->next) 00768 { 00769 widget->env->inv = NULL; 00770 widget->env->inv_rev = NULL; 00771 } 00772 /* or else make it the parent's first child */ 00773 else 00774 { 00775 widget->env->inv = widget->next; 00776 widget->next->prev = NULL; 00777 } 00778 } 00779 /* node is last sibling and should have a parent, move the inv_rev pointer to the previous sibling */ 00780 else if (!widget->next) 00781 { 00782 widget->env->inv_rev = widget->prev; 00783 widget->prev->next = NULL; 00784 } 00785 /* node to delete is in the middle of the tree somewhere */ 00786 else 00787 { 00788 widget->next->prev = widget->prev; 00789 widget->prev->next = widget->next; 00790 } 00791 00792 /* move the children to the top level of the list, starting from the end child */ 00793 for (tmp = widget->inv_rev; tmp; tmp = tmp->prev) 00794 { 00795 /* tmp is no longer in a container */ 00796 tmp->env = NULL; 00797 widget_list_head->prev = tmp; 00798 tmp->next = widget_list_head; 00799 widget_list_head = tmp; 00800 } 00801 00802 /* if widget type list has only one node, kill it */ 00803 if (cur_widget[widget->WidgetSubtypeID] == type_list_foot[widget->WidgetSubtypeID]) 00804 { 00805 cur_widget[widget->WidgetSubtypeID] = type_list_foot[widget->WidgetSubtypeID] = NULL; 00806 } 00807 /* widget is head node */ 00808 else if (widget == cur_widget[widget->WidgetSubtypeID]) 00809 { 00810 cur_widget[widget->WidgetSubtypeID] = cur_widget[widget->WidgetSubtypeID]->type_next; 00811 cur_widget[widget->WidgetSubtypeID]->type_prev = NULL; 00812 } 00813 /* widget is foot node */ 00814 else if (widget == type_list_foot[widget->WidgetSubtypeID]) 00815 { 00816 type_list_foot[widget->WidgetSubtypeID] = type_list_foot[widget->WidgetSubtypeID]->type_prev; 00817 type_list_foot[widget->WidgetSubtypeID]->type_next = NULL; 00818 } 00819 /* widget is in middle of type list */ 00820 else 00821 { 00822 widget->type_prev->type_next = widget->type_next; 00823 widget->type_next->type_prev = widget->type_prev; 00824 } 00825 } 00826 00827 #ifdef DEBUG_WIDGET 00828 LOG(llevDebug, "..REMOVED: %s, WidgetObjID: %d\n", widget->name, widget->WidgetObjID); 00829 #endif 00830 00831 /* free the surface */ 00832 if (widget->widgetSF) 00833 { 00834 SDL_FreeSurface(widget->widgetSF); 00835 widget->widgetSF = NULL; 00836 } 00837 00838 free(widget); 00839 00840 #ifdef DEBUG_WIDGET 00841 debug_count_nodes(1); 00842 LOG(llevInfo, "..remove_widget(): Done.\n"); 00843 #endif 00844 } 00845 00847 void detach_widget(widgetdata *widget) 00848 { 00849 /* sanity check */ 00850 if (!widget->env) 00851 { 00852 return; 00853 } 00854 00855 /* first unlink the widget from the container and siblings */ 00856 00857 /* if widget is only one in the container's inventory, clear both pointers */ 00858 if (!widget->prev && !widget->next) 00859 { 00860 widget->env->inv = NULL; 00861 widget->env->inv_rev = NULL; 00862 } 00863 /* widget is first sibling */ 00864 else if (!widget->prev) 00865 { 00866 widget->env->inv = widget->next; 00867 widget->next->prev = NULL; 00868 } 00869 /* widget is last sibling */ 00870 else if (!widget->next) 00871 { 00872 widget->env->inv_rev = widget->prev; 00873 widget->prev->next = NULL; 00874 } 00875 /* widget is a middle sibling */ 00876 else 00877 { 00878 widget->prev->next = widget->next; 00879 widget->next->prev = widget->prev; 00880 } 00881 00882 /* if something else exists in the container's inventory, make it auto-resize to fit the widgets inside */ 00883 if (widget->env->inv) 00884 { 00885 resize_widget(widget->env->inv, RESIZE_RIGHT, widget->env->inv->wd); 00886 resize_widget(widget->env->inv, RESIZE_BOTTOM, widget->env->inv->ht); 00887 } 00888 /* otherwise if its inventory is empty, resize it to its default size */ 00889 else 00890 { 00891 resize_widget(widget->env, RESIZE_RIGHT, con_widget[widget->env->WidgetSubtypeID].wd); 00892 resize_widget(widget->env, RESIZE_BOTTOM, con_widget[widget->env->WidgetSubtypeID].ht); 00893 } 00894 00895 /* widget is no longer in a container */ 00896 widget->env = NULL; 00897 /* move the widget to the top of the priority tree */ 00898 widget->prev = NULL; 00899 widget_list_head->prev = widget; 00900 widget->next = widget_list_head; 00901 widget_list_head = widget; 00902 } 00903 00904 #ifdef DEBUG_WIDGET 00905 00906 int debug_count_nodes_rec(widgetdata *widget, int i, int j, int output) 00907 { 00908 int tmp = 0; 00909 00910 do 00911 { 00912 /* we print out the top node, and then go down a level, rather than go down first */ 00913 if (output) 00914 { 00915 /* a way of representing graphically how many levels down we are */ 00916 for (tmp = 0; tmp < j; ++ tmp) 00917 { 00918 printf(".."); 00919 } 00920 00921 LOG(llevInfo, "..%s, WidgetObjID: %d\n", widget->name, widget->WidgetObjID); 00922 } 00923 00924 i++; 00925 00926 /* we want to process the widgets starting from the left hand side of the tree first */ 00927 if (widget->inv) 00928 { 00929 i = debug_count_nodes_rec(widget->inv, i, j + 1, output); 00930 } 00931 00932 /* get the next sibling for our next loop */ 00933 widget = widget->next; 00934 } 00935 while (widget); 00936 00937 return i; 00938 } 00939 00940 void debug_count_nodes(int output) 00941 { 00942 int i = 0; 00943 00944 LOG(llevInfo, "Output of widget nodes:\n"); 00945 LOG(llevInfo, "========================================\n"); 00946 00947 if (widget_list_head) 00948 { 00949 i = debug_count_nodes_rec(widget_list_head, 0, 0, output); 00950 } 00951 00952 LOG(llevInfo, "========================================\n"); 00953 LOG(llevInfo, "..Total widget nodes: %d\n", i); 00954 } 00955 #endif 00956 00961 static int load_interface_file(char *filename) 00962 { 00963 int i = -1, pos; 00964 FILE *stream; 00965 widgetdata *widget = NULL; 00966 char line[256], keyword[256], parameter[256]; 00967 int found_widget[TOTAL_SUBWIDGETS] = {0}; 00968 00969 #ifdef DEBUG_WIDGET 00970 LOG(llevDebug, "Entering load_interface_file()..\n"); 00971 #endif 00972 00973 /* Sanity check - if the file doesn't exist, exit with error */ 00974 if (!(stream = fopen_wrapper(filename, "r"))) 00975 { 00976 /* Inform user */ 00977 LOG(llevInfo, "load_interface_file(): Can't find file %s.\n", filename); 00978 return 0; 00979 } 00980 00981 /* Read the settings from the file */ 00982 while (fgets(line, 255, stream)) 00983 { 00984 if (line[0] == '#' || line[0] == '\n') 00985 { 00986 continue; 00987 } 00988 00989 i = 0; 00990 00991 while (line[i] && line[i] != ':') 00992 { 00993 i++; 00994 } 00995 00996 line[++i] = '\0'; 00997 00998 strncpy(keyword, line, sizeof(keyword)); 00999 strncpy(parameter, line + i + 1, sizeof(parameter)); 01000 01001 /* Remove the newline character */ 01002 parameter[strcspn(line + i + 1, "\n")] = 0; 01003 01004 /* Beginning */ 01005 if (strncmp(keyword, "Widget:", 7) == 0) 01006 { 01007 #ifdef DEBUG_WIDGET 01008 LOG(llevDebug, "..Trying to find \"Widget: %s\"\n", parameter); 01009 #endif 01010 01011 pos = 0; 01012 01013 /* Find the index of the widget for reference */ 01014 while (pos < TOTAL_SUBWIDGETS && (strcmp(con_widget[pos].name, parameter) != 0)) 01015 { 01016 ++pos; 01017 } 01018 01019 /* The widget name couldn't be found? */ 01020 if (pos >= TOTAL_SUBWIDGETS) 01021 { 01022 continue; 01023 } 01024 /* Get the block */ 01025 else 01026 { 01027 if (!con_widget[pos].no_kill) 01028 { 01029 continue; 01030 } 01031 01032 /* If we haven't found this widget, mark it */ 01033 if (!found_widget[pos]) 01034 { 01035 #ifdef DEBUG_WIDGET 01036 LOG(llevInfo, "Found! (Index = %d) (%d widgets total)\n", pos, TOTAL_SUBWIDGETS); 01037 #endif 01038 found_widget[pos] = 1; 01039 } 01040 01041 /* create the widget with that ID, it is already fully initialized to the defaults */ 01042 widget = create_widget_object(pos); 01043 01044 /* in case something went wrong */ 01045 if (!widget) 01046 { 01047 #ifdef DEBUG_WIDGET 01048 LOG(llevDebug, ".. Failed to create widget!\n"); 01049 #endif 01050 continue; 01051 } 01052 01053 while (fgets(line, 255, stream)) 01054 { 01055 if (line[0] == '#' || line[0] == '\n') 01056 { 01057 continue; 01058 } 01059 01060 /* End marker */ 01061 if (!strncmp(line, "end", 3)) 01062 { 01063 break; 01064 } 01065 01066 i = 0; 01067 01068 while (line[i] && line[i] != ':') 01069 { 01070 i++; 01071 } 01072 01073 line[++i] = '\0'; 01074 strcpy(keyword, line); 01075 strcpy(parameter, line + i + 1); 01076 01077 if (strncmp(keyword, "x:", 2) == 0) 01078 { 01079 widget->x1 = atoi(parameter); 01080 #ifdef DEBUG_WIDGET 01081 LOG(llevDebug, "..Loading: (%s %d)\n", keyword, widget->x1); 01082 #endif 01083 } 01084 else if (strncmp(keyword, "y:", 2) == 0) 01085 { 01086 widget->y1 = atoi(parameter); 01087 #ifdef DEBUG_WIDGET 01088 LOG(llevDebug, "..Loading: (%s %d)\n", keyword, widget->y1); 01089 #endif 01090 } 01091 else if (strncmp(keyword, "moveable:", 9) == 0) 01092 { 01093 widget->moveable = atoi(parameter); 01094 #ifdef DEBUG_WIDGET 01095 LOG(llevDebug, "..Loading: (%s %d)\n", keyword, widget->moveable); 01096 #endif 01097 } 01098 else if (strncmp(keyword, "active:", 7) == 0) 01099 { 01100 widget->show = atoi(parameter); 01101 #ifdef DEBUG_WIDGET 01102 LOG(llevDebug, "..Loading: (%s %d)\n", keyword, widget->show); 01103 #endif 01104 } 01105 else if (strncmp(keyword, "width:", 6) == 0) 01106 { 01107 widget->wd = atoi(parameter); 01108 #ifdef DEBUG_WIDGET 01109 LOG(llevDebug, "..Loading: (%s %d)\n", keyword, widget->wd); 01110 #endif 01111 } 01112 else if (strncmp(keyword, "height:", 7) == 0) 01113 { 01114 widget->ht = atoi(parameter); 01115 #ifdef DEBUG_WIDGET 01116 LOG(llevDebug, "..Loading: (%s %d)\n", keyword, widget->ht); 01117 #endif 01118 } 01119 else if (!strncmp(keyword, "font:", 5)) 01120 { 01121 textwin_struct *textwin = TEXTWIN(widget); 01122 char font_name[MAX_BUF]; 01123 int font_size, font_id; 01124 01125 if (textwin && sscanf(parameter, "%s %d", font_name, &font_size) == 2 && (font_id = get_font_id(font_name, font_size)) != -1) 01126 { 01127 textwin->font = font_id; 01128 } 01129 } 01130 } 01131 } 01132 } 01133 } 01134 01135 fclose(stream); 01136 01137 /* Go through the widgets */ 01138 for (pos = 0; pos < TOTAL_SUBWIDGETS; ++pos) 01139 { 01140 /* If a required widget was not found, load the default data for it. */ 01141 if (!found_widget[pos] && con_widget[pos].no_kill) 01142 { 01143 /* A newly created widget is loaded with the default values. */ 01144 create_widget_object(pos); 01145 LOG(llevDebug, "load_interface_file(): Critical widget is missing! Recreating with default values.\n"); 01146 } 01147 } 01148 01149 #ifdef DEBUG_WIDGET 01150 LOG(llevDebug, "..load_interface_file(): Done.\n"); 01151 #endif 01152 01153 return 1; 01154 } 01155 01158 void save_interface_file() 01159 { 01160 FILE *stream; 01161 01162 /* Leave, if there's an error opening or creating */ 01163 if (!(stream = fopen_wrapper(INTERFACE_FILE, "w"))) 01164 { 01165 return; 01166 } 01167 01168 fputs("#############################################\n", stream); 01169 fputs("# This is the Atrinik client interface file #\n", stream); 01170 fputs("#############################################\n", stream); 01171 01172 /* start walking through the widgets */ 01173 save_interface_file_rec(widget_list_foot, stream); 01174 01175 fclose(stream); 01176 } 01177 01181 void save_interface_file_rec(widgetdata *widget, FILE *stream) 01182 { 01183 do 01184 { 01185 /* skip the widget if it shouldn't be saved */ 01186 if (!widget->save) 01187 { 01188 widget = widget->prev; 01189 continue; 01190 } 01191 01192 /* we want to process the widgets starting from the left hand side of the tree first */ 01193 if (widget->inv_rev) 01194 { 01195 save_interface_file_rec(widget->inv_rev, stream); 01196 } 01197 01198 fprintf(stream, "\nWidget: %s\n", widget->name); 01199 fprintf(stream, "moveable: %d\n", widget->moveable); 01200 fprintf(stream, "active: %d\n", widget->show); 01201 fprintf(stream, "x: %d\n", widget->x1); 01202 fprintf(stream, "y: %d\n", widget->y1); 01203 01204 if (widget->save_width_height) 01205 { 01206 fprintf(stream, "width: %d\n", widget->wd); 01207 fprintf(stream, "height: %d\n", widget->ht); 01208 } 01209 01210 switch (widget->WidgetTypeID) 01211 { 01212 case CHATWIN_ID: 01213 case MSGWIN_ID: 01214 { 01215 textwin_struct *textwin = TEXTWIN(widget); 01216 01217 fprintf(stream, "font: %s %"FMT64U"\n", get_font_filename(textwin->font), (uint64) fonts[textwin->font].size); 01218 break; 01219 } 01220 } 01221 01222 /* End of block */ 01223 fputs("end\n", stream); 01224 01225 /* get the next sibling for our next loop */ 01226 widget = widget->prev; 01227 } 01228 while (widget); 01229 } 01230 01238 int widget_event_mousedn(int x, int y, SDL_Event *event) 01239 { 01240 widgetdata *widget; 01241 01242 /* update the widget event struct if the mouse is in a widget, or else get out of here for sanity reasons */ 01243 if (!widget_event_respond(x, y)) 01244 { 01245 return 0; 01246 } 01247 01248 widget = widget_mouse_event.owner; 01249 01250 /* sanity check */ 01251 if (!widget) 01252 { 01253 return 0; 01254 } 01255 01256 /* Set the priority to this widget */ 01257 SetPriorityWidget(widget); 01258 01259 if (widget_event_move.active) 01260 { 01261 widgetdata *widget_container; 01262 01263 widget = widget_mouse_event.owner; 01264 01265 widget_event_move.active = 0; 01266 widget_mouse_event.x = x; 01267 widget_mouse_event.y = y; 01268 /* no widgets are being moved now */ 01269 widget_event_move.owner = NULL; 01270 01271 /* Disable the custom cursor */ 01272 f_custom_cursor = 0; 01273 01274 /* Show the system cursor */ 01275 SDL_ShowCursor(1); 01276 01277 /* Due to a bug in SDL 1.2.x, the mouse X/Y position is not updated 01278 * while in fullscreen with the cursor hidden, so we must take care 01279 * of it ourselves. Apparently SDL 1.3 should fix it. 01280 * See http://old.nabble.com/Mouse-movement-problems-in-fullscreen-mode-td20890669.html 01281 * for details. */ 01282 SDL_WarpMouse(x, y); 01283 01284 /* Somehow the owner before the widget dragging is gone now. Not a good idea to carry on... */ 01285 if (!widget) 01286 { 01287 return 0; 01288 } 01289 01290 /* check to see if it's on top of a widget container */ 01291 widget_container = get_widget_owner(x, y, widget->next, NULL); 01292 01293 /* attempt to insert it into the widget container if it exists */ 01294 insert_widget_in_container(widget_container, widget); 01295 return 1; 01296 } 01297 01298 /* Right mouse button was clicked */ 01299 if (event->button.button == SDL_BUTTON_RIGHT && widget->WidgetTypeID != MAP_ID) 01300 { 01301 widgetdata *menu; 01302 01303 /* Create a context menu for the widget clicked on. */ 01304 menu = create_menu(x, y, widget); 01305 /* This bit probably shouldn't be hard coded in future. */ 01306 add_menuitem(menu, "Move Widget", &menu_move_widget, MENU_NORMAL, 0); 01307 01308 if (widget->WidgetSubtypeID == MAIN_INV_ID) 01309 { 01310 add_menuitem(menu, "Inventory Filters >", &menu_detach_widget, MENU_SUBMENU, 0); 01311 } 01312 else if (widget->WidgetSubtypeID == MSGWIN_ID || widget->WidgetSubtypeID == CHATWIN_ID) 01313 { 01314 add_menuitem(menu, "Clear", &menu_textwin_clear, MENU_NORMAL, 0); 01315 add_menuitem(menu, "Increase Font Size", &menu_textwin_font_inc, MENU_NORMAL, 0); 01316 add_menuitem(menu, "Decrease Font Size", &menu_textwin_font_dec, MENU_NORMAL, 0); 01317 } 01318 01319 menu_finalize(menu); 01320 01321 return 1; 01322 } 01323 /* Start resizing. */ 01324 else if (widget->resizeable && widget->resize_flags && event->button.button == SDL_BUTTON_LEFT) 01325 { 01326 widget_event_resize.active = 1; 01327 widget_event_resize.owner = widget; 01328 } 01329 /* Normal condition - respond to mouse down event */ 01330 else 01331 { 01332 /* Handler(s) for miscellaneous mouse movement(s) go here. */ 01333 01334 /* Special case for menuitems, if menuitem or a widget inside is clicked on, calls the function tied to the menuitem. */ 01335 widget_menu_event(widget, x, y); 01336 01337 /* Place here all the mousedown handlers. */ 01338 switch (widget->WidgetTypeID) 01339 { 01340 case MENU_B_ID: 01341 widget_menubuttons_event(widget, event); 01342 break; 01343 01344 case QUICKSLOT_ID: 01345 widget_quickslots_mouse_event(widget, event); 01346 break; 01347 01348 case CHATWIN_ID: 01349 case MSGWIN_ID: 01350 textwin_event(widget, event); 01351 break; 01352 01353 case RANGE_ID: 01354 widget_range_event(widget, x, y, *event, MOUSE_DOWN); 01355 break; 01356 01357 case BELOW_INV_ID: 01358 widget_below_window_event(widget, x, y, MOUSE_DOWN); 01359 break; 01360 01361 case TARGET_ID: 01362 widget_event_target(widget, x, y); 01363 break; 01364 01365 case MAIN_INV_ID: 01366 widget_inventory_event(widget, x, y, *event); 01367 break; 01368 01369 case PLAYER_INFO_ID: 01370 widget_player_data_event(widget, x, y); 01371 break; 01372 01373 case IN_NUMBER_ID: 01374 widget_number_event(widget, x, y); 01375 break; 01376 01377 case MPLAYER_ID: 01378 widget_mplayer_mevent(widget, event); 01379 break; 01380 01381 case SPELLS_ID: 01382 widget_spells_mevent(widget, event); 01383 break; 01384 01385 case MAP_ID: 01386 widget_map_mevent(widget, event); 01387 break; 01388 01389 case SKILLS_ID: 01390 widget_skills_mevent(widget, event); 01391 break; 01392 01393 case PARTY_ID: 01394 widget_party_mevent(widget, event); 01395 break; 01396 } 01397 } 01398 01399 /* User didn't click on a menu, so remove any menus that exist. */ 01400 if (widget->WidgetSubtypeID != MENU_ID) 01401 { 01402 widgetdata *menu, *tmp; 01403 01404 for (menu = cur_widget[MENU_ID]; menu; menu = tmp) 01405 { 01406 tmp = menu->type_next; 01407 remove_widget_object(menu); 01408 } 01409 } 01410 01411 return 1; 01412 } 01413 01421 int widget_event_mouseup(int x, int y, SDL_Event *event) 01422 { 01423 widgetdata *widget; 01424 01425 /* Widget is now being moved, don't do anything. */ 01426 if (widget_event_move.active) 01427 { 01428 return 1; 01429 } 01430 /* End resizing. */ 01431 else if (widget_event_resize.active) 01432 { 01433 widget_event_resize.active = 0; 01434 widget_event_resize.owner = NULL; 01435 return 1; 01436 } 01437 /* Normal condition - respond to mouse up event */ 01438 else 01439 { 01440 /* update the widget event struct if the mouse is in a widget, or else get out of here for sanity reasons */ 01441 if (!widget_event_respond(x, y)) 01442 { 01443 return 0; 01444 } 01445 01446 widget = widget_mouse_event.owner; 01447 01448 /* sanity check */ 01449 if (!widget) 01450 { 01451 return 0; 01452 } 01453 01454 /* Handler for the widgets go here */ 01455 switch (widget->WidgetTypeID) 01456 { 01457 case QUICKSLOT_ID: 01458 widget_quickslots_mouse_event(widget, event); 01459 break; 01460 01461 case CHATWIN_ID: 01462 case MSGWIN_ID: 01463 textwin_event(widget, event); 01464 break; 01465 01466 case PDOLL_ID: 01467 widget_show_player_doll_event(); 01468 break; 01469 01470 case RANGE_ID: 01471 widget_range_event(widget, x, y, *event, MOUSE_UP); 01472 break; 01473 01474 case MAIN_INV_ID: 01475 widget_inventory_event(widget, x, y, *event); 01476 break; 01477 01478 case MPLAYER_ID: 01479 widget_mplayer_mevent(widget, event); 01480 break; 01481 01482 case SPELLS_ID: 01483 widget_spells_mevent(widget, event); 01484 break; 01485 01486 case MENU_B_ID: 01487 widget_menubuttons_event(widget, event); 01488 break; 01489 01490 case MAP_ID: 01491 widget_map_mevent(widget, event); 01492 break; 01493 01494 case SKILLS_ID: 01495 widget_skills_mevent(widget, event); 01496 break; 01497 01498 case PARTY_ID: 01499 widget_party_mevent(widget, event); 01500 break; 01501 } 01502 01503 return 1; 01504 } 01505 } 01506 01514 int widget_event_mousemv(int x, int y, SDL_Event *event) 01515 { 01516 widgetdata *widget; 01517 01518 /* Widget moving condition */ 01519 if (widget_event_move.active) 01520 { 01521 int nx, ny; 01522 01523 widget = widget_event_move.owner; 01524 01525 /* The widget being moved doesn't exist. Sanity check in case something mad like this happens. */ 01526 if (!widget) 01527 { 01528 return 0; 01529 } 01530 01531 x -= widget_event_move.xOffset; 01532 y -= widget_event_move.yOffset; 01533 nx = x; 01534 ny = y; 01535 01536 /* Widget snapping logic courtesy of OpenTTD (GPLv2). */ 01537 if (setting_get_int(OPT_CAT_GENERAL, OPT_SNAP_RADIUS)) 01538 { 01539 widgetdata *tmp; 01540 int delta, hsnap, vsnap; 01541 01542 delta = 0; 01543 hsnap = vsnap = setting_get_int(OPT_CAT_GENERAL, OPT_SNAP_RADIUS); 01544 01545 for (tmp = widget_list_head; tmp; tmp = tmp->next) 01546 { 01547 if (tmp == widget || tmp->disable_snapping || !tmp->show || !tmp->visible) 01548 { 01549 continue; 01550 } 01551 01552 if (y + widget->ht > tmp->y1 && y < tmp->y1 + tmp->ht) 01553 { 01554 /* Your left border <-> other right border */ 01555 delta = abs(tmp->x1 + tmp->wd - x); 01556 01557 if (delta <= hsnap) 01558 { 01559 nx = tmp->x1 + tmp->wd; 01560 hsnap = delta; 01561 } 01562 01563 /* Your right border <-> other left border */ 01564 delta = abs(tmp->x1 - x - widget->wd); 01565 01566 if (delta <= hsnap) 01567 { 01568 nx = tmp->x1 - widget->wd; 01569 hsnap = delta; 01570 } 01571 } 01572 01573 if (widget->y1 + widget->ht >= tmp->y1 && widget->y1 <= tmp->y1 + tmp->ht) 01574 { 01575 /* Your left border <-> other left border */ 01576 delta = abs(tmp->x1 - x); 01577 01578 if (delta <= hsnap) 01579 { 01580 nx = tmp->x1; 01581 hsnap = delta; 01582 } 01583 01584 /* Your right border <-> other right border */ 01585 delta = abs(tmp->x1 + tmp->wd - x - widget->wd); 01586 01587 if (delta <= hsnap) 01588 { 01589 nx = tmp->x1 + tmp->wd - widget->wd; 01590 hsnap = delta; 01591 } 01592 } 01593 01594 if (x + widget->wd > tmp->x1 && x < tmp->x1 + tmp->wd) 01595 { 01596 /* Your top border <-> other bottom border */ 01597 delta = abs(tmp->y1 + tmp->ht - y); 01598 01599 if (delta <= vsnap) 01600 { 01601 ny = tmp->y1 + tmp->ht; 01602 vsnap = delta; 01603 } 01604 01605 /* Your bottom border <-> other top border */ 01606 delta = abs(tmp->y1 - y - widget->ht); 01607 01608 if (delta <= vsnap) 01609 { 01610 ny = tmp->y1 - widget->ht; 01611 vsnap = delta; 01612 } 01613 } 01614 01615 if (widget->x1 + widget->wd >= tmp->x1 && widget->x1 <= tmp->x1 + tmp->wd) 01616 { 01617 /* Your top border <-> other top border */ 01618 delta = abs(tmp->y1 - y); 01619 01620 if (delta <= vsnap) 01621 { 01622 ny = tmp->y1; 01623 vsnap = delta; 01624 } 01625 01626 /* Your bottom border <-> other bottom border */ 01627 delta = abs(tmp->y1 + tmp->ht - y - widget->ht); 01628 01629 if (delta <= vsnap) 01630 { 01631 ny = tmp->y1 + tmp->ht - widget->ht; 01632 vsnap = delta; 01633 } 01634 } 01635 } 01636 } 01637 01638 /* we move the widget here, as well as all the widgets inside it if they exist */ 01639 /* we use the recursive version since we already have the outermost container */ 01640 move_widget_rec(widget, nx - widget->x1, ny - widget->y1); 01641 01642 /* Ensure widget is on-screen. */ 01643 if (!setting_get_int(OPT_CAT_CLIENT, OPT_OFFSCREEN_WIDGETS)) 01644 { 01645 widget_ensure_onscreen(widget); 01646 } 01647 01648 map_udate_flag = 2; 01649 01650 return 1; 01651 } 01652 else if (widget_event_resize.active) 01653 { 01654 widget = widget_event_resize.owner; 01655 01656 if (!widget) 01657 { 01658 return 0; 01659 } 01660 01661 if (widget->resize_flags & (RESIZE_LEFT | RESIZE_RIGHT)) 01662 { 01663 resize_widget(widget, widget->resize_flags & ~(RESIZE_TOP | RESIZE_BOTTOM), MAX(widget->min_w, widget->resize_flags & RESIZE_LEFT ? widget->x1 - x + widget->wd : x - widget->x1)); 01664 } 01665 01666 if (widget->resize_flags & (RESIZE_TOP | RESIZE_BOTTOM)) 01667 { 01668 resize_widget(widget, widget->resize_flags & ~(RESIZE_LEFT | RESIZE_RIGHT), MAX(widget->min_h, widget->resize_flags & RESIZE_TOP ? widget->y1 - y + widget->ht : y - widget->y1)); 01669 } 01670 01671 switch (widget->WidgetTypeID) 01672 { 01673 case MSGWIN_ID: 01674 case CHATWIN_ID: 01675 textwin_readjust(widget); 01676 break; 01677 } 01678 01679 return 1; 01680 } 01681 /* Normal condition - respond to mouse move event */ 01682 else 01683 { 01684 textwin_struct *textwin = NULL; 01685 01686 /* update the widget event struct if the mouse is in a widget, or else get out of here for sanity reasons */ 01687 if (!widget_event_respond(x, y)) 01688 { 01689 return 0; 01690 } 01691 01692 widget = widget_mouse_event.owner; 01693 01694 /* sanity check */ 01695 if (!widget) 01696 { 01697 return 0; 01698 } 01699 01700 if (widget->resizeable) 01701 { 01702 widget->resizeable = 1; 01703 widget->resize_flags = 0; 01704 01705 if (y >= widget->y1 && y <= widget->y1 + 2) 01706 { 01707 widget->resize_flags |= RESIZE_TOP; 01708 } 01709 else if (y >= widget->y1 + widget->ht - 2 && y <= widget->y1 + widget->ht) 01710 { 01711 widget->resize_flags |= RESIZE_BOTTOM; 01712 } 01713 01714 if (x >= widget->x1 && x <= widget->x1 + 2) 01715 { 01716 widget->resize_flags |= RESIZE_LEFT; 01717 } 01718 else if (x >= widget->x1 + widget->wd - 2 && x <= widget->x1 + widget->wd) 01719 { 01720 widget->resize_flags |= RESIZE_RIGHT; 01721 } 01722 } 01723 01724 /* Handlers for miscellaneous mouse movements go here */ 01725 01726 /* Handlers for the widgets mouse move */ 01727 switch (widget->WidgetTypeID) 01728 { 01729 case CHATWIN_ID: 01730 case MSGWIN_ID: 01731 textwin = TEXTWIN(widget); 01732 01733 /* textwin special handling */ 01734 if (textwin) 01735 { 01736 if (textwin->highlight != TW_HL_NONE) 01737 { 01738 textwin->highlight = TW_HL_NONE; 01739 WIDGET_REDRAW(widget); 01740 } 01741 } 01742 01743 textwin_event(widget, event); 01744 break; 01745 01746 case MAIN_INV_ID: 01747 widget_inventory_event(widget, x, y, *event); 01748 break; 01749 01750 case MPLAYER_ID: 01751 widget_mplayer_mevent(widget, event); 01752 break; 01753 01754 case SPELLS_ID: 01755 widget_spells_mevent(widget, event); 01756 break; 01757 01758 case MENU_B_ID: 01759 widget_menubuttons_event(widget, event); 01760 break; 01761 01762 case MAP_ID: 01763 widget_map_mevent(widget, event); 01764 break; 01765 01766 case SKILLS_ID: 01767 widget_skills_mevent(widget, event); 01768 break; 01769 01770 case PARTY_ID: 01771 widget_party_mevent(widget, event); 01772 break; 01773 } 01774 01775 return 1; 01776 } 01777 } 01778 01780 int widget_event_start_move(widgetdata *widget, int x, int y) 01781 { 01782 /* get the outermost container so we can move the container with everything in it */ 01783 widget = get_outermost_container(widget); 01784 01785 /* if its moveable, start moving it when the conditions warrant it, or else run away */ 01786 if (!widget->moveable) 01787 { 01788 return 0; 01789 } 01790 01791 /* we know this widget owns the mouse.. */ 01792 widget_event_move.active = 1; 01793 01794 /* start the movement procedures */ 01795 widget_event_move.owner = widget; 01796 widget_event_move.xOffset = x - widget->x1; 01797 widget_event_move.yOffset = y - widget->y1; 01798 01799 /* enable the custom cursor */ 01800 f_custom_cursor = MSCURSOR_MOVE; 01801 /* hide the system cursor */ 01802 SDL_ShowCursor(0); 01803 01804 #ifdef WIN32 01805 /* Workaround another bug with SDL 1.2.x on Windows. Make sure the cursor 01806 * is in the center of the screen if we are in fullscreen mode. */ 01807 if (ScreenSurface->flags & SDL_FULLSCREEN) 01808 { 01809 SDL_WarpMouse(ScreenSurface->w / 2, ScreenSurface->h / 2); 01810 } 01811 #endif 01812 01813 return 1; 01814 } 01815 01817 int widget_event_respond(int x, int y) 01818 { 01819 /* only update the owner if there is no event override taking place */ 01820 if (!widget_event_override()) 01821 { 01822 widget_mouse_event.owner = get_widget_owner(x, y, NULL, NULL); 01823 } 01824 01825 /* sanity check.. return if mouse is not in a widget */ 01826 if (!widget_mouse_event.owner) 01827 { 01828 return 0; 01829 } 01830 01831 /* setup the event structure in response */ 01832 widget_mouse_event.x = x; 01833 widget_mouse_event.y = y; 01834 01835 return 1; 01836 } 01837 01839 int widget_event_override() 01840 { 01841 return 0; 01842 } 01843 01845 widgetdata *get_widget_owner(int x, int y, widgetdata *start, widgetdata *end) 01846 { 01847 widgetdata *success; 01848 01849 /* mouse cannot be used by widgets */ 01850 if (IsMouseExclusive) 01851 { 01852 return NULL; 01853 } 01854 01855 /* no widgets exist */ 01856 if (!widget_list_head) 01857 { 01858 return NULL; 01859 } 01860 01861 /* sometimes we want a fast way to get the widget behind the widget at the front. 01862 * this is what start is for, and we will only start walking the list beginning with start. 01863 * if start is NULL, we just do a regular search */ 01864 if (!start) 01865 { 01866 start = widget_list_head; 01867 } 01868 01869 /* ok, let's kick off the recursion. if we find our widget, we get a widget back. if not, we get a big fat NULL */ 01870 success = get_widget_owner_rec(x, y, start, end); 01871 01872 /*LOG(llevDebug, "WIDGET OWNER: %s, WidgetObjID: %d\n", success? success->name: "NULL", success? success->WidgetObjID: -1);*/ 01873 01874 return success; 01875 } 01876 01877 /* traverse through the tree & perform custom or default hit-test */ 01878 widgetdata *get_widget_owner_rec(int x, int y, widgetdata *widget, widgetdata *end) 01879 { 01880 widgetdata *success = NULL; 01881 01882 do 01883 { 01884 /* we want to get the first widget starting from the left hand side of the tree first */ 01885 if (widget->inv) 01886 { 01887 success = get_widget_owner_rec(x, y, widget->inv, end); 01888 01889 /* we found a widget in the hit test? if so, get out of this recursive mess with our prize */ 01890 if (success) 01891 { 01892 return success; 01893 } 01894 } 01895 01896 /* skip if widget is hidden */ 01897 if (!widget->show) 01898 { 01899 widget = widget->next; 01900 continue; 01901 } 01902 01903 switch (widget->WidgetTypeID) 01904 { 01905 default: 01906 if (x >= widget->x1 && x <= (widget->x1 + widget->wd) && y >= widget->y1 && y <= (widget->y1 + widget->ht)) 01907 { 01908 return widget; 01909 } 01910 } 01911 01912 /* get the next sibling for our next loop */ 01913 widget = widget->next; 01914 } 01915 while (widget || widget != end); 01916 01917 return NULL; 01918 } 01919 01923 static void process_widget(widgetdata *widget) 01924 { 01925 switch (widget->WidgetTypeID) 01926 { 01927 case STATS_ID: 01928 widget_player_stats(widget); 01929 break; 01930 01931 case RESIST_ID: 01932 widget_show_resist(widget); 01933 break; 01934 01935 case MAIN_LVL_ID: 01936 widget_show_main_lvl(widget); 01937 break; 01938 01939 case SKILL_EXP_ID: 01940 widget_show_skill_exp(widget); 01941 break; 01942 01943 case REGEN_ID: 01944 widget_show_regeneration(widget); 01945 break; 01946 01947 case SKILL_LVL_ID: 01948 widget_skillgroups(widget); 01949 break; 01950 01951 case MENU_B_ID: 01952 widget_menubuttons(widget); 01953 break; 01954 01955 case QUICKSLOT_ID: 01956 widget_quickslots(widget); 01957 break; 01958 01959 case CHATWIN_ID: 01960 case MSGWIN_ID: 01961 widget_textwin_show(widget); 01962 break; 01963 01964 case PDOLL_ID: 01965 widget_show_player_doll(widget); 01966 break; 01967 01968 case BELOW_INV_ID: 01969 widget_show_below_window(widget); 01970 break; 01971 01972 case PLAYER_INFO_ID: 01973 widget_show_player_data(widget); 01974 break; 01975 01976 case RANGE_ID: 01977 widget_show_range(widget); 01978 break; 01979 01980 case TARGET_ID: 01981 widget_show_target(widget); 01982 break; 01983 01984 case MAIN_INV_ID: 01985 widget_show_inventory_window(widget); 01986 break; 01987 01988 case MAPNAME_ID: 01989 widget_show_mapname(widget); 01990 break; 01991 01992 case IN_CONSOLE_ID: 01993 widget_show_console(widget); 01994 break; 01995 01996 case IN_NUMBER_ID: 01997 widget_show_number(widget); 01998 break; 01999 02000 case FPS_ID: 02001 widget_show_fps(widget); 02002 break; 02003 02004 case CONTAINER_ID: 02005 widget_show_container(widget); 02006 break; 02007 02008 case LABEL_ID: 02009 widget_show_label(widget); 02010 break; 02011 02012 case BITMAP_ID: 02013 widget_show_bitmap(widget); 02014 break; 02015 02016 case MPLAYER_ID: 02017 widget_show_mplayer(widget); 02018 break; 02019 02020 case SPELLS_ID: 02021 widget_spells_render(widget); 02022 break; 02023 02024 case SKILLS_ID: 02025 widget_skills_render(widget); 02026 break; 02027 02028 case PARTY_ID: 02029 widget_party_render(widget); 02030 break; 02031 } 02032 } 02033 02038 static void process_widget_background(widgetdata *widget) 02039 { 02040 switch (widget->WidgetTypeID) 02041 { 02042 case MPLAYER_ID: 02043 widget_mplayer_background(widget); 02044 break; 02045 02046 case PARTY_ID: 02047 widget_party_background(widget); 02048 break; 02049 } 02050 } 02051 02055 void process_widgets() 02056 { 02057 /* sanity check */ 02058 if (!widget_list_foot) 02059 { 02060 return; 02061 } 02062 02063 process_widgets_rec(widget_list_foot); 02064 } 02065 02070 void process_widgets_rec(widgetdata *widget) 02071 { 02072 popup_struct *popup; 02073 02074 popup = popup_get_visible(); 02075 02076 do 02077 { 02078 /* if widget isn't hidden, process it. this is mostly to do with rendering them */ 02079 if (widget->show && widget->visible && (!popup || popup_overlay_need_update(popup))) 02080 { 02081 process_widget(widget); 02082 } 02083 02084 process_widget_background(widget); 02085 02086 /* we want to process the widgets starting from the right hand side of the tree first */ 02087 if (widget->inv_rev) 02088 { 02089 process_widgets_rec(widget->inv_rev); 02090 } 02091 02092 /* get the previous sibling for our next loop */ 02093 widget = widget->prev; 02094 } 02095 while (widget); 02096 } 02097 02103 void SetPriorityWidget(widgetdata *node) 02104 { 02105 #ifdef DEBUG_WIDGET 02106 LOG(llevDebug, "Entering SetPriorityWidget(WidgetObjID=%d)..\n", node->WidgetObjID); 02107 #endif 02108 02109 /* widget doesn't exist, means parent node has no children, so nothing to do here */ 02110 if (!node) 02111 { 02112 #ifdef DEBUG_WIDGET 02113 LOG(llevDebug, "..SetPriorityWidget(): Done (Node does not exist).\n"); 02114 #endif 02115 return; 02116 } 02117 02118 if (node->WidgetTypeID == MAP_ID) 02119 { 02120 return; 02121 } 02122 02123 #ifdef DEBUG_WIDGET 02124 LOG(llevDebug, "..BEFORE:\n"); 02125 LOG(llevDebug, "....node: %p - %s\n", node, node->name); 02126 LOG(llevDebug, "....node->env: %p - %s\n", node->env, node->env? node->env->name: "NULL"); 02127 LOG(llevDebug, "....node->prev: %p - %s, node->next: %p - %s\n", node->prev, node->prev? node->prev->name: "NULL", node->next, node->next? node->next->name: "NULL"); 02128 LOG(llevDebug, "....node->inv: %p - %s, node->inv_rev: %p - %s\n", node->inv, node->inv? node->inv->name: "NULL", node->inv_rev, node->inv_rev? node->inv_rev->name: "NULL"); 02129 #endif 02130 02131 /* see if the node has a parent before continuing */ 02132 if (node->env) 02133 { 02134 SetPriorityWidget(node->env); 02135 02136 /* Strip containers are sorted in a fixed order, and no part of any widget inside should be covered by a sibling. 02137 * This means we don't need to bother moving the node to the front inside the container. */ 02138 switch (node->env->WidgetSubtypeID) 02139 { 02140 case CONTAINER_STRIP_ID: 02141 case MENU_ID: 02142 case MENUITEM_ID: 02143 return; 02144 } 02145 } 02146 02147 /* now we need to move our other node in front of the first sibling */ 02148 if (!node->prev) 02149 { 02150 #ifdef DEBUG_WIDGET 02151 LOG(llevDebug, "..SetPriorityWidget(): Done (Node already at front).\n"); 02152 #endif 02153 /* no point continuing, node is already at the front */ 02154 return; 02155 } 02156 02157 /* Unlink node from its current position in the priority tree. */ 02158 02159 /* node is last sibling, clear the pointer of the previous sibling */ 02160 if (!node->next) 02161 { 02162 /* node also has a parent pointing to it, hand the inv_rev pointer to the previous sibling */ 02163 if (node->env) 02164 { 02165 node->env->inv_rev = node->prev; 02166 } 02167 /* no parent, this must be the foot then, so move it to the previous node */ 02168 else 02169 { 02170 widget_list_foot = node->prev; 02171 } 02172 02173 node->prev->next = NULL; 02174 } 02175 else 02176 { 02177 /* link up the adjacent nodes */ 02178 node->prev->next = node->next; 02179 node->next->prev = node->prev; 02180 } 02181 02182 /* Insert node at the head of its container, or make it the root node if it is not in a container. */ 02183 02184 /* Node is now the first sibling so the parent should point to it. */ 02185 if (node->env) 02186 { 02187 node->next = node->env->inv; 02188 node->env->inv = node; 02189 } 02190 /* We are out of containers and this node is about to become the first sibling, which means it's taking the place of the root node. */ 02191 else 02192 { 02193 node->next = widget_list_head; 02194 widget_list_head = node; 02195 } 02196 02197 /* Point the former head node to this node. */ 02198 node->next->prev = node; 02199 /* There's no siblings in front of node now. */ 02200 node->prev = NULL; 02201 02202 #ifdef DEBUG_WIDGET 02203 LOG(llevDebug, "..AFTER:\n"); 02204 LOG(llevDebug, "....node: %p - %s\n", node, node->name); 02205 LOG(llevDebug, "....node->env: %p - %s\n", node->env, node->env? node->env->name: "NULL"); 02206 LOG(llevDebug, "....node->prev: %p - %s, node->next: %p - %s\n", node->prev, node->prev? node->prev->name: "NULL", node->next, node->next? node->next->name: "NULL"); 02207 LOG(llevDebug, "....node->inv: %p - %s, node->inv_rev: %p - %s\n", node->inv, node->inv? node->inv->name: "NULL", node->inv_rev, node->inv_rev? node->inv_rev->name: "NULL"); 02208 02209 LOG(llevDebug, "..SetPriorityWidget(): Done.\n"); 02210 #endif 02211 } 02212 02216 void SetPriorityWidget_reverse(widgetdata *node) 02217 { 02218 if (!node) 02219 { 02220 return; 02221 } 02222 02223 if (!node->next) 02224 { 02225 return; 02226 } 02227 02228 if (!node->prev) 02229 { 02230 if (node->env) 02231 { 02232 node->env->inv_rev = node->next; 02233 } 02234 else 02235 { 02236 widget_list_head = node->next; 02237 } 02238 02239 node->next->prev = NULL; 02240 } 02241 else 02242 { 02243 node->next->prev = node->prev; 02244 node->prev->next = node->next; 02245 } 02246 02247 if (node->env) 02248 { 02249 node->prev = node->env->inv; 02250 node->env->inv = node; 02251 } 02252 else 02253 { 02254 node->prev = widget_list_foot; 02255 widget_list_foot = node; 02256 } 02257 02258 node->prev->next = node; 02259 node->next = NULL; 02260 } 02261 02262 void insert_widget_in_container(widgetdata *widget_container, widgetdata *widget) 02263 { 02264 _widget_container *container; 02265 _widget_container_strip *container_strip; 02266 02267 /* sanity checks */ 02268 if (!widget_container || !widget) 02269 { 02270 return; 02271 } 02272 02273 /* no, we don't want to end the universe just yet... */ 02274 if (widget_container == widget) 02275 { 02276 return; 02277 } 02278 02279 /* is the widget already in a container? */ 02280 if (widget->env) 02281 { 02282 return; 02283 } 02284 02285 /* if the widget isn't a container, get out of here */ 02286 if (widget_container->WidgetTypeID != CONTAINER_ID) 02287 { 02288 return; 02289 } 02290 02291 /* we have our container, now we attempt to place the widget inside it */ 02292 container = CONTAINER(widget_container); 02293 02294 /* check to see if the widget is compatible with it */ 02295 if (container->widget_type != -1 && container->widget_type != widget->WidgetTypeID) 02296 { 02297 return; 02298 } 02299 02300 /* if we get here, we now proceed to insert the widget into the container */ 02301 02302 /* snap the widget into the widget container if it is a strip container */ 02303 if (widget_container->inv) 02304 { 02305 switch (widget_container->WidgetSubtypeID) 02306 { 02307 case CONTAINER_STRIP_ID: 02308 case MENU_ID: 02309 case MENUITEM_ID: 02310 container_strip = CONTAINER_STRIP(widget_container); 02311 02312 /* container is horizontal, insert the widget to the right of the first widget in its inventory */ 02313 if (container_strip->horizontal) 02314 { 02315 move_widget_rec(widget, widget_container->inv->x1 + widget_container->inv->wd + container_strip->inner_padding - widget->x1, widget_container->y1 + container->outer_padding_top - widget->y1); 02316 } 02317 /* otherwise the container is vertical, so insert the widget below the first child widget */ 02318 else 02319 { 02320 move_widget_rec(widget, widget_container->x1 + container->outer_padding_left - widget->x1, widget_container->inv->y1 + widget_container->inv->ht + container_strip->inner_padding - widget->y1); 02321 } 02322 02323 break; 02324 } 02325 } 02326 /* no widgets inside it yet, so snap it to the bounds of the container */ 02327 else 02328 { 02329 move_widget(widget, widget_container->x1 + container->outer_padding_left - widget->x1, widget_container->y1 + container->outer_padding_top - widget->y1); 02330 } 02331 02332 /* link up the adjacent nodes, there *should* be at least two nodes next to each other here so no sanity checks should be required */ 02333 if (!widget->prev) 02334 { 02335 /* widget is no longer the root now, pass it on to the next widget */ 02336 if (widget == widget_list_head) 02337 { 02338 widget_list_head = widget->next; 02339 } 02340 02341 widget->next->prev = NULL; 02342 } 02343 else if (!widget->next) 02344 { 02345 /* widget is no longer the foot, move it to the previous widget */ 02346 if (widget == widget_list_foot) 02347 { 02348 widget_list_foot = widget->prev; 02349 } 02350 02351 widget->prev->next = NULL; 02352 } 02353 else 02354 { 02355 widget->prev->next = widget->next; 02356 widget->next->prev = widget->prev; 02357 } 02358 02359 /* the widget to be placed inside will have a new sibling next to it, or NULL if it doesn't exist */ 02360 widget->next = widget_container->inv; 02361 /* it's also going to be the first child node, so it has no siblings on the other side */ 02362 widget->prev = NULL; 02363 02364 /* if inventory doesn't exist, set the end child pointer too */ 02365 if (!widget_container->inv) 02366 { 02367 widget_container->inv_rev = widget; 02368 } 02369 /* otherwise, link the first child in the inventory to the widget about to be inserted */ 02370 else 02371 { 02372 widget_container->inv->prev = widget; 02373 } 02374 02375 /* this new widget becomes the first widget in the container */ 02376 widget_container->inv = widget; 02377 /* set the environment of the widget inside */ 02378 widget->env = widget_container; 02379 02380 /* resize the container to fit the new widget. a little dirty trick here, 02381 * we just resize the widget inside by nothing and it will trigger the auto-resize */ 02382 resize_widget(widget, RESIZE_RIGHT, widget->wd); 02383 resize_widget(widget, RESIZE_BOTTOM, widget->ht); 02384 } 02385 02387 widgetdata *get_outermost_container(widgetdata *widget) 02388 { 02389 widgetdata *tmp = widget; 02390 02391 /* Sanity check. */ 02392 if (!widget) 02393 { 02394 return NULL; 02395 } 02396 02397 /* Get the outsidemost container if the widget is inside one. */ 02398 while (tmp->env) 02399 { 02400 tmp = tmp->env; 02401 widget = tmp; 02402 } 02403 02404 return widget; 02405 } 02406 02412 widgetdata *widget_find_by_surface(SDL_Surface *surface) 02413 { 02414 widgetdata *tmp; 02415 02416 for (tmp = widget_list_head; tmp; tmp = tmp->next) 02417 { 02418 if (tmp->widgetSF == surface) 02419 { 02420 return tmp; 02421 } 02422 } 02423 02424 return NULL; 02425 } 02426 02427 /* wrapper function to get the outermost container the widget is inside before moving it */ 02428 void move_widget(widgetdata *widget, int x, int y) 02429 { 02430 widget = get_outermost_container(widget); 02431 02432 move_widget_rec(widget, x, y); 02433 } 02434 02435 /* move all widgets inside the container with the container at the same time */ 02436 void move_widget_rec(widgetdata *widget, int x, int y) 02437 { 02438 /* widget doesn't exist, means the parent node has no children */ 02439 if (!widget) 02440 { 02441 return; 02442 } 02443 02444 /* no movement needed */ 02445 if (x == 0 && y == 0) 02446 { 02447 return; 02448 } 02449 02450 /* move the widget */ 02451 widget->x1 += x; 02452 widget->y1 += y; 02453 02454 /* here, we want to walk through the inventory of the widget, if it exists. 02455 * when we come across a widget, we move it like we did with the container. 02456 * we loop until we reach the last sibling, but we also need to go recursive if we find a child node */ 02457 for (widget = widget->inv; widget; widget = widget->next) 02458 { 02459 move_widget_rec(widget, x, y); 02460 } 02461 } 02462 02463 void resize_widget(widgetdata *widget, int side, int offset) 02464 { 02465 int x = widget->x1; 02466 int y = widget->y1; 02467 int width = widget->wd; 02468 int height = widget->ht; 02469 02470 if (side & RESIZE_LEFT) 02471 { 02472 x = widget->x1 + widget->wd - offset; 02473 width = offset; 02474 } 02475 else if (side & RESIZE_RIGHT) 02476 { 02477 width = offset; 02478 } 02479 02480 if (side & RESIZE_TOP) 02481 { 02482 y = widget->y1 + widget->ht - offset; 02483 height = offset; 02484 } 02485 else if (side & RESIZE_BOTTOM) 02486 { 02487 height = offset; 02488 } 02489 02490 resize_widget_rec(widget, x, width, y, height); 02491 } 02492 02493 void resize_widget_rec(widgetdata *widget, int x, int width, int y, int height) 02494 { 02495 widgetdata *widget_container, *tmp, *cmp1, *cmp2, *cmp3, *cmp4; 02496 _widget_container_strip *container_strip = NULL; 02497 _widget_container *container = NULL; 02498 02499 /* move the widget. this is the easy bit, watch as your eyes bleed when you see the next thing we have to do */ 02500 widget->x1 = x; 02501 widget->y1 = y; 02502 widget->wd = width; 02503 widget->ht = height; 02504 02505 WIDGET_REDRAW(widget); 02506 02507 /* now we get our parent node if it exists */ 02508 02509 /* loop until we hit the first sibling */ 02510 for (widget_container = widget; widget_container->prev; widget_container = widget_container->prev) 02511 { 02512 } 02513 02514 /* does the first sibling have a parent node? */ 02515 if (widget_container->env) 02516 { 02517 /* ok, now we need to resize the parent too. but before we do this, we need to see if other widgets inside should prevent it from 02518 * being resized. the code below is ugly, but necessary in order to calculate the new size of the container. and one more thing... 02519 * MY EYES! THE GOGGLES DO NOTHING! */ 02520 02521 widget_container = widget_container->env; 02522 container = CONTAINER(widget_container); 02523 02524 /* special case for strip containers */ 02525 switch (widget_container->WidgetSubtypeID) 02526 { 02527 case CONTAINER_STRIP_ID: 02528 case MENU_ID: 02529 case MENUITEM_ID: 02530 container_strip = CONTAINER_STRIP(widget_container); 02531 02532 /* we move all the widgets before or after the widget that got resized, depending on which side got the resize */ 02533 if (container_strip->horizontal) 02534 { 02535 /* now move everything we come across */ 02536 move_widget_rec(widget, 0, widget_container->y1 + container->outer_padding_top - widget->y1); 02537 02538 /* every node before the widget we push right */ 02539 for (tmp = widget->prev; tmp; tmp = tmp->prev) 02540 { 02541 move_widget_rec(tmp, tmp->next->x1 + tmp->next->wd - tmp->x1 + container_strip->inner_padding, widget_container->y1 + container->outer_padding_top - tmp->y1); 02542 } 02543 02544 /* while every node after the widget we push left */ 02545 for (tmp = widget->next; tmp; tmp = tmp->next) 02546 { 02547 move_widget_rec(tmp, tmp->prev->x1 - tmp->x1 - tmp->wd - container_strip->inner_padding, widget_container->y1 + container->outer_padding_top - tmp->y1); 02548 } 02549 02550 /* we have to set this, otherwise stupid things happen */ 02551 x = widget_container->inv_rev->x1; 02552 /* we don't want the container moving up or down in this case */ 02553 y = widget_container->y1 + container->outer_padding_top; 02554 } 02555 else 02556 { 02557 /* now move everything we come across */ 02558 move_widget_rec(widget, widget_container->x1 + container->outer_padding_left - widget->x1, 0); 02559 02560 /* every node before the widget we push downwards */ 02561 for (tmp = widget->prev; tmp; tmp = tmp->prev) 02562 { 02563 move_widget_rec(tmp, widget_container->x1 + container->outer_padding_left - tmp->x1, tmp->next->y1 + tmp->next->ht - tmp->y1 + container_strip->inner_padding); 02564 } 02565 02566 /* while every node after the widget we push upwards */ 02567 for (tmp = widget->next; tmp; tmp = tmp->next) 02568 { 02569 move_widget_rec(tmp, widget_container->x1 + container->outer_padding_left - tmp->x1, tmp->prev->y1 - tmp->y1 - tmp->ht - container_strip->inner_padding); 02570 } 02571 02572 /* we don't want the container moving sideways in this case */ 02573 x = widget_container->x1 + container->outer_padding_left; 02574 /* we have to set this, otherwise stupid things happen */ 02575 y = widget_container->inv_rev->y1; 02576 } 02577 break; 02578 } 02579 02580 /* TODO: add the buffer system so that this mess of code will only need to be executed after the user stops resizing the widget */ 02581 cmp1 = cmp2 = cmp3 = cmp4 = widget; 02582 02583 for (tmp = widget_container->inv; tmp; tmp = tmp->next) 02584 { 02585 /* widget's left x co-ordinate becomes greater than tmp's left x coordinate */ 02586 if (cmp1->x1 > tmp->x1) 02587 { 02588 x = tmp->x1; 02589 width += cmp1->x1 - tmp->x1; 02590 cmp1 = tmp; 02591 } 02592 02593 /* widget's top y co-ordinate becomes greater than tmp's top y coordinate */ 02594 if (cmp2->y1 > tmp->y1) 02595 { 02596 y = tmp->y1; 02597 height += cmp2->y1 - tmp->y1; 02598 cmp2 = tmp; 02599 } 02600 02601 /* widget's right x co-ordinate becomes less than tmp's right x coordinate */ 02602 if (cmp3->x1 + cmp3->wd < tmp->x1 + tmp->wd) 02603 { 02604 width += tmp->x1 + tmp->wd - cmp3->x1 - cmp3->wd; 02605 cmp3 = tmp; 02606 } 02607 02608 /* widget's bottom y co-ordinate becomes less than tmp's bottom y coordinate */ 02609 if (cmp4->y1 + cmp4->ht < tmp->y1 + tmp->ht) 02610 { 02611 height += tmp->y1 + tmp->ht - cmp4->y1 - cmp4->ht; 02612 cmp4 = tmp; 02613 } 02614 } 02615 02616 x -= container->outer_padding_left; 02617 y -= container->outer_padding_top; 02618 width += container->outer_padding_left + container->outer_padding_right; 02619 height += container->outer_padding_top + container->outer_padding_bottom; 02620 02621 /* after all that, we now check to see if the parent needs to be resized before we waste even more resources going recursive */ 02622 if (x != widget_container->x1 || y != widget_container->y1 || width != widget_container->wd || height != widget_container->ht) 02623 { 02624 resize_widget_rec(widget_container, x, width, y, height); 02625 } 02626 } 02627 } 02628 02630 widgetdata *add_label(char *text, int font, const char *color) 02631 { 02632 widgetdata *widget; 02633 _widget_label *label; 02634 02635 widget = create_widget_object(LABEL_ID); 02636 label = LABEL(widget); 02637 02638 label->text = text; 02639 02640 label->font = font; 02641 label->color = color; 02642 02643 resize_widget(widget, RESIZE_RIGHT, string_get_width(font, text, 0)); 02644 resize_widget(widget, RESIZE_BOTTOM, string_get_height(font, text, 0) + 3); 02645 02646 return widget; 02647 } 02648 02650 widgetdata *add_bitmap(int bitmap_id) 02651 { 02652 widgetdata *widget; 02653 _widget_bitmap *bitmap; 02654 02655 widget = create_widget_object(BITMAP_ID); 02656 bitmap = BITMAP(widget); 02657 02658 bitmap->bitmap_id = bitmap_id; 02659 02660 resize_widget(widget, RESIZE_RIGHT, Bitmaps[bitmap_id]->bitmap->w); 02661 resize_widget(widget, RESIZE_BOTTOM, Bitmaps[bitmap_id]->bitmap->h); 02662 02663 return widget; 02664 } 02665 02667 widgetdata *create_menu(int x, int y, widgetdata *owner) 02668 { 02669 widgetdata *widget_menu = create_widget_object(MENU_ID); 02670 _widget_container *container_menu = CONTAINER(widget_menu); 02671 _widget_container_strip *container_strip_menu = CONTAINER_STRIP(widget_menu); 02672 02673 /* Place the menu at these co-ordinates. */ 02674 widget_menu->x1 = x; 02675 widget_menu->y1 = y; 02676 /* Point the menu to the owner. */ 02677 (MENU(widget_menu))->owner = owner; 02678 /* Magic numbers for now, maybe it will be possible in future to customize this in files. */ 02679 container_menu->outer_padding_left = 2; 02680 container_menu->outer_padding_right = 2; 02681 container_menu->outer_padding_top = 2; 02682 container_menu->outer_padding_bottom = 2; 02683 container_strip_menu->inner_padding = 0; 02684 02685 return widget_menu; 02686 } 02687 02689 void add_menuitem(widgetdata *menu, char *text, void (*menu_func_ptr)(widgetdata *, int, int), int menu_type, int val) 02690 { 02691 widgetdata *widget_menuitem, *widget_label, *widget_bitmap, *tmp; 02692 _widget_container *container_menuitem, *container_menu; 02693 _widget_container_strip *container_strip_menuitem; 02694 _menuitem *menuitem; 02695 02696 widget_menuitem = create_widget_object(MENUITEM_ID); 02697 02698 container_menuitem = CONTAINER(widget_menuitem); 02699 container_strip_menuitem = CONTAINER_STRIP(widget_menuitem); 02700 02701 /* Initialize attributes. */ 02702 container_menuitem->outer_padding_left = 4; 02703 container_menuitem->outer_padding_right = 2; 02704 container_menuitem->outer_padding_top = 2; 02705 container_menuitem->outer_padding_bottom = 0; 02706 container_strip_menuitem->inner_padding = 4; 02707 container_strip_menuitem->horizontal = 1; 02708 02709 widget_label = add_label(text, FONT_ARIAL10, COLOR_WHITE); 02710 02711 if (menu_type == MENU_CHECKBOX) 02712 { 02713 /* This is really just test code to see if bitmaps work. 02714 * Menuitems will later contain checkboxes later anyway, 02715 * so this will probably evolve into proper code later. */ 02716 widget_bitmap = add_bitmap(val ? BITMAP_CHECKBOX_ON : BITMAP_CHECKBOX); 02717 insert_widget_in_container(widget_menuitem, widget_bitmap); 02718 } 02719 02720 insert_widget_in_container(widget_menuitem, widget_label); 02721 insert_widget_in_container(menu, widget_menuitem); 02722 02723 /* Add the pointer to the function to the menuitem. */ 02724 menuitem = MENUITEM(widget_menuitem); 02725 menuitem->menu_func_ptr = menu_func_ptr; 02726 menuitem->menu_type = menu_type; 02727 02728 /* Sanity check. Menuitems should always exist inside a menu. */ 02729 if (widget_menuitem->env && widget_menuitem->env->WidgetSubtypeID == MENU_ID) 02730 { 02731 container_menu = CONTAINER(widget_menuitem->env); 02732 02733 /* Resize labels in each menuitem to the width of the menu. */ 02734 for (tmp = widget_menuitem; tmp; tmp = tmp->next) 02735 { 02736 if (tmp->inv) 02737 { 02738 container_menuitem = CONTAINER(tmp); 02739 02740 if (menu_type == MENU_CHECKBOX) 02741 { 02742 resize_widget(tmp->inv, RESIZE_RIGHT, menu->wd - tmp->inv_rev->wd - container_strip_menuitem->inner_padding - container_menu->outer_padding_left - container_menu->outer_padding_right - container_menuitem->outer_padding_left - container_menuitem->outer_padding_right); 02743 } 02744 else 02745 { 02746 resize_widget(tmp->inv, RESIZE_RIGHT, menu->wd - container_menu->outer_padding_left - container_menu->outer_padding_right - container_menuitem->outer_padding_left - container_menuitem->outer_padding_right); 02747 } 02748 } 02749 } 02750 } 02751 } 02752 02754 void add_separator(widgetdata *widget) 02755 { 02756 (void) widget; 02757 } 02758 02765 void menu_finalize(widgetdata *widget) 02766 { 02767 int xoff = 0, yoff = 0; 02768 02769 /* Would the menu go over the maximum screen width? */ 02770 if (widget->x1 + widget->wd > ScreenSurface->w) 02771 { 02772 /* Will appear to the left of the cursor instead of right of it. */ 02773 xoff = -widget->wd; 02774 02775 /* Take submenus into account, and shift them depending on the 02776 * parent menu's width. */ 02777 if (widget->type_prev && widget->type_prev->WidgetSubtypeID == MENU_ID) 02778 { 02779 xoff += -widget->type_prev->wd + 4; 02780 } 02781 } 02782 02783 /* Similar checks for screen height. */ 02784 if (widget->y1 + widget->ht > ScreenSurface->h) 02785 { 02786 /* Submenu, shift it up, so all of it can appear. */ 02787 if (widget->type_prev && widget->type_prev->WidgetSubtypeID == MENU_ID) 02788 { 02789 yoff = ScreenSurface->h - widget->ht - widget->y1 - 1; 02790 } 02791 /* Will appear above the cursor. */ 02792 else 02793 { 02794 yoff = -widget->ht; 02795 } 02796 } 02797 02798 move_widget(widget, xoff, yoff); 02799 } 02800 02802 void widget_redraw_all(int widget_type_id) 02803 { 02804 widgetdata *widget = cur_widget[widget_type_id]; 02805 02806 for (; widget; widget = widget->type_next) 02807 { 02808 widget->redraw = 1; 02809 } 02810 } 02811 02812 void menu_move_widget(widgetdata *widget, int x, int y) 02813 { 02814 widget_event_start_move(widget, x, y); 02815 } 02816 02817 void menu_create_widget(widgetdata *widget, int x, int y) 02818 { 02819 (void) x; 02820 (void) y; 02821 create_widget_object(widget->WidgetSubtypeID); 02822 } 02823 02824 void menu_remove_widget(widgetdata *widget, int x, int y) 02825 { 02826 (void) x; 02827 (void) y; 02828 remove_widget_object(widget); 02829 } 02830 02831 void menu_detach_widget(widgetdata *widget, int x, int y) 02832 { 02833 (void) x; 02834 (void) y; 02835 detach_widget(widget); 02836 } 02837 02838 void menu_set_say_filter(widgetdata *widget, int x, int y) 02839 { 02840 (void) widget; 02841 (void) x; 02842 (void) y; 02843 } 02844 02845 void menu_set_shout_filter(widgetdata *widget, int x, int y) 02846 { 02847 (void) widget; 02848 (void) x; 02849 (void) y; 02850 } 02851 02852 void menu_set_gsay_filter(widgetdata *widget, int x, int y) 02853 { 02854 (void) widget; 02855 (void) x; 02856 (void) y; 02857 } 02858 02859 void menu_set_tell_filter(widgetdata *widget, int x, int y) 02860 { 02861 (void) widget; 02862 (void) x; 02863 (void) y; 02864 } 02865 02866 void menu_set_channel_filter(widgetdata *widget, int x, int y) 02867 { 02868 (void) widget; 02869 (void) x; 02870 (void) y; 02871 } 02872 02873 void submenu_chatwindow_filters(widgetdata *widget, int x, int y) 02874 { 02875 (void) x; 02876 (void) y; 02877 add_menuitem(widget, "Say", &menu_set_say_filter, MENU_CHECKBOX, 0); 02878 add_menuitem(widget, "Shout", &menu_set_shout_filter, MENU_CHECKBOX, 0); 02879 add_menuitem(widget, "Group", &menu_set_gsay_filter, MENU_CHECKBOX, 0); 02880 add_menuitem(widget, "Tells", &menu_set_tell_filter, MENU_CHECKBOX, 0); 02881 add_menuitem(widget, "Channels", &menu_set_channel_filter, MENU_CHECKBOX, 0); 02882 } 02883 02884 void menu_inv_filter_all() 02885 { 02886 inventory_filter_set(INVENTORY_FILTER_ALL); 02887 } 02888 02889 void menu_inv_filter_applied() 02890 { 02891 inventory_filter_toggle(INVENTORY_FILTER_APPLIED); 02892 } 02893 02894 void menu_inv_filter_containers() 02895 { 02896 inventory_filter_toggle(INVENTORY_FILTER_CONTAINER); 02897 } 02898 02899 void menu_inv_filter_magical() 02900 { 02901 inventory_filter_toggle(INVENTORY_FILTER_MAGICAL); 02902 } 02903 02904 void menu_inv_filter_cursed() 02905 { 02906 inventory_filter_toggle(INVENTORY_FILTER_CURSED); 02907 } 02908 02909 void menu_inv_filter_unidentified() 02910 { 02911 inventory_filter_toggle(INVENTORY_FILTER_UNIDENTIFIED); 02912 } 02913 02914 void menu_inv_filter_locked() 02915 { 02916 inventory_filter_toggle(INVENTORY_FILTER_LOCKED); 02917 } 02918 02919 void menu_inv_filter_unapplied() 02920 { 02921 inventory_filter_toggle(INVENTORY_FILTER_UNAPPLIED); 02922 }
1.7.4