00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029 #include <cassert>
00030 #include <fstream>
00031 #include <gdk/gdkkeysyms.h>
00032 #include "shapegroup.h"
00033 #include "Flex.h"
00034 #include "utils.h"
00035 #include "exceptions.h"
00036 #include "studio.h"
00037 #include "objbrowse.h"
00038 #include "shapefile.h"
00039
00040 using std::vector;
00041 using std::ios;
00042 using std::string;
00043 using std::cout;
00044 using std::endl;
00045 using EStudio::Alert;
00046
00047
00048
00049
00050
00051 Shape_group::Shape_group
00052 (
00053 const char *nm,
00054 Shape_group_file *f
00055 ) : name(nm), file(f)
00056 {
00057 }
00058
00059
00060
00061
00062
00063 void Shape_group::del
00064 (
00065 int i
00066 )
00067 {
00068 assert(i >= 0 && i < size());
00069 std::vector<int>::erase(begin() + i);
00070 file->modified = true;
00071 }
00072
00073
00074
00075
00076
00077 void Shape_group::swap
00078 (
00079 int i
00080 )
00081 {
00082 int x0 = (*this)[i];
00083 (*this)[i] = (*this)[i + 1];
00084 (*this)[i + 1] = x0;
00085 file->modified = true;
00086 }
00087
00088
00089
00090
00091
00092 void Shape_group::add
00093 (
00094 int id
00095 )
00096 {
00097 for (vector<int>::const_iterator it = begin(); it != end(); ++it)
00098 if ((*it) == id)
00099 return;
00100 push_back(id);
00101 file->modified = true;
00102 }
00103
00104
00105
00106
00107
00108 Shape_group_file::Shape_group_file
00109 (
00110 const char *nm
00111 ) : name(nm), modified(false)
00112 {
00113 Flex *flex = 0;
00114 std::string patchname = "<PATCH>/" + name;
00115 std::string staticname = "<STATIC>/" + name;
00116 if (U7exists(patchname))
00117 flex = new Flex(patchname);
00118 else if (U7exists(staticname))
00119 flex = new Flex(staticname);
00120 if (flex)
00121 {
00122 int cnt = flex->number_of_objects();
00123 for (int i = 0; i < cnt; i++)
00124 {
00125 std::size_t len;
00126 char *buf = flex->retrieve(i, len);
00127 char *gname = buf;
00128 unsigned char *ptr = (unsigned char *)
00129 gname + strlen(gname) + 1;
00130 int sz = Read2(ptr);
00131 assert ((len - ((char *) ptr - buf))/2 == sz);
00132 Shape_group *grp = new Shape_group(gname, this);
00133 grp->reserve(sz);
00134 for (int j = 0; j < sz; j++)
00135 grp->push_back(Read2(ptr));
00136 groups.push_back(grp);
00137 delete buf;
00138 }
00139 delete flex;
00140 }
00141 }
00142
00143
00144
00145
00146
00147
00148
00149 int Shape_group_file::find
00150 (
00151 const char *nm
00152 )
00153 {
00154 for (vector<Shape_group *>::const_iterator it = groups.begin();
00155 it != groups.end(); ++it)
00156 if ((*it)->name == nm)
00157 return (it - groups.begin());
00158 return -1;
00159 }
00160
00161
00162
00163
00164
00165 Shape_group_file::~Shape_group_file
00166 (
00167 )
00168 {
00169 for (vector<Shape_group *>::iterator it = groups.begin();
00170 it != groups.end(); ++it)
00171 delete (*it);
00172 }
00173
00174
00175
00176
00177
00178 void Shape_group_file::remove
00179 (
00180 int index,
00181 bool del
00182 )
00183 {
00184 modified = true;
00185 assert(index >= 0 && index < groups.size());
00186 Shape_group *grp = groups[index];
00187 groups.erase(groups.begin() + index);
00188 if (del)
00189 delete grp;
00190 }
00191
00192
00193
00194
00195
00196 void Shape_group_file::write
00197 (
00198 )
00199 {
00200 std::ofstream out;
00201 std::string patchname = "<PATCH>/" + name;
00202 U7open(out, patchname.c_str());
00203 int cnt = groups.size();
00204 Flex_writer gfile(out, "ExultStudio shape groups", cnt);
00205 int i;
00206 for (i = 0; i < cnt; i++)
00207 {
00208 Shape_group *grp = groups[i];
00209 const char *nm = grp->get_name();
00210 int sz = grp->size();
00211
00212 long len = strlen(nm) + 1 + 2 + 2*sz;
00213 unsigned char *buf = new unsigned char[len];
00214 strcpy((char *) buf, nm);
00215 unsigned char *ptr = buf + strlen(nm) + 1;
00216 Write2(ptr, sz);
00217 for (vector<int>::iterator it = grp->begin();
00218 it != grp->end(); it++)
00219 Write2(ptr, *it);
00220 assert(ptr - buf == len);
00221
00222 out.write(reinterpret_cast<char *>(buf), len);
00223 delete buf;
00224 gfile.mark_section_done();
00225 }
00226 if (!gfile.close())
00227 Alert("Error writing '%s'", patchname.c_str());
00228 modified = false;
00229 }
00230
00231
00232
00233
00234
00235
00236 static int Get_tree_row
00237 (
00238 GtkTreePath *path
00239 )
00240 {
00241 gchar *str = gtk_tree_path_to_string(path);
00242 int row = atoi(str);
00243 g_free(str);
00244 return row;
00245 }
00246 static int Get_tree_row
00247 (
00248 GtkTreeModel *model,
00249 GtkTreeIter *iter
00250 )
00251 {
00252 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
00253 int row = Get_tree_row(path);
00254 gtk_tree_path_free(path);
00255 return row;
00256 }
00257
00258
00259
00260
00261 C_EXPORT void
00262 on_groups_add_clicked (GtkToggleButton *button,
00263 gpointer user_data)
00264 {
00265 ExultStudio::get_instance()->add_group();
00266 }
00267
00268 C_EXPORT void
00269 on_groups_del_clicked (GtkToggleButton *button,
00270 gpointer user_data)
00271 {
00272 ExultStudio::get_instance()->del_group();
00273 }
00274
00275 C_EXPORT gboolean
00276 on_groups_new_name_key_press (GtkEntry *entry,
00277 GdkEventKey *event,
00278 gpointer user_data)
00279 {
00280 if (event->keyval == GDK_Return)
00281 {
00282 ExultStudio::get_instance()->add_group();
00283 return TRUE;
00284 }
00285 return FALSE;
00286 }
00287
00288
00289
00290
00291 C_EXPORT void
00292 on_group_list_cursor_changed (GtkTreeView *tview)
00293 {
00294 ExultStudio::get_instance()->setup_group_controls();
00295 }
00296
00297 void
00298 on_group_list_row_inserted (GtkTreeModel *model,
00299 GtkTreePath *path,
00300 GtkTreeIter *iter,
00301 gpointer user_data)
00302 {
00303 ExultStudio::get_instance()->groups_changed(model, path, iter);
00304 }
00305
00306 void
00307 on_group_list_row_changed (GtkTreeModel *model,
00308 GtkTreePath *path,
00309 GtkTreeIter *iter,
00310 gpointer user_data)
00311 {
00312 ExultStudio::get_instance()->groups_changed(model, path, iter, true);
00313 }
00314
00315 void
00316 on_group_list_row_deleted (GtkTreeModel *model,
00317 GtkTreePath *path,
00318 gpointer user_data)
00319 {
00320 ExultStudio::get_instance()->groups_changed(model, path, 0);
00321 }
00322
00323 C_EXPORT void
00324 on_group_list_row_activated (GtkTreeView *treeview,
00325 GtkTreePath *path,
00326 GtkTreeViewColumn *column,
00327 gpointer user_data)
00328 {
00329 ExultStudio::get_instance()->open_group_window();
00330 }
00331
00332
00333 enum
00334 {
00335 GRP_FILE_COLUMN = 0,
00336 GRP_GROUP_COLUMN,
00337 GRP_NUM_COLUMNS
00338 };
00339
00340
00341
00342
00343
00344
00345 void ExultStudio::setup_groups
00346 (
00347 )
00348 {
00349 Shape_group_file *groups = curfile->get_groups();
00350 if (!groups)
00351 {
00352 set_visible("groups_frame", FALSE);
00353 return;
00354 }
00355 GtkTreeView *tview = GTK_TREE_VIEW(
00356 glade_xml_get_widget(app_xml, "group_list"));
00357 GtkTreeModel *oldmod = gtk_tree_view_get_model(tview);
00358 GtkTreeStore *model;
00359 gulong addsig = 0, delsig = 0, chgsig = 0;
00360 if (!oldmod)
00361 {
00362 model = gtk_tree_store_new(GRP_NUM_COLUMNS,
00363 G_TYPE_STRING, G_TYPE_POINTER);
00364 gtk_tree_view_set_model(tview, GTK_TREE_MODEL(model));
00365 g_object_unref(model);
00366
00367 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
00368 g_object_set (renderer, "xalign", 0.0, NULL);
00369 gint col_offset = gtk_tree_view_insert_column_with_attributes(
00370 tview,
00371 -1, "Names",
00372 renderer, "text",
00373 GRP_FILE_COLUMN, NULL);
00374 GtkTreeViewColumn *column = gtk_tree_view_get_column(tview,
00375 col_offset - 1);
00376 gtk_tree_view_column_set_clickable(column, TRUE);
00377 addsig = g_signal_connect(G_OBJECT(model), "row-inserted",
00378 GTK_SIGNAL_FUNC(on_group_list_row_inserted), this);
00379
00380 g_object_set_data(G_OBJECT(model), "row-inserted",
00381 (gpointer) addsig);
00382 delsig = g_signal_connect(G_OBJECT(model), "row-deleted",
00383 GTK_SIGNAL_FUNC(on_group_list_row_deleted), this);
00384 g_object_set_data(G_OBJECT(model), "row-deleted",
00385 (gpointer) delsig);
00386 chgsig = g_signal_connect(G_OBJECT(model), "row-changed",
00387 GTK_SIGNAL_FUNC(on_group_list_row_changed), this);
00388 g_object_set_data(G_OBJECT(model), "row-changed",
00389 (gpointer) delsig);
00390 }
00391 else
00392 {
00393 model = GTK_TREE_STORE(oldmod);
00394 addsig = (gulong) g_object_get_data(G_OBJECT(model),
00395 "row-inserted");
00396 delsig = (gulong) g_object_get_data(G_OBJECT(model),
00397 "row-deleted");
00398 chgsig = (gulong) g_object_get_data(G_OBJECT(model),
00399 "row-changed");
00400 }
00401
00402 g_signal_handler_block(model, addsig);
00403 g_signal_handler_block(model, delsig);
00404 g_signal_handler_block(model, chgsig);
00405 gtk_tree_store_clear(model);
00406 set_visible("groups_frame", TRUE);
00407 gtk_tree_view_set_reorderable(tview, TRUE);
00408 int cnt = groups->size();
00409 GtkTreeIter iter;
00410 for (int i = 0; i < cnt; i++)
00411 {
00412 Shape_group *grp = groups->get(i);
00413 gtk_tree_store_append(model, &iter, NULL);
00414 gtk_tree_store_set(model, &iter,
00415 GRP_FILE_COLUMN, grp->get_name(),
00416 GRP_GROUP_COLUMN, grp,
00417 -1);
00418 }
00419 gtk_tree_view_set_rules_hint(tview, TRUE);
00420 g_signal_handler_unblock(model, addsig);
00421 g_signal_handler_unblock(model, delsig);
00422 g_signal_handler_unblock(model, chgsig);
00423 setup_group_controls();
00424 }
00425
00426
00427
00428
00429
00430 void ExultStudio::setup_group_controls
00431 (
00432 )
00433 {
00434 set_visible("groups_frame", true);
00435 GtkTreeView *tview = GTK_TREE_VIEW(
00436 glade_xml_get_widget(app_xml, "group_list"));
00437 GtkTreeSelection *list = gtk_tree_view_get_selection(tview);
00438 if (list)
00439 {
00440
00441
00442 set_sensitive("groups_del", true);
00443
00444
00445 }
00446 else
00447 {
00448
00449 set_sensitive("groups_del", false);
00450
00451
00452 }
00453 }
00454
00455
00456
00457
00458
00459 void ExultStudio::add_group
00460 (
00461 )
00462 {
00463 if (!curfile)
00464 return;
00465 GtkTreeView *tview = GTK_TREE_VIEW(
00466 glade_xml_get_widget(app_xml, "group_list"));
00467 GtkTreeStore *model = GTK_TREE_STORE(gtk_tree_view_get_model(tview));
00468 const char *nm = get_text_entry("groups_new_name");
00469 Shape_group_file *groups = curfile->get_groups();
00470
00471 if (nm && *nm && groups->find(nm) < 0)
00472 {
00473 Shape_group *grp = new Shape_group(nm, groups);
00474 GtkTreeIter iter;
00475 gtk_tree_store_append(model, &iter, NULL);
00476 gtk_tree_store_set(model, &iter,
00477 GRP_FILE_COLUMN, nm,
00478 GRP_GROUP_COLUMN, grp,
00479 -1);
00480 }
00481 set_entry("groups_new_name", "");
00482 }
00483
00484 void ExultStudio::del_group
00485 (
00486 )
00487 {
00488 if (!curfile)
00489 return;
00490 GtkTreeView *tview = GTK_TREE_VIEW(
00491 glade_xml_get_widget(app_xml, "group_list"));
00492 GtkTreeSelection *list = gtk_tree_view_get_selection(tview);
00493 if (!list)
00494 return;
00495 GtkTreeModel *model;
00496 GtkTreeIter iter;
00497 if (!gtk_tree_selection_get_selected(list, &model, &iter))
00498 return;
00499 int row = Get_tree_row(model, &iter);
00500 Shape_group_file *groups = curfile->get_groups();
00501 Shape_group *grp = groups->get(row);
00502 string msg("Delete group '");
00503 msg += grp->get_name();
00504 msg += "'?";
00505 int choice = prompt(msg.c_str(), "Yes", "No");
00506 if (choice != 0)
00507 return;
00508 delete groups->get(row);
00509 gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
00510
00511 vector<GtkWindow*> toclose;
00512 vector<GtkWindow*>::const_iterator it;
00513 for (it = group_windows.begin(); it != group_windows.end(); ++it)
00514 {
00515 Object_browser *chooser = (Object_browser *)
00516 gtk_object_get_data(GTK_OBJECT(*it), "browser");
00517 if (chooser->get_group() == grp)
00518
00519 toclose.push_back(*it);
00520 }
00521 for (it = toclose.begin(); it != toclose.end(); ++it)
00522 close_group_window(GTK_WIDGET(*it));
00523 }
00524
00525
00526
00527
00528
00529 void ExultStudio::groups_changed
00530 (
00531 GtkTreeModel *model,
00532 GtkTreePath *path,
00533 GtkTreeIter *loc,
00534 bool value
00535 )
00536 {
00537 if (!curfile)
00538 return;
00539 Shape_group_file *groups = curfile->get_groups();
00540 int row = Get_tree_row(path);
00541 if (!loc)
00542 groups->remove(row, false);
00543 else
00544 {
00545 void *grpaddr = 0;
00546 gtk_tree_model_get(model, loc, GRP_GROUP_COLUMN, &grpaddr,
00547 -1);
00548 Shape_group *grp = (Shape_group *) grpaddr;
00549 if (value)
00550 groups->set(grp, row);
00551 else
00552 groups->insert(grp, row);
00553 }
00554 }
00555
00556
00557
00558
00559
00560
00561
00562 C_EXPORT gboolean on_group_window_delete_event
00563 (
00564 GtkWidget *widget,
00565 GdkEvent *event,
00566 gpointer user_data
00567 )
00568 {
00569 ExultStudio::get_instance()->close_group_window(widget);
00570 return TRUE;
00571 }
00572 C_EXPORT void
00573 on_group_up_clicked (GtkToggleButton *button,
00574 gpointer user_data)
00575 {
00576 Object_browser *chooser = (Object_browser *)gtk_object_get_data(
00577 GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(button))),
00578 "browser");
00579 Shape_group *grp = chooser->get_group();
00580 int i = chooser->get_selected();
00581 if (grp && i > 0)
00582 {
00583 grp->swap(i - 1);
00584 ExultStudio::get_instance()->update_group_windows(grp);
00585 }
00586 }
00587 C_EXPORT void
00588 on_group_down_clicked (GtkToggleButton *button,
00589 gpointer user_data)
00590 {
00591 Object_browser *chooser = (Object_browser *)gtk_object_get_data(
00592 GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(button))),
00593 "browser");
00594 Shape_group *grp = chooser->get_group();
00595 int i = chooser->get_selected();
00596 if (grp && i < grp->size() - 1)
00597 {
00598 grp->swap(i);
00599 ExultStudio::get_instance()->update_group_windows(grp);
00600 }
00601 }
00602 C_EXPORT void
00603 on_group_shape_remove_clicked (GtkToggleButton *button,
00604 gpointer user_data)
00605 {
00606 Object_browser *chooser = (Object_browser *)gtk_object_get_data(
00607 GTK_OBJECT(gtk_widget_get_toplevel(GTK_WIDGET(button))),
00608 "browser");
00609 Shape_group *grp = chooser->get_group();
00610 int i = chooser->get_selected();
00611 if (grp && i >= 0)
00612 {
00613 grp->del(i);
00614 ExultStudio::get_instance()->update_group_windows(grp);
00615 }
00616 }
00617
00618
00619
00620
00621
00622 void ExultStudio::open_group_window
00623 (
00624 )
00625 {
00626 GtkTreeView *tview = GTK_TREE_VIEW(
00627 glade_xml_get_widget(app_xml, "group_list"));
00628 GtkTreeSelection *list = gtk_tree_view_get_selection(tview);
00629 if (!list || !curfile || !vgafile || !palbuf)
00630 return;
00631 GtkTreeModel *model;
00632 GtkTreeIter iter;
00633 if (!gtk_tree_selection_get_selected(list, &model, &iter))
00634 return;
00635 int row = Get_tree_row(model, &iter);
00636 Shape_group_file *groups = curfile->get_groups();
00637 Shape_group *grp = groups->get(row);
00638 GladeXML *xml = glade_xml_new(glade_path, "group_window", NULL);
00639 glade_xml_signal_autoconnect(xml);
00640 GtkWidget *grpwin = glade_xml_get_widget(xml, "group_window");
00641 Object_browser *chooser = curfile->create_browser(vgafile,palbuf, grp);
00642
00643 gtk_object_set_data(GTK_OBJECT(grpwin), "xml", xml);
00644 gtk_object_set_data(GTK_OBJECT(grpwin), "browser", chooser);
00645
00646 string title("Exult Group: ");
00647 title += grp->get_name();
00648 gtk_window_set_title(GTK_WINDOW(grpwin), title.c_str());
00649 GtkWidget *field = glade_xml_get_widget(xml, "group_name");
00650 if (field)
00651 gtk_entry_set_text(GTK_ENTRY(field), grp->get_name());
00652
00653 GtkWidget *browser_box = glade_xml_get_widget(xml, "group_shapes" );
00654 gtk_widget_show(browser_box);
00655 gtk_box_pack_start(GTK_BOX(browser_box), chooser->get_widget(),
00656 TRUE, TRUE, 0);
00657
00658 gtk_signal_connect (GTK_OBJECT(grpwin), "delete_event",
00659 GTK_SIGNAL_FUNC (on_group_window_delete_event),
00660 this);
00661 group_windows.push_back(GTK_WINDOW(grpwin));
00662 gtk_widget_show(grpwin);
00663 }
00664
00665
00666
00667
00668
00669 void ExultStudio::close_group_window
00670 (
00671 GtkWidget *grpwin
00672 )
00673 {
00674
00675 for (vector<GtkWindow*>::iterator it = group_windows.begin();
00676 it != group_windows.end(); ++it)
00677 {
00678 if (*it == GTK_WINDOW(grpwin))
00679 {
00680 group_windows.erase(it);
00681 break;
00682 }
00683 }
00684 GladeXML *xml = (GladeXML *) gtk_object_get_data(GTK_OBJECT(grpwin),
00685 "xml");
00686 Object_browser *chooser = (Object_browser *) gtk_object_get_data(
00687 GTK_OBJECT(grpwin), "browser");
00688 delete chooser;
00689 gtk_widget_destroy(grpwin);
00690 g_object_unref(G_OBJECT(xml));
00691 }
00692
00693
00694
00695
00696
00697 void ExultStudio::save_groups
00698 (
00699 )
00700 {
00701 if (!files)
00702 return;
00703 int cnt = files->size();
00704 for (int i = 0; i < cnt; i++)
00705 {
00706 Shape_file_info *info = (*files)[i];
00707 Shape_group_file *gfile = info->get_groups();
00708 if (gfile && gfile->is_modified())
00709 gfile->write();
00710 }
00711 }
00712
00713
00714
00715
00716
00717 bool ExultStudio::groups_modified
00718 (
00719 )
00720 {
00721 if (!files)
00722 return false;
00723 int cnt = files->size();
00724 for (int i = 0; i < cnt; i++)
00725 {
00726 Shape_file_info *info = (*files)[i];
00727 Shape_group_file *gfile = info->get_groups();
00728 if (gfile && gfile->is_modified())
00729 return true;
00730 }
00731 return false;
00732 }
00733
00734
00735
00736
00737
00738 void ExultStudio::update_group_windows
00739 (
00740 Shape_group *grp
00741 )
00742 {
00743 for (vector<GtkWindow*>::const_iterator it = group_windows.begin();
00744 it != group_windows.end(); ++it)
00745 {
00746 Object_browser *chooser = (Object_browser *)
00747 gtk_object_get_data(GTK_OBJECT(*it), "browser");
00748 if (!grp || chooser->get_group() == grp)
00749 {
00750 chooser->render();
00751 chooser->show();
00752 }
00753 }
00754 }
00755