00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022
00023 #ifdef HAVE_SYS_TYPES_H
00024 #include <sys/types.h>
00025 #endif
00026 #include <dirent.h>
00027 #include <gtk/gtk.h>
00028 #ifdef XWIN
00029 #include <gdk/gdkx.h>
00030 #endif
00031 #include <glib.h>
00032 #include <unistd.h>
00033 #include <errno.h>
00034
00035 #include <cstdio>
00036 #ifdef WIN32
00037 #include <windows.h>
00038 #include <ole2.h>
00039 #include "servewin32.h"
00040 #else
00041 #include <sys/socket.h>
00042 #include <sys/un.h>
00043 #endif
00044 #include <fcntl.h>
00045 #include <cstdarg>
00046
00047 #include "shapelst.h"
00048 #include "shapevga.h"
00049 #include "Flex.h"
00050 #include "studio.h"
00051 #include "utils.h"
00052 #include "u7drag.h"
00053 #include "shapegroup.h"
00054 #include "shapefile.h"
00055 #include "locator.h"
00056 #include "combo.h"
00057 #include "Configuration.h"
00058 #include "objserial.h"
00059 #include "exceptions.h"
00060 #include "logo.xpm"
00061 #include "fnames.h"
00062 #include "execbox.h"
00063
00064 using std::cerr;
00065 using std::cout;
00066 using std::endl;
00067 using std::string;
00068 using std::vector;
00069 using std::ofstream;
00070
00071 ExultStudio *ExultStudio::self = 0;
00072 Configuration *config = 0;
00073 const std::string c_empty_string;
00074
00075
00076 static char *mode_names[4] = {"move1", "paint1", "paint_with_chunks1",
00077 "pick_for_combo1"};
00078
00079 enum ExultFileTypes {
00080 ShapeArchive =1,
00081 ChunkArchive,
00082 PaletteFile,
00083 FlexArchive,
00084 ComboArchive
00085 };
00086
00087 typedef struct _FileTreeItem FileTreeItem;
00088 struct _FileTreeItem
00089 {
00090 const gchar *label;
00091 ExultFileTypes datatype;
00092 FileTreeItem *children;
00093 };
00094
00095
00096 enum
00097 {
00098 FOLDER_COLUMN = 0,
00099 FILE_COLUMN,
00100 DATA_COLUMN,
00101 NUM_COLUMNS
00102 };
00103
00104
00105 static void Filelist_selection(GtkTreeView *treeview, GtkTreePath *path)
00106 {
00107 int type = -1;
00108 char *text;
00109 GtkTreeIter iter;
00110 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
00111
00112 gtk_tree_model_get_iter(model, &iter, path);
00113 gtk_tree_model_get(model, &iter, FILE_COLUMN, &text, DATA_COLUMN,
00114 &type,-1);
00115 printf("%s %d\n",text,type);
00116
00117 ExultStudio *studio = ExultStudio::get_instance();
00118 switch(type) {
00119 case ShapeArchive:
00120 studio->set_browser("Shape Browser",
00121 studio->create_browser(text));
00122 break;
00123 case ComboArchive:
00124 studio->set_browser("Combo Browser",
00125 studio->create_browser(text));
00126 break;
00127 case ChunkArchive:
00128 studio->set_browser("Chunk Browser",
00129 studio->create_browser(text));
00130 break;
00131 case PaletteFile:
00132 studio->set_browser("Palette Browser",
00133 studio->create_browser(text));
00134 break;
00135 default:
00136 break;
00137 }
00138 g_free(text);
00139 }
00140
00141 C_EXPORT void on_filelist_tree_cursor_changed(GtkTreeView *treeview)
00142 {
00143 GtkTreePath *path;
00144 GtkTreeViewColumn *col;
00145
00146 gtk_tree_view_get_cursor(treeview, &path, &col);
00147 Filelist_selection(treeview, path);
00148 }
00149
00150 C_EXPORT void
00151 on_open_game_activate (GtkMenuItem *menuitem,
00152 gpointer user_data)
00153 {
00154 ExultStudio::get_instance()->choose_game_path();
00155 }
00156
00157 C_EXPORT void
00158 on_new_game_activate (GtkMenuItem *menuitem,
00159 gpointer user_data)
00160 {
00161 ExultStudio::get_instance()->new_game();
00162 }
00163
00164 C_EXPORT void
00165 on_connect_activate (GtkMenuItem *menuitem,
00166 gpointer user_data)
00167 {
00168 ExultStudio::get_instance()->connect_to_server();
00169 }
00170
00171 C_EXPORT void
00172 on_save_all1_activate (GtkMenuItem *menuitem,
00173 gpointer user_data)
00174 {
00175 ExultStudio::get_instance()->save_all();
00176 }
00177
00178 C_EXPORT void
00179 on_new_shapes_file_activate (GtkMenuItem *menuitem,
00180 gpointer user_data)
00181 {
00182 ExultStudio::get_instance()->new_shape_file(false);
00183 }
00184
00185 C_EXPORT void
00186 on_new_shape_file_activate (GtkMenuItem *menuitem,
00187 gpointer user_data)
00188 {
00189 ExultStudio::get_instance()->new_shape_file(true);
00190 }
00191
00192 C_EXPORT void
00193 on_save_map_menu_activate (GtkMenuItem *menuitem,
00194 gpointer user_data)
00195 {
00196 ExultStudio::get_instance()->write_map();
00197 }
00198
00199 C_EXPORT void
00200 on_read_map_menu_activate (GtkMenuItem *menuitem,
00201 gpointer user_data)
00202 {
00203 ExultStudio::get_instance()->read_map();
00204 }
00205
00206 C_EXPORT void
00207 on_save_shape_info1_activate (GtkMenuItem *menuitem,
00208 gpointer user_data)
00209 {
00210 ExultStudio::get_instance()->write_shape_info();
00211 }
00212
00213 C_EXPORT void
00214 on_reload_usecode_menu_activate (GtkMenuItem *menuitem,
00215 gpointer user_data)
00216 {
00217 ExultStudio::get_instance()->reload_usecode();
00218 }
00219
00220 C_EXPORT void
00221 on_compile_usecode_menu_activate (GtkMenuItem *menuitem,
00222 gpointer user_data)
00223 {
00224 ExultStudio::get_instance()->compile();
00225 }
00226
00227 C_EXPORT void
00228 on_save_groups1_activate (GtkMenuItem *menuitem,
00229 gpointer user_data)
00230 {
00231 ExultStudio::get_instance()->save_groups();
00232 }
00233
00234 C_EXPORT void
00235 on_save_combos1_activate (GtkMenuItem *menuitem,
00236 gpointer user_data)
00237 {
00238 ExultStudio::get_instance()->save_combos();
00239 }
00240
00241 C_EXPORT void
00242 on_preferences_activate (GtkMenuItem *menuitem,
00243 gpointer user_data)
00244 {
00245 ExultStudio::get_instance()->open_preferences();
00246 }
00247
00248 C_EXPORT void
00249 on_cut1_activate (GtkMenuItem *menuitem,
00250 gpointer user_data)
00251 {
00252 unsigned char z = 0;
00253 ExultStudio::get_instance()->send_to_server(Exult_server::cut,
00254 &z, 1);
00255 }
00256
00257 C_EXPORT void
00258 on_copy1_activate (GtkMenuItem *menuitem,
00259 gpointer user_data)
00260 {
00261 unsigned char o = 1;
00262 ExultStudio::get_instance()->send_to_server(Exult_server::cut,
00263 &o, 1);
00264 }
00265
00266 C_EXPORT void
00267 on_paste1_activate (GtkMenuItem *menuitem,
00268 gpointer user_data)
00269 {
00270 ExultStudio::get_instance()->send_to_server(Exult_server::paste);
00271 }
00272
00273 C_EXPORT void
00274 on_properties1_activate (GtkMenuItem *menuitem,
00275 gpointer user_data)
00276 {
00277 unsigned char o = 0;
00278 ExultStudio::get_instance()->send_to_server(
00279 Exult_server::edit_selected, &o, 1);
00280 }
00281
00282 C_EXPORT void
00283 on_basic_properties1_activate (GtkMenuItem *menuitem,
00284 gpointer user_data)
00285 {
00286 unsigned char o = 1;
00287 ExultStudio::get_instance()->send_to_server(
00288 Exult_server::edit_selected, &o, 1);
00289 }
00290
00291 C_EXPORT void
00292 on_move1_activate (GtkMenuItem *menuitem,
00293 gpointer user_data)
00294 {
00295
00296 if (GTK_CHECK_MENU_ITEM(menuitem)->active)
00297 ExultStudio::get_instance()->set_edit_mode(0);
00298 }
00299
00300 C_EXPORT void
00301 on_paint1_activate (GtkMenuItem *menuitem,
00302 gpointer user_data)
00303 {
00304 if (GTK_CHECK_MENU_ITEM(menuitem)->active)
00305 ExultStudio::get_instance()->set_edit_mode(1);
00306 }
00307
00308 C_EXPORT void
00309 on_paint_with_chunks1_activate (GtkMenuItem *menuitem,
00310 gpointer user_data)
00311 {
00312 if (GTK_CHECK_MENU_ITEM(menuitem)->active)
00313 ExultStudio::get_instance()->set_edit_mode(2);
00314 }
00315
00316 C_EXPORT void
00317 on_pick_for_combo1_activate (GtkMenuItem *menuitem,
00318 gpointer user_data)
00319 {
00320 if (GTK_CHECK_MENU_ITEM(menuitem)->active)
00321 ExultStudio::get_instance()->set_edit_mode(3);
00322 }
00323
00324 C_EXPORT void
00325 on_unused_shapes1_activate (GtkMenuItem *menuitem,
00326 gpointer user_data)
00327 {
00328 if (EStudio::Prompt(
00329 "Finding unused shapes may take several minutes\nProceed?",
00330 "Yes", "No") != 0)
00331 return;
00332 ExultStudio::get_instance()->send_to_server(
00333 Exult_server::unused_shapes);
00334 }
00335
00336 C_EXPORT void
00337 on_play_button_clicked (GtkToggleButton *button,
00338 gpointer user_data)
00339 {
00340 ExultStudio::get_instance()->set_play(
00341 gtk_toggle_button_get_active(button));
00342 }
00343
00344 C_EXPORT void
00345 on_tile_grid_button_toggled (GtkToggleButton *button,
00346 gpointer user_data)
00347 {
00348 ExultStudio::get_instance()->set_tile_grid(
00349 gtk_toggle_button_get_active(button));
00350 }
00351
00352 C_EXPORT void
00353 on_edit_lift_spin_changed (GtkSpinButton *button,
00354 gpointer user_data)
00355 {
00356 ExultStudio::get_instance()->set_edit_lift(
00357 gtk_spin_button_get_value_as_int(button));
00358 }
00359
00360 C_EXPORT void
00361 on_hide_lift_spin_changed (GtkSpinButton *button,
00362 gpointer user_data)
00363 {
00364 ExultStudio::get_instance()->set_hide_lift(
00365 gtk_spin_button_get_value_as_int(button));
00366 }
00367
00368 C_EXPORT void
00369 on_edit_terrain_button_toggled (GtkToggleButton *button,
00370 gpointer user_data)
00371 {
00372 ExultStudio::get_instance()->set_edit_terrain(
00373 gtk_toggle_button_get_active(button));
00374 }
00375
00376 void on_choose_directory (gchar *dir,
00377 gpointer user_data)
00378 {
00379 ExultStudio::get_instance()->set_game_path(dir);
00380 }
00381
00382
00383
00384
00385 C_EXPORT gint on_main_window_configure_event
00386 (
00387 GtkWidget *widget,
00388 GdkEventConfigure *event,
00389 gpointer data
00390 )
00391 {
00392 ExultStudio *studio = ExultStudio::get_instance();
00393
00394 studio->set_spin("hide_lift_spin",
00395 studio->get_spin("hide_lift_spin"), 1, 16);
00396 return FALSE;
00397 }
00398
00399
00400
00401
00402 C_EXPORT gboolean on_main_window_delete_event
00403 (
00404 GtkWidget *widget,
00405 GdkEvent *event,
00406 gpointer user_data
00407 )
00408 {
00409 if (!ExultStudio::get_instance()->okay_to_close())
00410 return TRUE;
00411 return FALSE;
00412 }
00413 C_EXPORT void on_main_window_destroy_event
00414 (
00415 GtkWidget *widget,
00416 gpointer data
00417 )
00418 {
00419 gtk_main_quit();
00420 }
00421
00422
00423
00424 C_EXPORT void
00425 on_main_window_quit (GtkMenuItem *menuitem,
00426 gpointer user_data)
00427 {
00428 if (ExultStudio::get_instance()->okay_to_close())
00429 gtk_main_quit();
00430 }
00431
00432
00433
00434 C_EXPORT gboolean on_main_window_focus_in_event
00435 (
00436 GtkWidget *widget,
00437 GdkEventFocus *event,
00438 gpointer user_data
00439 )
00440 {
00441 Shape_chooser::check_editing_files();
00442 return FALSE;
00443 }
00444
00445
00446
00447
00448
00449
00450 ExultStudio::ExultStudio(int argc, char **argv): files(0), curfile(0),
00451 names(0), glade_path(0), shape_info_modified(false),
00452 shape_names_modified(false),
00453 vgafile(0), facefile(0), eggwin(0),
00454 server_socket(-1), server_input_tag(-1),
00455 static_path(0), image_editor(0), default_game(0), background_color(0),
00456 browser(0), palbuf(0), egg_monster_draw(0),
00457 egg_ctx(0),
00458 waiting_for_server(0), npcwin(0), npc_draw(0), npc_face_draw(0),
00459 npc_ctx(0), npc_status_id(0),
00460 objwin(0), obj_draw(0), shapewin(0), shape_draw(0),
00461 equipwin(0), locwin(0), combowin(0), compilewin(0), compile_box(0)
00462 {
00463
00464 self = this;
00465 gtk_init( &argc, &argv );
00466 gdk_rgb_init();
00467 glade_init();
00468 config = new Configuration;
00469 config->read_config_file(USER_CONFIGURATION_FILE);
00470
00471 const char *xmldir = 0;
00472 const char *game = 0;
00473 static char *optstring = "g:x:d:";
00474 extern int optind, opterr, optopt;
00475 extern char *optarg;
00476 opterr = 0;
00477 int optchr;
00478 while ((optchr = getopt(argc, argv, optstring)) != -1)
00479 switch (optchr)
00480 {
00481 case 'g':
00482 game = optarg;
00483 break;
00484 case 'x':
00485 xmldir = optarg;
00486 break;
00487 }
00488 string dirstr, datastr;
00489 if (!xmldir)
00490 {
00491 config->value("config/disk/data_path", datastr, EXULT_DATADIR);
00492 xmldir = datastr.c_str();
00493 }
00494 string defgame;
00495 config->value("config/estudio/default_game", defgame, "blackgate");
00496 default_game = g_strdup(defgame.c_str());
00497 if (!game)
00498 game = default_game;
00499 config->set("config/estudio/default_game", defgame, true);
00500 char path[256];
00501 if(xmldir)
00502 strcpy(path, xmldir);
00503 else if(U7exists(EXULT_DATADIR"/exult_studio.glade"))
00504 strcpy(path,EXULT_DATADIR);
00505 else
00506 strcpy(path,".");
00507 strcat(path, "/exult_studio.glade");
00508
00509 app_xml = glade_xml_new(path, NULL, NULL);
00510 app = glade_xml_get_widget( app_xml, "main_window" );
00511 glade_path = g_strdup(path);
00512
00513
00514
00515 glade_xml_signal_autoconnect(app_xml);
00516 int w, h;
00517 config->value("config/estudio/main/width", w, 0);
00518 config->value("config/estudio/main/height", h, 0);
00519 if (w > 0 && h > 0)
00520
00521 gtk_window_resize(GTK_WINDOW(app), w, h);
00522 gtk_widget_show( app );
00523
00524 int bcolor;
00525 config->value("config/estudio/background_color", bcolor, 0);
00526 background_color = bcolor;
00527 if (game)
00528 {
00529 string d("config/disk/game/");
00530 d += game;
00531 string gd = d + "/path";
00532 config->value(gd.c_str(), dirstr, "");
00533 if (dirstr == "")
00534 {
00535 cerr << "Game '" << game <<
00536 "' path not found in config. file" << endl;
00537 exit(1);
00538 }
00539 string pd = d + "/patch";
00540 string ptchstr;
00541 config->value(pd.c_str(), ptchstr, "");
00542 set_game_path(dirstr.c_str(), ptchstr == "" ? 0
00543 : ptchstr.c_str());
00544 }
00545 string iedit;
00546 config->value("config/estudio/image_editor", iedit, "gimp-remote -n");
00547 image_editor = g_strdup(iedit.c_str());
00548 config->set("config/estudio/image_editor", iedit, true);
00549 #ifdef WIN32
00550 OleInitialize(NULL);
00551 #endif
00552
00553
00554 GSList *group = NULL;
00555 for (int i = 0; i < sizeof(mode_names)/sizeof(mode_names[0]); i++)
00556 {
00557 GtkWidget *item = glade_xml_get_widget(app_xml, mode_names[i]);
00558 gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(item),
00559 group);
00560 group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(item));
00561 gtk_check_menu_item_set_active(
00562 GTK_CHECK_MENU_ITEM(item), i == 0);
00563 }
00564 }
00565
00566 ExultStudio::~ExultStudio()
00567 {
00568 #ifdef WIN32
00569 OleUninitialize();
00570 #endif
00571
00572 int w = app->allocation.width, h = app->allocation.height;
00573
00574 Shape_chooser::clear_editing_files();
00575 config->set("config/estudio/main/width", w, true);
00576 config->set("config/estudio/main/height", h, true);
00577 int num_names = names.size();
00578 for (int i = 0; i < num_names; i++)
00579 delete names[i];
00580 names.resize(0);
00581 g_free(glade_path);
00582 delete files;
00583 files = 0;
00584 delete [] palbuf;
00585 palbuf = 0;
00586 if (objwin)
00587 gtk_widget_destroy(objwin);
00588 delete obj_draw;
00589 if (eggwin)
00590 gtk_widget_destroy(eggwin);
00591 delete egg_monster_draw;
00592 eggwin = 0;
00593 if (npcwin)
00594 gtk_widget_destroy(npcwin);
00595 delete npc_draw;
00596 npcwin = 0;
00597 if (shapewin)
00598 gtk_widget_destroy(shapewin);
00599 delete shape_draw;
00600 shapewin = 0;
00601 if (equipwin)
00602 gtk_widget_destroy(equipwin);
00603 equipwin = 0;
00604 if (compilewin)
00605 gtk_widget_destroy(compilewin);
00606 compilewin = 0;
00607 delete compile_box;
00608 compile_box = 0;
00609 if (locwin)
00610 delete locwin;
00611 if (combowin)
00612 delete combowin;
00613 locwin = 0;
00614 g_object_unref( G_OBJECT( app_xml ) );
00615 #ifndef WIN32
00616 if (server_input_tag >= 0)
00617 gdk_input_remove(server_input_tag);
00618 if (server_socket >= 0)
00619 close(server_socket);
00620 #else
00621 if (server_input_tag >= 0)
00622 gtk_timeout_remove(server_input_tag);
00623 if (server_socket >= 0)
00624 Exult_server::disconnect_from_server();
00625 #endif
00626 g_free(static_path);
00627 g_free(image_editor);
00628 g_free(default_game);
00629 self = 0;
00630 delete config;
00631 config = 0;
00632 }
00633
00634
00635
00636
00637
00638 bool ExultStudio::okay_to_close
00639 (
00640 )
00641 {
00642 if (need_to_save())
00643 {
00644 int choice = prompt("File(s) modified. Save?",
00645 "Yes", "No", "Cancel");
00646 if (choice == 2)
00647 return false;
00648 if (choice == 0)
00649 save_all();
00650 }
00651 return true;
00652 }
00653
00654
00655
00656
00657
00658 inline bool Window_has_focus(GtkWindow *win)
00659 {
00660 return (win->focus_widget != 0 &&
00661 GTK_WIDGET_HAS_FOCUS(win->focus_widget));
00662 }
00663
00664
00665
00666
00667
00668
00669 bool ExultStudio::has_focus
00670 (
00671 )
00672 {
00673 if (Window_has_focus(GTK_WINDOW(app)))
00674 return true;
00675
00676 vector<GtkWindow*>::const_iterator it;
00677 for (it = group_windows.begin(); it != group_windows.end(); ++it)
00678 if (Window_has_focus(*it))
00679 return true;
00680 return false;
00681 }
00682
00683
00684
00685
00686 void ExultStudio::set_browser(const char *name, Object_browser *obj)
00687 {
00688 GtkWidget *browser_frame = glade_xml_get_widget(app_xml,
00689 "browser_frame" );
00690 GtkWidget *browser_box = glade_xml_get_widget(app_xml, "browser_box" );
00691
00692 if (browser)
00693 gtk_container_remove(GTK_CONTAINER(browser_box),
00694 browser->get_widget());
00695 browser = obj;
00696
00697 gtk_frame_set_label( GTK_FRAME( browser_frame ), name );
00698 gtk_widget_show( browser_box );
00699 if (browser)
00700 gtk_box_pack_start(GTK_BOX(browser_box),
00701 browser->get_widget(), TRUE, TRUE, 0);
00702 }
00703
00704 Object_browser *ExultStudio::create_browser(const char *fname)
00705 {
00706 curfile = open_shape_file(fname);
00707 if (!curfile)
00708 return 0;
00709 Object_browser *chooser = curfile->get_browser(vgafile, palbuf);
00710 setup_groups();
00711 return chooser;
00712 }
00713
00714
00715
00716
00717
00718 Shape_group_file *ExultStudio::get_cur_groups
00719 (
00720 )
00721 {
00722 return curfile ? curfile->get_groups() : 0;
00723 }
00724
00725
00726
00727
00728
00729 inline bool Is_dir_marker
00730 (
00731 char c
00732 )
00733 {
00734 return (c == '/' || c == '\\' || c == ':');
00735 }
00736
00737
00738
00739
00740
00741 void on_choose_new_game_dir
00742 (
00743 const char *dir,
00744 gpointer udata
00745 )
00746 {
00747 ((ExultStudio *) udata)->create_new_game(dir);
00748 }
00749 void ExultStudio::create_new_game
00750 (
00751 const char *dir
00752 )
00753 {
00754
00755 const char *eptr = dir + strlen(dir) - 1;
00756 while (eptr >= dir && Is_dir_marker(*eptr))
00757 eptr--;
00758 eptr++;
00759 const char *ptr = eptr - 1;
00760 for ( ; ptr >= dir; ptr--)
00761 if (Is_dir_marker(*ptr))
00762 {
00763 ptr++;
00764 break;
00765 }
00766 if (ptr < dir || eptr - ptr <= 0)
00767 {
00768 EStudio::Alert("Can't find base game name in '%s'", dir);
00769 return;
00770 }
00771 string gamestr(ptr, eptr - ptr);
00772 string dirstr(dir);
00773 string static_path = dirstr + "/static";
00774 if (U7exists(static_path))
00775 {
00776 string msg("Directory '");
00777 msg += static_path;
00778 msg += "' already exists.\n";
00779 msg += "Files within may be overwritten.\n";
00780 msg += "Proceed?";
00781 if (prompt(msg.c_str(), "Yes", "No") != 0)
00782 return;
00783 }
00784 U7mkdir(dir, 0755);
00785
00786 U7mkdir(static_path.c_str(), 0755);
00787 string patch_path = dirstr + "/patch";
00788 U7mkdir(patch_path.c_str(), 0755);
00789
00790 string d("config/disk/game/");
00791 string gameconfig = d + gamestr;
00792 d = gameconfig + "/path";
00793 config->set(d.c_str(), dirstr, false);
00794 d = gameconfig + "/patch";
00795 config->set(d.c_str(), patch_path, false);
00796 d = gameconfig + "/editing";
00797 config->set(d.c_str(), "yes", true);
00798 string esdir;
00799 config->value("config/disk/data_path", esdir, EXULT_DATADIR);
00800 esdir += "/estudio/new";
00801 DIR *dirrd = opendir(esdir.c_str());
00802 if (!dirrd)
00803 EStudio::Alert("'%s' for initial data files not found",
00804 esdir.c_str());
00805 else
00806 {
00807 struct dirent *entry;
00808 while(entry=readdir(dirrd))
00809 {
00810 char *fname = entry->d_name;
00811 int flen = strlen(fname);
00812
00813 if(!strcmp(fname, ".") || !strcmp(fname,".."))
00814 continue;
00815 string src = esdir + '/' + fname;
00816 string dest = static_path + '/' + fname;
00817 try {
00818 U7copy(src.c_str(), dest.c_str());
00819 } catch (exult_exception& e) {
00820 EStudio::Alert(e.what());
00821 }
00822 }
00823 closedir(dirrd);
00824 }
00825 set_game_path(dir);
00826 write_shape_info(true);
00827 }
00828
00829
00830
00831
00832
00833 void ExultStudio::new_game()
00834 {
00835 if (!okay_to_close())
00836 return;
00837 GtkFileSelection *fsel = Create_file_selection(
00838 "Choose new game directory",
00839 on_choose_new_game_dir, this);
00840 gtk_widget_show(GTK_WIDGET(fsel));
00841 }
00842
00843
00844
00845
00846 void ExultStudio::choose_game_path()
00847 {
00848 if (!okay_to_close())
00849 return;
00850 size_t bufsize=128;
00851 char * cwd(new char[bufsize]);
00852 while(!getcwd(cwd,bufsize))
00853 {
00854 if(errno==ERANGE)
00855 {
00856 bufsize+=128;
00857 delete [] cwd;
00858 cwd=new char[bufsize];
00859 }
00860 else
00861 {
00862
00863 delete [] cwd;
00864 return;
00865 }
00866 }
00867 GtkFileSelection *fsel = Create_file_selection(
00868 "Select game directory",
00869 (File_sel_okay_fun) on_choose_directory, 0L);
00870 gtk_file_selection_set_filename(fsel, cwd);
00871 gtk_widget_show(GTK_WIDGET(fsel));
00872 delete [] cwd;
00873 }
00874
00875
00876
00877
00878
00879
00880 void ExultStudio::set_game_path(const char *gamepath, const char *patchpath)
00881 {
00882
00883 Shape_chooser::clear_editing_files();
00884
00885 add_system_path("<GAME>", gamepath);
00886 if (static_path)
00887 g_free(static_path);
00888
00889 static_path = g_strdup_printf("%s/static", gamepath);
00890 add_system_path("<STATIC>", static_path);
00891 char *patch_path = patchpath ? g_strdup(patchpath) :
00892 g_strdup_printf("%s/patch", gamepath);
00893 add_system_path("<PATCH>", patch_path);
00894 if (!U7exists(patch_path))
00895 U7mkdir(patch_path, 0755);
00896 g_free(patch_path);
00897
00898 U7FileManager::get_ptr()->reset();
00899 delete palbuf;
00900 string palname("<PATCH>/");
00901 palname += "palettes.flx";
00902 size_t len;
00903 if (!U7exists(palname.c_str()))
00904 (palname = "<STATIC>/") += "palettes.flx";
00905 if (!U7exists(palname.c_str()))
00906 {
00907 palbuf = new unsigned char[3*256];
00908 memset(palbuf, (63<<16)|(63<<8)|63, 3*256);
00909 }
00910 else
00911 {
00912 U7object pal(palname.c_str(), 0);
00913
00914 palbuf = (unsigned char *) pal.retrieve(len);
00915 }
00916
00917 palbuf[3*255] = (background_color>>18)&0x3f;
00918 palbuf[3*255 + 1] = (background_color>>10)&0x3f;
00919 palbuf[3*255 + 2] = (background_color>>2)&0x3f;
00920
00921 int num_names = names.size();
00922 for (int i = 0; i < num_names; i++)
00923 delete names[i];
00924 names.resize(0);
00925 delete files;
00926 browser = 0;
00927 files = new Shape_file_set();
00928 vgafile = open_shape_file("shapes.vga");
00929 facefile = open_shape_file("faces.vga");
00930
00931 string txtname("<PATCH>/text.flx");
00932 if (!U7exists(txtname.c_str()))
00933 txtname = "<STATIC>/text.flx";
00934 if (U7exists(txtname.c_str()))
00935 {
00936 Flex *items = new Flex(txtname.c_str());
00937 int num_names = items->number_of_objects();
00938 names.resize(num_names);
00939 int i;
00940 for (i = 0; i < num_names; i++)
00941 names[i] = items->retrieve(i, len);
00942 delete items;
00943 }
00944 setup_file_list();
00945 set_browser("", 0);
00946 connect_to_server();
00947 }
00948
00949 void add_to_tree(GtkTreeStore *model, const char *folderName, const char *files, ExultFileTypes file_type)
00950 {
00951 struct dirent *entry;
00952 GtkTreeIter iter;
00953
00954
00955 gtk_tree_store_append(model, &iter, NULL);
00956 gtk_tree_store_set(model, &iter,
00957 FOLDER_COLUMN, folderName,
00958 FILE_COLUMN, NULL,
00959 DATA_COLUMN, -1,
00960 -1);
00961
00962
00963 GtkTreeIter child_iter;
00964 char *startpos = (char *)files;
00965 int adding_children = 1;
00966 do {
00967 char *pattern;
00968 char *commapos = strstr(startpos, ",");
00969 if(commapos==0) {
00970 pattern = strdup(startpos);
00971 adding_children = 0;
00972 } else {
00973 pattern = g_strndup(startpos, commapos-startpos);
00974 startpos = commapos+1;
00975 }
00976
00977 string spath("<STATIC>"), ppath("<PATCH>");
00978 spath = get_system_path(spath);
00979 ppath = get_system_path(ppath);
00980 char *ext = strstr(pattern,"*");
00981 if(!ext)
00982 ext = pattern;
00983 else
00984 ext++;
00985 DIR *dir = opendir(ppath.c_str());
00986 if (dir) {
00987 while(entry=readdir(dir)) {
00988 char *fname = entry->d_name;
00989 int flen = strlen(fname);
00990
00991 if(!strcmp(fname,".")||!strcmp(fname,"..") ||strcasecmp(fname + flen - strlen(ext), ext) != 0)
00992 continue;
00993 gtk_tree_store_append (model, &child_iter, &iter);
00994 gtk_tree_store_set (model, &child_iter,
00995 FOLDER_COLUMN, NULL,
00996 FILE_COLUMN, fname,
00997 DATA_COLUMN, file_type,
00998 -1);
00999
01000 }
01001 closedir(dir);
01002 }
01003 dir = opendir(spath.c_str());
01004 if (dir) {
01005 while(entry=readdir(dir)) {
01006 char *fname = entry->d_name;
01007 int flen = strlen(fname);
01008
01009 if(!strcmp(fname,".")||!strcmp(fname,"..")||strcasecmp(fname + flen - strlen(ext), ext) != 0)
01010 continue;
01011
01012 string fullpath(ppath);
01013 fullpath += "/";
01014 fullpath += fname;
01015 if (U7exists(fullpath))
01016 continue;
01017 gtk_tree_store_append (model, &child_iter, &iter);
01018 gtk_tree_store_set (model, &child_iter,
01019 FOLDER_COLUMN, NULL,
01020 FILE_COLUMN, fname,
01021 DATA_COLUMN, file_type,
01022 -1);
01023 }
01024 closedir(dir);
01025 }
01026
01027 free(pattern);
01028 } while (adding_children);
01029 }
01030
01031
01032
01033
01034
01035 void ExultStudio::setup_file_list() {
01036 GtkWidget *file_list = glade_xml_get_widget( app_xml, "file_list" );
01037
01038
01039 GtkTreeModel *oldmod = gtk_tree_view_get_model(
01040 GTK_TREE_VIEW(file_list));
01041 GtkTreeStore *model;
01042 if (oldmod)
01043 model = GTK_TREE_STORE(oldmod);
01044 else
01045 {
01046 model = gtk_tree_store_new(
01047 NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
01048 gtk_tree_view_set_model(GTK_TREE_VIEW(file_list),
01049 GTK_TREE_MODEL(model));
01050 g_object_unref(model);
01051 gint col_offset;
01052 GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
01053 GtkTreeViewColumn *column;
01054
01055
01056 g_object_set (renderer, "xalign", 0.0, NULL);
01057 col_offset = gtk_tree_view_insert_column_with_attributes(
01058 GTK_TREE_VIEW(file_list),
01059 -1, "Folders",
01060 renderer, "text",
01061 FOLDER_COLUMN, NULL);
01062 column = gtk_tree_view_get_column(GTK_TREE_VIEW(file_list),
01063 col_offset - 1);
01064 gtk_tree_view_column_set_clickable(
01065 GTK_TREE_VIEW_COLUMN(column), TRUE);
01066
01067 col_offset = gtk_tree_view_insert_column_with_attributes(
01068 GTK_TREE_VIEW(file_list),
01069 -1, "Files",
01070 renderer, "text",
01071 FILE_COLUMN, NULL);
01072 column = gtk_tree_view_get_column(GTK_TREE_VIEW(file_list),
01073 col_offset - 1);
01074 gtk_tree_view_column_set_clickable(
01075 GTK_TREE_VIEW_COLUMN(column), TRUE);
01076 }
01077 gtk_tree_store_clear(model);
01078 add_to_tree(model, "Shape Files", "*.vga,*.shp,combos.flx", ShapeArchive);
01079 add_to_tree(model, "Map Files", "u7chunks", ChunkArchive);
01080 add_to_tree(model, "Palette Files", "*.pal,palettes.flx", PaletteFile);
01081
01082 #if 0
01083 add_to_tree(model, "FLEX Files", "*.flx", FlexArchive);
01084 #endif
01085
01086 gtk_tree_view_expand_all(GTK_TREE_VIEW(file_list));
01087 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(file_list), TRUE);
01088 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(file_list)), GTK_SELECTION_SINGLE);
01089 }
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100 void ExultStudio::save_all
01101 (
01102 )
01103 {
01104 save_groups();
01105 if (files)
01106 {
01107 Shape_chooser::check_editing_files();
01108 files->flush();
01109 }
01110 write_shape_info();
01111 write_map();
01112 }
01113
01114
01115
01116
01117
01118 bool ExultStudio::need_to_save
01119 (
01120 )
01121 {
01122 if (groups_modified())
01123 return true;
01124 if (files && files->is_modified())
01125 return true;
01126 if (shape_info_modified || shape_names_modified)
01127 return true;
01128
01129 if (Send_data(server_socket, Exult_server::info) != -1)
01130 {
01131 unsigned char data[Exult_server::maxlength];
01132 Exult_server::Msg_type id;
01133 Exult_server::wait_for_response(server_socket, 100);
01134 int len = Exult_server::Receive_data(server_socket,
01135 id, data, sizeof(data));
01136 unsigned char *ptr = &data[0];
01137 int vers, edlift, hdlift, edmode;
01138 bool editing, grid, mod;
01139 if (id == Exult_server::info &&
01140 Game_info_in(data, len, vers, edlift, hdlift,
01141 editing, grid, mod, edmode) &&
01142 mod == true)
01143 return true;
01144 }
01145 return false;
01146 }
01147
01148
01149
01150
01151
01152 void ExultStudio::write_map
01153 (
01154 )
01155 {
01156 send_to_server(Exult_server::write_map);
01157 }
01158
01159
01160
01161
01162
01163 void ExultStudio::read_map
01164 (
01165 )
01166 {
01167 send_to_server(Exult_server::read_map);
01168 }
01169
01170
01171
01172
01173
01174 void ExultStudio::write_shape_info
01175 (
01176 bool force
01177 )
01178 {
01179 if ((force || shape_info_modified) && vgafile)
01180 {
01181 Shapes_vga_file *svga =
01182 (Shapes_vga_file *) vgafile->get_ifile();
01183
01184 svga->read_info(false, true);
01185 svga->write_info(false);
01186 }
01187 shape_info_modified = false;
01188 if (force || shape_names_modified)
01189 {
01190 shape_names_modified = false;
01191 int cnt = names.size();
01192 std::ofstream out;
01193 U7open(out, "<PATCH>/text.flx");
01194 Flex_writer writer(out, "Text created by ExultStudio", cnt);
01195 for (int i = 0; i < cnt; i++)
01196 {
01197 char *str = names[i];
01198 if (str)
01199 out << str;
01200 out.put((char) 0);
01201 writer.mark_section_done();
01202 }
01203 if (!writer.close())
01204 EStudio::Alert("Error writing 'text.flx'");
01205 }
01206 }
01207
01208
01209
01210
01211
01212 void ExultStudio::reload_usecode
01213 (
01214 )
01215 {
01216 send_to_server(Exult_server::reload_usecode);
01217 }
01218
01219
01220
01221
01222
01223 void ExultStudio::set_play
01224 (
01225 gboolean play
01226 )
01227 {
01228 unsigned char data[Exult_server::maxlength];
01229 unsigned char *ptr = &data[0];
01230 Write2(ptr, play ? 0 : 1);
01231 send_to_server(Exult_server::map_editing_mode, data, ptr - data);
01232 }
01233
01234
01235
01236
01237
01238 void ExultStudio::set_tile_grid
01239 (
01240 gboolean grid
01241 )
01242 {
01243 unsigned char data[Exult_server::maxlength];
01244 unsigned char *ptr = &data[0];
01245 Write2(ptr, grid ? 1 : 0);
01246 send_to_server(Exult_server::tile_grid, data, ptr - data);
01247 }
01248
01249
01250
01251
01252
01253 void ExultStudio::set_edit_lift
01254 (
01255 int lift
01256 )
01257 {
01258 unsigned char data[Exult_server::maxlength];
01259 unsigned char *ptr = &data[0];
01260 Write2(ptr, lift);
01261 send_to_server(Exult_server::edit_lift, data, ptr - data);
01262 }
01263
01264
01265
01266
01267
01268 void ExultStudio::set_hide_lift
01269 (
01270 int lift
01271 )
01272 {
01273 unsigned char data[Exult_server::maxlength];
01274 unsigned char *ptr = &data[0];
01275 Write2(ptr, lift);
01276 send_to_server(Exult_server::hide_lift, data, ptr - data);
01277 }
01278
01279
01280
01281
01282
01283 void ExultStudio::set_edit_terrain
01284 (
01285 gboolean terrain
01286 )
01287 {
01288 unsigned char data[Exult_server::maxlength];
01289 unsigned char *ptr = &data[0];
01290 Write2(ptr, terrain ? 1 : 0);
01291
01292 send_to_server(Exult_server::terrain_editing_mode, data, ptr - data);
01293 if (!terrain)
01294 {
01295 if (browser)
01296 browser->end_terrain_editing();
01297
01298 set_spin("hide_lift_spin", 16, true);
01299 }
01300 else
01301 set_sensitive("hide_lift_spin", false);
01302
01303 GtkWidget *mitem = glade_xml_get_widget(app_xml,
01304 terrain ? "paint1" : "move1");
01305 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem), TRUE);
01306 }
01307
01308 void ExultStudio::set_edit_mode
01309 (
01310 int md
01311 )
01312 {
01313 unsigned char data[Exult_server::maxlength];
01314 unsigned char *ptr = &data[0];
01315 Write2(ptr, md);
01316
01317 send_to_server(Exult_server::set_edit_mode, data, ptr - data);
01318 }
01319
01320
01321
01322
01323
01324 static void Insert_text
01325 (
01326 GtkEditable *ed,
01327 const char *text,
01328 int& pos
01329 )
01330 {
01331 gtk_editable_insert_text(ed, text, strlen(text), &pos);
01332 }
01333
01334
01335
01336
01337
01338 void ExultStudio::show_unused_shapes
01339 (
01340 unsigned char *data,
01341 int datalen
01342 )
01343 {
01344 int nshapes = datalen*8;
01345 GtkTextView *text = GTK_TEXT_VIEW(glade_xml_get_widget(app_xml, "msg_text"));
01346 GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
01347 gtk_text_buffer_set_text(buffer, "", 0);
01348 set_visible("msg_win", TRUE);
01349 int pos = 0;
01350 GtkEditable *ed = GTK_EDITABLE(text);
01351 Insert_text(ed,
01352 "The following shapes were not found.\n", pos);
01353 Insert_text(ed,
01354 "Note that some may be created by usecode (script)\n\n", pos);
01355 for (int i = 0x96; i < nshapes; i++)
01356 if (!(data[i/8]&(1<<(i%8))))
01357 {
01358 const char *nm = get_shape_name(i);
01359 char *msg = g_strdup_printf(" Shape %4d: %s\n",
01360 i, nm ? nm : "");
01361 Insert_text(ed, msg, pos);
01362 g_free(msg);
01363 }
01364
01365 }
01366
01367
01368
01369
01370
01371
01372
01373
01374 Shape_file_info *ExultStudio::open_shape_file
01375 (
01376 const char *basename
01377 )
01378 {
01379 Shape_file_info *info = files->create(basename);
01380 if (!info)
01381 EStudio::Alert("'%s' not found in static or patch directories",
01382 basename);
01383 return info;
01384 }
01385
01386
01387
01388
01389
01390 void ExultStudio::new_shape_file
01391 (
01392 bool single
01393 )
01394 {
01395 GtkFileSelection *fsel = Create_file_selection(
01396 single ? "Write new .shp file" : "Write new .vga file",
01397 (File_sel_okay_fun) create_shape_file,
01398 (gpointer) single);
01399
01400
01401 if (is_system_path_defined("<PATCH>"))
01402 {
01403 string patch = get_system_path("<PATCH>/");
01404 gtk_file_selection_set_filename(fsel, patch.c_str());
01405 }
01406 gtk_widget_show(GTK_WIDGET(fsel));
01407 }
01408
01409
01410
01411
01412
01413 void ExultStudio::create_shape_file
01414 (
01415 char *pathname,
01416 gpointer udata
01417 )
01418 {
01419 bool oneshape = (bool) udata;
01420 Shape *shape = 0;
01421 if (oneshape)
01422 {
01423 const int w = 8, h = 8;
01424 unsigned char pixels[w*h];
01425 memset(&pixels[0], 1, w*h);
01426 shape = new Shape(new Shape_frame(&pixels[0],
01427 w, h, w - 1, h - 1, true));
01428 }
01429 try {
01430 if (oneshape)
01431 Image_file_info::write_file(pathname, &shape, 1, true);
01432 else
01433 Image_file_info::write_file(pathname, 0, 0, false);
01434 }
01435 catch (const exult_exception& e) {
01436 EStudio::Alert(e.what());
01437 }
01438 ExultStudio *studio = ExultStudio::get_instance();
01439 studio->setup_file_list();
01440 }
01441
01442
01443
01444
01445
01446 bool ExultStudio::get_toggle
01447 (
01448 char *name
01449 )
01450 {
01451 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01452 return btn ? gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn)) : -1;
01453 }
01454
01455
01456
01457
01458
01459 void ExultStudio::set_toggle
01460 (
01461 char *name,
01462 bool val
01463 )
01464 {
01465 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01466 if (btn)
01467 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn), val);
01468 }
01469
01470
01471
01472
01473
01474 unsigned char ExultStudio::get_bit_toggles
01475 (
01476 char **names,
01477 int num
01478 )
01479 {
01480 unsigned char bits = 0;
01481 for (int i = 0; i < num; i++)
01482 bits |= (get_toggle(names[i]) ? 1 : 0) << i;
01483 return bits;
01484 }
01485
01486
01487
01488
01489
01490
01491 void ExultStudio::set_bit_toggles
01492 (
01493 char **names,
01494 int num,
01495 unsigned char bits
01496 )
01497 {
01498 for (int i = 0; i < num; i++)
01499 set_toggle(names[i], (bits&(1<<i)) != 0);
01500 }
01501
01502
01503
01504
01505
01506 int ExultStudio::get_optmenu
01507 (
01508 char *name
01509 )
01510 {
01511 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01512 if (!btn)
01513 return -1;
01514 GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(btn));
01515 GtkWidget *active = gtk_menu_get_active(GTK_MENU(menu));
01516 return g_list_index(GTK_MENU_SHELL(menu)->children, active);
01517 }
01518
01519
01520
01521
01522
01523 void ExultStudio::set_optmenu
01524 (
01525 char *name,
01526 int val
01527 )
01528 {
01529 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01530 if (btn)
01531 gtk_option_menu_set_history(GTK_OPTION_MENU(btn), val);
01532 }
01533
01534
01535
01536
01537
01538 int ExultStudio::get_spin
01539 (
01540 char *name
01541 )
01542 {
01543 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01544 return btn ? gtk_spin_button_get_value_as_int(
01545 GTK_SPIN_BUTTON(btn)) : -1;
01546 }
01547
01548
01549
01550
01551
01552 void ExultStudio::set_spin
01553 (
01554 char *name,
01555 int val,
01556 bool sensitive
01557 )
01558 {
01559 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01560 if (btn)
01561 {
01562 gtk_spin_button_set_value(GTK_SPIN_BUTTON(btn), val);
01563 gtk_widget_set_sensitive(btn, sensitive);
01564 }
01565 }
01566
01567
01568
01569
01570
01571 void ExultStudio::set_spin
01572 (
01573 char *name,
01574 int val,
01575 int low, int high
01576 )
01577 {
01578 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01579 if (btn)
01580 {
01581 gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(btn),
01582 GTK_ADJUSTMENT(
01583 gtk_adjustment_new (0, low, high, 1, 10, 10)));
01584 gtk_spin_button_set_value(GTK_SPIN_BUTTON(btn), val);
01585 }
01586 }
01587
01588
01589
01590
01591
01592
01593
01594 int ExultStudio::get_num_entry
01595 (
01596 char *name
01597 )
01598 {
01599 GtkWidget *field = glade_xml_get_widget(app_xml, name);
01600 if (!field)
01601 return -1;
01602 const gchar *txt = gtk_entry_get_text(GTK_ENTRY(field));
01603 if (!txt)
01604 return -1;
01605 while (*txt == ' ')
01606 txt++;
01607 if (txt[0] == '0' && txt[1] == 'x')
01608 return (int) strtoul(txt + 2, 0, 16);
01609 else
01610 return atoi(txt);
01611 }
01612
01613
01614
01615
01616
01617
01618
01619 const gchar *ExultStudio::get_text_entry
01620 (
01621 char *name
01622 )
01623 {
01624 GtkWidget *field = glade_xml_get_widget(app_xml, name);
01625 if (!field)
01626 return 0;
01627 return gtk_entry_get_text(GTK_ENTRY(field));
01628 }
01629
01630
01631
01632
01633
01634 void ExultStudio::set_entry
01635 (
01636 char *name,
01637 int val,
01638 bool hex,
01639 bool sensitive
01640 )
01641 {
01642 GtkWidget *field = glade_xml_get_widget(app_xml, name);
01643 if (field)
01644 {
01645 char *txt = hex ? g_strdup_printf("0x%x", val)
01646 : g_strdup_printf("%d", val);
01647 gtk_entry_set_text(GTK_ENTRY(field), txt);
01648 g_free(txt);
01649 gtk_widget_set_sensitive(field, sensitive);
01650 }
01651 }
01652
01653
01654
01655
01656
01657 void ExultStudio::set_entry
01658 (
01659 char *name,
01660 const char *val,
01661 bool sensitive
01662 )
01663 {
01664 GtkWidget *field = glade_xml_get_widget(app_xml, name);
01665 if (field)
01666 {
01667 gtk_entry_set_text(GTK_ENTRY(field), val);
01668 gtk_widget_set_sensitive(field, sensitive);
01669 }
01670 }
01671
01672
01673
01674
01675
01676
01677 guint ExultStudio::set_statusbar
01678 (
01679 char *name,
01680 int context,
01681 char *msg
01682 )
01683 {
01684 GtkWidget *sbar = glade_xml_get_widget(app_xml, name);
01685 if (sbar)
01686 return gtk_statusbar_push(GTK_STATUSBAR(sbar), context, msg);
01687 else
01688 return 0;
01689 }
01690
01691
01692
01693
01694
01695 void ExultStudio::remove_statusbar
01696 (
01697 char *name,
01698 int context,
01699 guint msgid
01700 )
01701 {
01702 if (msgid == 0)
01703 return;
01704 GtkWidget *sbar = glade_xml_get_widget(app_xml, name);
01705 if (sbar)
01706 return gtk_statusbar_remove(GTK_STATUSBAR(sbar),context,msgid);
01707 }
01708
01709
01710
01711
01712
01713 void ExultStudio::set_button
01714 (
01715 char *name,
01716 const char *text
01717 )
01718 {
01719 GtkWidget *btn = glade_xml_get_widget(app_xml, name);
01720 GtkLabel *label = GTK_LABEL(GTK_BIN(btn)->child);
01721 gtk_label_set_text(label, text);
01722 }
01723
01724
01725
01726
01727
01728 void ExultStudio::set_visible
01729 (
01730 char *name,
01731 bool vis
01732 )
01733 {
01734 GtkWidget *widg = glade_xml_get_widget(app_xml, name);
01735 if (widg)
01736 {
01737 if (vis)
01738 gtk_widget_show(widg);
01739 else
01740 gtk_widget_hide(widg);
01741 }
01742 }
01743
01744
01745
01746
01747
01748 void ExultStudio::set_sensitive
01749 (
01750 char *name,
01751 bool tf
01752 )
01753 {
01754 GtkWidget *widg = glade_xml_get_widget(app_xml, name);
01755 if (widg)
01756 gtk_widget_set_sensitive(widg, tf);
01757 }
01758
01759
01760
01761
01762 static int prompt_choice = 0;
01763
01764 C_EXPORT void
01765 on_prompt3_yes_clicked (GtkToggleButton *button,
01766 gpointer user_data)
01767 {
01768 prompt_choice = 0;
01769 }
01770 C_EXPORT void
01771 on_prompt3_no_clicked (GtkToggleButton *button,
01772 gpointer user_data)
01773 {
01774 prompt_choice = 1;
01775 }
01776 C_EXPORT void
01777 on_prompt3_cancel_clicked (GtkToggleButton *button,
01778 gpointer user_data)
01779 {
01780 prompt_choice = 2;
01781 }
01782
01783
01784
01785
01786
01787
01788
01789
01790 int ExultStudio::prompt
01791 (
01792 const char *msg,
01793 const char *choice0,
01794 const char *choice1,
01795 const char *choice2
01796 )
01797 {
01798 static GdkPixmap *logo_pixmap = NULL;
01799 static GdkBitmap *logo_mask = NULL;
01800 if (!logo_pixmap)
01801 {
01802 logo_pixmap = gdk_pixmap_create_from_xpm_d(app->window,
01803 &logo_mask, NULL, logo_xpm);
01804 GtkWidget *pix = gtk_pixmap_new(logo_pixmap, logo_mask);
01805 gtk_widget_show(pix);
01806 GtkWidget *hbox = glade_xml_get_widget(app_xml,
01807 "prompt3_hbox");
01808 gtk_box_pack_start(GTK_BOX(hbox), pix, FALSE, FALSE, 12);
01809
01810 gtk_box_reorder_child(GTK_BOX(hbox), pix, 0);
01811 }
01812 GtkWidget *dlg = glade_xml_get_widget(app_xml, "prompt3_dialog");
01813 gtk_label_set_text(
01814 GTK_LABEL(glade_xml_get_widget(app_xml, "prompt3_label")),
01815 msg);
01816 set_button("prompt3_yes", choice0);
01817 if (choice1)
01818 {
01819 set_button("prompt3_no", choice1);
01820 set_visible("prompt3_no", true);
01821 }
01822 else
01823 set_visible("prompt3_no", false);
01824 if (choice2)
01825 {
01826 set_button("prompt3_cancel", choice2);
01827 set_visible("prompt3_cancel", true);
01828 }
01829 else
01830 set_visible("prompt3_cancel", false);
01831 prompt_choice = -1;
01832 gtk_window_set_modal(GTK_WINDOW(dlg), true);
01833 gtk_widget_show(dlg);
01834 while (prompt_choice == -1)
01835 gtk_main_iteration();
01836 gtk_widget_hide(dlg);
01837 assert(prompt_choice >= 0 && prompt_choice <= 2);
01838 return prompt_choice;
01839 }
01840
01841 namespace EStudio {
01842
01843
01844
01845
01846 int Prompt
01847 (
01848 const char *msg,
01849 const char *choice0,
01850 const char *choice1,
01851 const char *choice2
01852 )
01853 {
01854 return ExultStudio::get_instance()->prompt(msg, choice0, choice1,
01855 choice2);
01856 }
01857
01858
01859
01860
01861 void Alert
01862 (
01863 const char *msg,
01864 ...
01865 )
01866 {
01867 std::va_list args;
01868 va_start(args, msg);
01869 char *fullmsg = g_strdup_vprintf(msg, args);
01870 Prompt(fullmsg, "Okay");
01871 g_free(fullmsg);
01872 }
01873
01874
01875
01876
01877
01878
01879
01880 GtkWidget *Add_menu_item
01881 (
01882 GtkWidget *menu,
01883 const char *label,
01884 GtkSignalFunc func,
01885 gpointer func_data
01886 )
01887 {
01888 GtkWidget *mitem = label ? gtk_menu_item_new_with_label(label) :
01889 gtk_menu_item_new();
01890 gtk_widget_show(mitem);
01891 gtk_menu_append(GTK_MENU(menu), mitem);
01892 if (!label)
01893 gtk_widget_set_sensitive(mitem, FALSE);
01894 if (func)
01895 gtk_signal_connect(GTK_OBJECT(mitem), "activate",
01896 GTK_SIGNAL_FUNC(func), func_data);
01897 return mitem;
01898 }
01899
01900
01901
01902
01903
01904 GtkWidget *Create_arrow_button
01905 (
01906 GtkArrowType dir,
01907 GtkSignalFunc clicked,
01908 gpointer func_data
01909 )
01910 {
01911 GtkWidget *btn = gtk_button_new();
01912 gtk_widget_show(btn);
01913 GTK_WIDGET_SET_FLAGS(btn, GTK_CAN_DEFAULT);
01914 GtkWidget *arrow = gtk_arrow_new(dir, GTK_SHADOW_OUT);
01915 gtk_widget_show(arrow);
01916 gtk_container_add(GTK_CONTAINER(btn), arrow);
01917 gtk_signal_connect(GTK_OBJECT(btn), "clicked", clicked, func_data);
01918 return btn;
01919 }
01920
01921 }
01922
01923
01924
01925
01926
01927 C_EXPORT void
01928 on_prefs_cancel_clicked (GtkButton *button,
01929 gpointer user_data)
01930 {
01931 gtk_widget_hide(gtk_widget_get_toplevel(GTK_WIDGET(button)));
01932 }
01933 C_EXPORT void
01934 on_prefs_apply_clicked (GtkButton *button,
01935 gpointer user_data)
01936 {
01937 ExultStudio::get_instance()->save_preferences();
01938 }
01939 C_EXPORT void
01940 on_prefs_okay_clicked (GtkButton *button,
01941 gpointer user_data)
01942 {
01943 ExultStudio::get_instance()->save_preferences();
01944 gtk_widget_hide(gtk_widget_get_toplevel(GTK_WIDGET(button)));
01945 }
01946
01947
01948
01949
01950
01951 void ExultStudio::background_color_okay
01952 (
01953 GtkWidget *dlg,
01954 gpointer data
01955 )
01956 {
01957 GtkColorSelectionDialog *colorsel = GTK_COLOR_SELECTION_DIALOG(dlg);
01958 gdouble rgb[3];
01959 gtk_color_selection_get_color(
01960 GTK_COLOR_SELECTION(colorsel->colorsel), rgb);
01961 unsigned char r = (unsigned char) (rgb[0]*256),
01962 g = (unsigned char) (rgb[1]*256),
01963 b = (unsigned char) (rgb[2]*256);
01964 ExultStudio *studio = ExultStudio::get_instance();
01965 studio->background_color = (r<<16) + (g<<8) + b;
01966
01967 GtkWidget *backgrnd = glade_xml_get_widget(studio->app_xml,
01968 "prefs_background");
01969 gtk_object_set_user_data(GTK_OBJECT(backgrnd),
01970 (gpointer) studio->background_color);
01971 GdkRectangle area = {0, 0, backgrnd->allocation.width,
01972 backgrnd->allocation.height};
01973 gtk_widget_draw(backgrnd, &area);
01974 gtk_widget_destroy(dlg);
01975 }
01976
01977 C_EXPORT void
01978 on_prefs_background_choose_clicked (GtkButton *button,
01979 gpointer user_data)
01980 {
01981 GtkColorSelectionDialog *colorsel = GTK_COLOR_SELECTION_DIALOG(
01982 gtk_color_selection_dialog_new("Background color"));
01983 gtk_window_set_modal(GTK_WINDOW(colorsel), true);
01984
01985 gtk_signal_connect_object(GTK_OBJECT(colorsel->ok_button), "clicked",
01986 GTK_SIGNAL_FUNC(ExultStudio::background_color_okay),
01987 GTK_OBJECT(colorsel));
01988 gtk_signal_connect_object(GTK_OBJECT(colorsel->cancel_button),
01989 "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy),
01990 GTK_OBJECT(colorsel));
01991
01992 gtk_signal_connect(GTK_OBJECT(colorsel), "delete_event",
01993 GTK_SIGNAL_FUNC(gtk_false), 0L);
01994
01995 guint32 c = ExultStudio::get_instance()->get_background_color();
01996 gdouble rgb[3];
01997 rgb[0] = ((double) ((c>>16)&0xff))/256;
01998 rgb[1] = ((double) ((c>>8)&0xff))/256;
01999 rgb[2] = ((double) ((c>>0)&0xff))/256;
02000 gtk_color_selection_set_color(GTK_COLOR_SELECTION(colorsel->colorsel),
02001 rgb);
02002 gtk_widget_show(GTK_WIDGET(colorsel));
02003 }
02004
02005 C_EXPORT gboolean on_prefs_background_expose_event
02006 (
02007 GtkWidget *widget,
02008 GdkEventExpose *event,
02009 gpointer data
02010 )
02011 {
02012 guint32 color = (guint32) gtk_object_get_user_data(GTK_OBJECT(widget));
02013 GdkGC *gc = (GdkGC *)
02014 gtk_object_get_data(GTK_OBJECT(widget), "color_gc");
02015 if (!gc)
02016 {
02017 gc = gdk_gc_new(widget->window);
02018 gtk_object_set_data(GTK_OBJECT(widget), "color_gc", gc);
02019 }
02020 gdk_rgb_gc_set_foreground(gc, color);
02021 gdk_draw_rectangle(widget->window, gc, TRUE, event->area.x,
02022 event->area.y, event->area.width, event->area.height);
02023 return (TRUE);
02024 }
02025
02026
02027 C_EXPORT gboolean on_prefs_window_delete_event
02028 (
02029 GtkWidget *widget,
02030 GdkEvent *event,
02031 gpointer user_data
02032 )
02033 {
02034 gtk_widget_hide(widget);
02035 return TRUE;
02036 }
02037
02038
02039
02040
02041
02042 void ExultStudio::open_preferences
02043 (
02044 )
02045 {
02046 set_entry("prefs_image_editor", image_editor ? image_editor : "");
02047 set_entry("prefs_default_game", default_game ? default_game : "");
02048 GtkWidget *backgrnd = glade_xml_get_widget(app_xml,
02049 "prefs_background");
02050 gtk_object_set_user_data(GTK_OBJECT(backgrnd),
02051 (gpointer) background_color);
02052 GtkWidget *win = glade_xml_get_widget(app_xml, "prefs_window");
02053 gtk_widget_show(win);
02054 }
02055
02056
02057
02058
02059
02060 void ExultStudio::save_preferences
02061 (
02062 )
02063 {
02064 const char *text = get_text_entry("prefs_image_editor");
02065 g_free(image_editor);
02066 image_editor = g_strdup(text);
02067 config->set("config/estudio/image_editor", image_editor, true);
02068 text = get_text_entry("prefs_default_game");
02069 g_free(default_game);
02070 default_game = g_strdup(text);
02071 config->set("config/estudio/default_game", default_game, true);
02072 GtkWidget *backgrnd = glade_xml_get_widget(app_xml,
02073 "prefs_background");
02074 background_color = (guint32) gtk_object_get_user_data(
02075 GTK_OBJECT(backgrnd));
02076 config->set("config/estudio/background_color", background_color, true);
02077
02078 palbuf[3*255] = (background_color>>18)&0x3f;
02079 palbuf[3*255 + 1] = (background_color>>10)&0x3f;
02080 palbuf[3*255 + 2] = (background_color>>2)&0x3f;
02081 if (browser)
02082 browser->set_background_color(background_color);
02083 }
02084
02085
02086
02087
02088
02089 void ExultStudio::run()
02090 {
02091 gtk_main();
02092 }
02093
02094
02095
02096
02097
02098 static gint Reconnect
02099 (
02100 gpointer data
02101 )
02102 {
02103 ExultStudio *studio = (ExultStudio *) data;
02104 if (studio->connect_to_server())
02105 return 0;
02106 else
02107 return 1;
02108 }
02109
02110
02111
02112
02113
02114
02115
02116 bool ExultStudio::send_to_server
02117 (
02118 Exult_server::Msg_type id,
02119 unsigned char *data,
02120 int datalen
02121 )
02122 {
02123 if (Send_data(server_socket, id, data, datalen) == -1)
02124 {
02125 cerr << "Error sending to server" << endl;
02126 return false;
02127 }
02128 return true;
02129 }
02130
02131
02132
02133
02134
02135 #ifndef WIN32
02136 static void Read_from_server
02137 (
02138 gpointer data,
02139 gint socket,
02140 GdkInputCondition condition
02141 )
02142 {
02143 ExultStudio *studio = (ExultStudio *) data;
02144 studio->read_from_server();
02145 }
02146 #else
02147 static gint Read_from_server
02148 (
02149 gpointer data
02150 )
02151 {
02152 ExultStudio *studio = (ExultStudio *) data;
02153 studio->read_from_server();
02154 return TRUE;
02155 }
02156 #endif
02157
02158 gint Do_Drop_Callback(gpointer data);
02159
02160 void ExultStudio::read_from_server
02161 (
02162 )
02163 {
02164 #ifdef WIN32
02165
02166 int len = Exult_server::peek_pipe();
02167
02168
02169
02170 if (len == -1) {
02171 cout << "Disconnected from server" << endl;
02172 gtk_timeout_remove(server_input_tag);
02173 Exult_server::disconnect_from_server();
02174 server_input_tag = -1;
02175 server_socket = -1;
02176
02177 gtk_timeout_add(4000, Reconnect, this);
02178
02179 return;
02180 }
02181 if (len < 1) return;
02182 #endif
02183 unsigned char data[Exult_server::maxlength];
02184 Exult_server::Msg_type id;
02185 int datalen = Exult_server::Receive_data(server_socket, id, data,
02186 sizeof(data));
02187 if (datalen < 0)
02188 {
02189 cout << "Error reading from server" << endl;
02190 if (server_socket == -1)
02191 {
02192 #ifndef WIN32
02193 gdk_input_remove(server_input_tag);
02194 #else
02195 gtk_timeout_remove(server_input_tag);
02196 Exult_server::disconnect_from_server();
02197 #endif
02198 server_input_tag = -1;
02199
02200 gtk_timeout_add(4000, Reconnect, this);
02201 }
02202 return;
02203 }
02204 cout << "Read " << datalen << " bytes from server" << endl;
02205 cout << "ID = " << (int) id << endl;
02206 switch (id)
02207 {
02208 case Exult_server::obj:
02209 open_obj_window(data, datalen);
02210 break;
02211 case Exult_server::egg:
02212 open_egg_window(data, datalen);
02213 break;
02214 case Exult_server::npc:
02215 open_npc_window(data, datalen);
02216 break;
02217 case Exult_server::user_responded:
02218 case Exult_server::cancel:
02219 case Exult_server::locate_terrain:
02220 case Exult_server::swap_terrain:
02221 case Exult_server::insert_terrain:
02222 case Exult_server::delete_terrain:
02223 case Exult_server::locate_shape:
02224 case Exult_server::game_pos:
02225 if (waiting_for_server)
02226 {
02227 waiting_for_server(id, data, datalen, waiting_client);
02228 waiting_for_server = 0;
02229 waiting_client = 0;
02230 }
02231 else if (browser)
02232 browser->server_response((int) id, data, datalen);
02233 break;
02234 case Exult_server::info:
02235 info_received(data, datalen);
02236 break;
02237 case Exult_server::view_pos:
02238 if (locwin)
02239 locwin->view_changed(data, datalen);
02240 break;
02241 case Exult_server::combo_pick:
02242 open_combo_window();
02243 if (combowin)
02244 combowin->add(data, datalen);
02245 break;
02246 case Exult_server::unused_shapes:
02247 show_unused_shapes(data, datalen);
02248 break;
02249 case Exult_server::select_status:
02250 set_edit_menu(data[0] != 0, data[1] != 0);
02251 break;
02252 case Exult_server::usecode_debugging:
02253 std::cerr << "Warning: got a usecode debugging message! (ignored)"
02254 << std::endl;
02255 break;
02256 }
02257 }
02258
02259
02260
02261
02262
02263
02264 bool ExultStudio::connect_to_server
02265 (
02266 )
02267 {
02268 if (!static_path)
02269 return false;
02270 #ifndef WIN32
02271 if (server_socket >= 0)
02272 {
02273 close(server_socket);
02274 gdk_input_remove(server_input_tag);
02275 }
02276 server_socket = server_input_tag = -1;
02277 struct sockaddr_un addr;
02278 addr.sun_family = AF_UNIX;
02279
02280 char *home = getenv("HOME");
02281 addr.sun_path[0] = 0;
02282 if (home)
02283 {
02284 strcpy(addr.sun_path, home);
02285 strcat(addr.sun_path, "/.exult/exultserver");
02286 if (!U7exists(addr.sun_path))
02287 addr.sun_path[0] = 0;
02288 }
02289 if (!addr.sun_path[0])
02290 {
02291 strcpy(addr.sun_path, static_path);
02292 char *pstatic = strrchr(addr.sun_path, '/');
02293 if (pstatic && !pstatic[1])
02294 {
02295 pstatic[0] = 0;
02296 pstatic = strrchr(addr.sun_path, '/');
02297 }
02298 if (!pstatic)
02299 {
02300 cout << "Can't find gamedat for socket" << endl;
02301 return false;
02302 }
02303 strcpy(pstatic + 1, "gamedat/exultserver");
02304 }
02305 server_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
02306 if (server_socket < 0)
02307 {
02308 perror("Failed to open map-editor socket");
02309 return false;
02310 }
02311
02312
02313
02314 cout << "Trying to connect to server at '" << addr.sun_path << "'"
02315 << endl;
02316 if (connect(server_socket, (struct sockaddr *) &addr,
02317 sizeof(addr.sun_family) + strlen(addr.sun_path)) == -1)
02318 {
02319 perror("Socket connect");
02320 close(server_socket);
02321 server_socket = -1;
02322 return false;
02323 }
02324 server_input_tag = gdk_input_add(server_socket,
02325 GDK_INPUT_READ, Read_from_server, this);
02326 #else
02327
02328 if (server_socket != -1) Exult_server::disconnect_from_server();
02329 if (server_input_tag != -1) gtk_timeout_remove(server_input_tag);
02330 server_socket = server_input_tag = -1;
02331
02332 if (Exult_server::try_connect_to_server(static_path) > 0)
02333 server_input_tag = gtk_timeout_add(50, Read_from_server, this);
02334 else
02335 return false;
02336 #endif
02337 cout << "Connected to server" << endl;
02338 send_to_server(Exult_server::info);
02339 set_edit_menu(false, false);
02340 return true;
02341 }
02342
02343
02344
02345
02346 void ExultStudio::info_received
02347 (
02348 unsigned char *data,
02349 int len
02350 )
02351 {
02352 int vers, edlift, hdlift, edmode;
02353 bool editing, grid, mod;
02354 Game_info_in(data, len, vers, edlift, hdlift,
02355 editing, grid, mod, edmode);
02356 if (vers != Exult_server::version)
02357 {
02358 EStudio::Alert("Expected ExultServer version %d, but got %d",
02359 Exult_server::version, vers);
02360 #ifndef WIN32
02361 close(server_socket);
02362 gdk_input_remove(server_input_tag);
02363 #else
02364 Exult_server::disconnect_from_server();
02365 gtk_timeout_remove(server_input_tag);
02366 #endif
02367 server_socket = server_input_tag = -1;
02368 return;
02369 }
02370
02371 set_spin("edit_lift_spin", edlift);
02372 set_spin("hide_lift_spin", hdlift);
02373 set_toggle("play_button", !editing);
02374 set_toggle("tile_grid_button", grid);
02375 if (edmode >= 0 && edmode < sizeof(mode_names)/sizeof(mode_names[0]))
02376 {
02377 GtkWidget *mitem = glade_xml_get_widget(app_xml,
02378 mode_names[edmode]);
02379
02380 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mitem),
02381 TRUE);
02382 }
02383 }
02384
02385
02386
02387
02388
02389
02390 void ExultStudio::set_edit_menu
02391 (
02392 bool sel,
02393 bool clip
02394 )
02395 {
02396 set_sensitive("cut1", sel);
02397 set_sensitive("copy1", sel);
02398 set_sensitive("paste1", clip);
02399 set_sensitive("properties1", sel);
02400 set_sensitive("basic_properties1", sel);
02401 }
02402