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 #ifdef WIN32
00030 #include "Windrag.h"
00031 #endif
00032
00033 #include <gtk/gtk.h>
00034 #ifdef XWIN
00035 #include <gdk/gdkx.h>
00036 #endif
00037 #include <glib.h>
00038 #include "chunklst.h"
00039 #include "vgafile.h"
00040 #include "ibuf8.h"
00041 #include "Flex.h"
00042 #include "u7drag.h"
00043 #include "exult_constants.h"
00044 #include "studio.h"
00045 #include "utils.h"
00046 #include "shapegroup.h"
00047
00048 #include <iosfwd>
00049
00050 using std::cout;
00051 using std::endl;
00052 using std::strlen;
00053 using EStudio::Add_menu_item;
00054 using EStudio::Create_arrow_button;
00055
00056 const int border = 2;
00057
00058
00059
00060
00061
00062
00063 void Chunk_chooser::show
00064 (
00065 int x, int y, int w, int h
00066 )
00067 {
00068 Shape_draw::show(draw->window, x, y, w, h);
00069 if (selected >= 0)
00070 {
00071 Rectangle b = info[selected].box;
00072
00073 gdk_draw_rectangle(draw->window, drawgc, FALSE,
00074 b.x, b.y, b.w, b.h);
00075 }
00076 }
00077
00078
00079
00080
00081
00082 void Chunk_chooser::tell_server
00083 (
00084 )
00085 {
00086 if (selected < 0)
00087 return;
00088 unsigned char buf[Exult_server::maxlength];
00089 unsigned char *ptr = &buf[0];
00090 Write2(ptr, info[selected].num);
00091 ExultStudio *studio = ExultStudio::get_instance();
00092 studio->send_to_server(Exult_server::set_edit_chunknum,
00093 buf, ptr - buf);
00094 }
00095
00096
00097
00098
00099
00100
00101 void Chunk_chooser::select
00102 (
00103 int new_sel
00104 )
00105 {
00106 if (new_sel < 0 || new_sel >= info_cnt)
00107 return;
00108 selected = new_sel;
00109 tell_server();
00110 enable_controls();
00111 int chunknum = info[selected].num;
00112
00113
00114 char buf[150];
00115 g_snprintf(buf, sizeof(buf), "Chunk %d", chunknum);
00116 gtk_statusbar_push(GTK_STATUSBAR(sbar), sbar_sel, buf);
00117 }
00118
00119
00120
00121
00122
00123 void Chunk_chooser::render
00124 (
00125 )
00126 {
00127
00128 int selchunk = -1, new_selected = -1;
00129 if (selected >= 0)
00130 selchunk = info[selected].num;
00131
00132
00133 delete [] info;
00134
00135 gint winw = draw->allocation.width, winh = draw->allocation.height;
00136
00137 info = new Chunk_info[256];
00138 info_cnt = 0;
00139
00140 iwin->fill8(255);
00141 int index = index0;
00142
00143 const int chunkw = 128, chunkh = 128;
00144 int total_cnt = get_count();
00145 int y = border;
00146
00147 while (index < total_cnt && y + chunkh/2 + border <= winh)
00148 {
00149 int x = border;
00150 int cliph = y + chunkh <= winh ? chunkh : (winh - y);
00151 while (index < total_cnt && x + chunkw + border <= winw)
00152 {
00153 iwin->set_clip(x, y, chunkw, cliph);
00154 int chunknum = group ? (*group)[index] : index;
00155 render_chunk(chunknum, x, y);
00156 iwin->clear_clip();
00157
00158 info[info_cnt].set(chunknum, x, y, chunkw, chunkh);
00159 if (chunknum == selchunk)
00160
00161 new_selected = info_cnt;
00162 info_cnt++;
00163 index++;
00164 x += chunkw + border;
00165 }
00166 y += chunkh + border;
00167 }
00168 if (new_selected == -1)
00169 unselect(false);
00170 else
00171 select(new_selected);
00172 }
00173
00174
00175
00176
00177
00178
00179
00180 unsigned char *Chunk_chooser::get_chunk
00181 (
00182 int chunknum
00183 )
00184 {
00185 unsigned char *data = chunklist[chunknum];
00186 if (data)
00187 return data;
00188
00189 unsigned char buf[Exult_server::maxlength];
00190 unsigned char *ptr = &buf[0];
00191 unsigned char *newptr = &buf[0];
00192 Write2(ptr, chunknum);
00193 ExultStudio *studio = ExultStudio::get_instance();
00194 int server_socket = studio->get_server_socket();
00195 Exult_server::Msg_type id;
00196 int datalen;
00197 if (!studio->send_to_server(Exult_server::send_terrain,
00198 buf, ptr - buf) ||
00199 !Exult_server::wait_for_response(server_socket, 100) ||
00200 (datalen = Exult_server::Receive_data(server_socket,
00201 id, buf, sizeof(buf))) == -1 ||
00202 id != Exult_server::send_terrain ||
00203 Read2(newptr) != chunknum)
00204 {
00205 data = new unsigned char[512];
00206 chunklist[chunknum] = data;
00207 chunkfile.seekg(chunknum*512);
00208 chunkfile.read(reinterpret_cast<char *>(data), 512);
00209 if (!chunkfile.good())
00210 {
00211 memset(data, 0, 512);
00212 cout << "Error reading chunk file" << endl;
00213 }
00214 }
00215 else
00216 set_chunk(buf, datalen);
00217 return chunklist[chunknum];
00218 }
00219
00220
00221
00222
00223
00224 void Chunk_chooser::update_num_chunks
00225 (
00226 int new_num_chunks
00227 )
00228 {
00229 num_chunks = new_num_chunks;
00230 GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(vscroll));
00231 adj->upper = num_chunks;
00232 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242 void Chunk_chooser::set_chunk
00243 (
00244 unsigned char *data,
00245 int datalen
00246 )
00247 {
00248 int tnum = Read2(data);
00249 int new_num_chunks = Read2(data);
00250 datalen -= 4;
00251 if (datalen != 512)
00252 {
00253 cout << "Set_chunk: Wrong data length" << endl;
00254 return;
00255 }
00256 if (tnum < 0 || tnum >= new_num_chunks)
00257 {
00258 cout << "Set_chunk: Bad terrain # (" << tnum <<
00259 ") received" << endl;
00260 return;
00261 }
00262 if (new_num_chunks != num_chunks)
00263 {
00264 if (new_num_chunks > num_chunks)
00265 chunklist.resize(new_num_chunks);
00266 update_num_chunks(new_num_chunks);
00267 }
00268 unsigned char *chunk = chunklist[tnum];
00269 if (!chunk)
00270 chunk = chunklist[tnum] = new unsigned char[512];
00271 memcpy(chunk, data, 512);
00272 }
00273
00274
00275
00276
00277
00278 void Chunk_chooser::render_chunk
00279 (
00280 int chunknum,
00281 int xoff, int yoff
00282 )
00283 {
00284 unsigned char *data = get_chunk(chunknum);
00285 int y = c_tilesize;
00286 for (int ty = 0; ty < c_tiles_per_chunk; ty++, y += c_tilesize)
00287 {
00288 int x = c_tilesize;
00289 for (int tx = 0; tx < c_tiles_per_chunk; tx++,
00290 x += c_tilesize)
00291 {
00292 unsigned char l = *data++;
00293 unsigned char h = *data++;
00294 int shapenum = l + 256*(h&0x3);
00295 int framenum = h >> 2;
00296 Shape_frame *s = ifile->get_shape(shapenum, framenum);
00297 if (s)
00298 s->paint(iwin, xoff + x - 1, yoff + y -1);
00299 }
00300 }
00301 }
00302
00303
00304
00305
00306
00307 int Chunk_chooser::get_count
00308 (
00309 )
00310 {
00311 return group ? group->size() : num_chunks;
00312 }
00313
00314
00315
00316
00317
00318 gint Chunk_chooser::configure
00319 (
00320 GtkWidget *widget,
00321 GdkEventConfigure *event,
00322 gpointer data
00323 )
00324 {
00325 Chunk_chooser *chooser = (Chunk_chooser *) data;
00326 chooser->Shape_draw::configure();
00327 chooser->render();
00328
00329 int w = event->width, h = event->height;
00330 int per_row = (w - border)/(128 + border);
00331 int num_rows = (h - border)/(128 + border);
00332 int page_size = per_row*num_rows;
00333 GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(
00334 chooser->vscroll));
00335 adj->step_increment = per_row;
00336 adj->page_increment = page_size;
00337 adj->page_size = page_size;
00338 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
00339 if (chooser->group)
00340 chooser->enable_drop();
00341
00342 return (TRUE);
00343 }
00344
00345
00346
00347
00348
00349
00350 gint Chunk_chooser::expose
00351 (
00352 GtkWidget *widget,
00353 GdkEventExpose *event,
00354 gpointer data
00355 )
00356 {
00357 Chunk_chooser *chooser = (Chunk_chooser *) data;
00358 chooser->show(event->area.x, event->area.y, event->area.width,
00359 event->area.height);
00360 return (TRUE);
00361 }
00362
00363
00364
00365
00366
00367 #ifdef WIN32
00368
00369 static bool win32_button = false;
00370
00371 gint Chunk_chooser::win32_drag_motion
00372 (
00373 GtkWidget *widget,
00374 GdkEventMotion *event,
00375 gpointer data
00376 )
00377 {
00378 if (win32_button)
00379 {
00380 win32_button = false;
00381
00382
00383 windragdata wdata;
00384
00385
00386
00387 drag_data_get(NULL, NULL, (GtkSelectionData *) &wdata,
00388 U7_TARGET_CHUNKID, 0, data);
00389
00390 POINT pnt;
00391 GetCursorPos(&pnt);
00392
00393 LPDROPSOURCE idsrc = (LPDROPSOURCE) new Windropsource(0,
00394 pnt.x, pnt.y);
00395 LPDATAOBJECT idobj = (LPDATAOBJECT) new Winstudioobj(wdata);
00396 DWORD dndout;
00397
00398 HRESULT res = DoDragDrop(idobj, idsrc, DROPEFFECT_COPY, &dndout);
00399 if (FAILED(res)) {
00400 g_warning ("Oops! Something is wrong with OLE2 DnD..");
00401 }
00402
00403 delete idsrc;
00404 idobj->Release();
00405 }
00406
00407 return true;
00408 };
00409
00410 #else
00411 gint Chunk_chooser::drag_motion
00412 (
00413 GtkWidget *widget,
00414 GdkEventMotion *event,
00415 gpointer data
00416 )
00417 {
00418 Chunk_chooser *chooser = (Chunk_chooser *) data;
00419 if (!chooser->dragging && chooser->selected >= 0)
00420 chooser->start_drag(U7_TARGET_CHUNKID_NAME,
00421 U7_TARGET_CHUNKID, (GdkEvent *) event);
00422 return true;
00423 }
00424 #endif
00425
00426 gint Chunk_chooser::mouse_press
00427 (
00428 GtkWidget *widget,
00429 GdkEventButton *event,
00430 gpointer data
00431 )
00432 {
00433 Chunk_chooser *chooser = (Chunk_chooser *) data;
00434
00435 if (event->button == 4) {
00436 chooser->scroll(true);
00437 return(TRUE);
00438 } else if (event->button == 5) {
00439 chooser->scroll(false);
00440 return(TRUE);
00441 }
00442
00443 int old_selected = chooser->selected;
00444 int i;
00445 for (i = 0; i < chooser->info_cnt; i++)
00446 if (chooser->info[i].box.has_point(
00447 (int) event->x, (int) event->y))
00448 {
00449
00450
00451
00452 #ifdef WIN32
00453
00454
00455
00456
00457
00458 win32_button = true;
00459 #endif
00460
00461 chooser->selected = i;
00462 chooser->locate_cx = chooser->locate_cy = -1;
00463 chooser->render();
00464 chooser->show();
00465
00466 if (chooser->sel_changed)
00467 (*chooser->sel_changed)();
00468 break;
00469 }
00470 if (i == chooser->info_cnt && event->button == 1)
00471 chooser->unselect(true);
00472 else if (event->button == 3)
00473 gtk_menu_popup(GTK_MENU(chooser->create_popup()), 0, 0, 0, 0,
00474 event->button, event->time);
00475 return (TRUE);
00476 }
00477
00478
00479
00480
00481 static gint Mouse_release
00482 (
00483 GtkWidget *widget,
00484 GdkEventButton *event,
00485 gpointer data
00486 )
00487 {
00488 Chunk_chooser *chooser = (Chunk_chooser *) data;
00489 chooser->mouse_up();
00490 }
00491
00492
00493
00494
00495
00496 void Chunk_chooser::drag_data_get
00497 (
00498 GtkWidget *widget,
00499 GdkDragContext *context,
00500 GtkSelectionData *seldata,
00501 guint info,
00502 guint time,
00503 gpointer data
00504 )
00505 {
00506 cout << "In DRAG_DATA_GET" << endl;
00507 Chunk_chooser *chooser = (Chunk_chooser *) data;
00508 if (chooser->selected < 0 || info != U7_TARGET_CHUNKID)
00509 return;
00510 guchar buf[30];
00511 Chunk_info& shinfo = chooser->info[chooser->selected];
00512 int len = Store_u7_chunkid(buf, shinfo.num);
00513 cout << "Setting selection data (" << shinfo.num << ')' << endl;
00514 #ifdef WIN32
00515 windragdata *wdata = (windragdata *)seldata;
00516 wdata->assign(info, len, buf);
00517 #else
00518
00519 gtk_selection_owner_set(widget, gdk_atom_intern("XdndSelection", 0),
00520 time);
00521
00522 gtk_selection_data_set(seldata,
00523 gdk_atom_intern(U7_TARGET_CHUNKID_NAME, 0),
00524 8, buf, len);
00525 #endif
00526 }
00527
00528
00529
00530
00531
00532 gint Chunk_chooser::selection_clear
00533 (
00534 GtkWidget *widget,
00535 GdkEventSelection *event,
00536 gpointer data
00537 )
00538 {
00539
00540 cout << "SELECTION_CLEAR" << endl;
00541 return TRUE;
00542 }
00543
00544
00545
00546
00547
00548 gint Chunk_chooser::drag_begin
00549 (
00550 GtkWidget *widget,
00551 GdkDragContext *context,
00552 gpointer data
00553 )
00554 {
00555 cout << "In DRAG_BEGIN" << endl;
00556 Chunk_chooser *chooser = (Chunk_chooser *) data;
00557 if (chooser->selected < 0)
00558 return FALSE;
00559 #if 0
00560
00561 Chunk_info& shinfo = chooser->info[chooser->selected];
00562 Chunk_frame *chunk = chooser->ifile->get_chunk(shinfo.chunknum,
00563 shinfo.framenum);
00564 if (!chunk)
00565 return FALSE;
00566 int w = chunk->get_width(), h = chunk->get_height(),
00567 xright = chunk->get_xright(), ybelow = chunk->get_ybelow();
00568 Image_buffer8 tbuf(w, h);
00569 tbuf.fill8(0xff);
00570 unsigned char *tbits = tbuf.get_bits();
00571 chunk->paint(&tbuf, w - 1 - xright, h - 1 - ybelow);
00572
00573 GdkPixmap *pixmap = gdk_pixmap_new(widget->window, w, h, -1);
00574 gdk_draw_indexed_image(pixmap, chooser->drawgc, 0, 0, w, h,
00575 GDK_RGB_DITHER_NORMAL, tbits,
00576 tbuf.get_line_width(), chooser->palette);
00577 int mask_stride = (w + 7)/8;
00578 char *mdata = new char[mask_stride*h];
00579 for (int y = 0; y < h; y++)
00580
00581 for (int b = 0; b < mask_stride; b++)
00582 {
00583 char bits = 0;
00584 unsigned char *vals = tbits + y*w + b*8;
00585 for (int i = 0; i < 8; i++)
00586 if (vals[i] != 0xff)
00587 bits |= (1<<i);
00588 mdata[y*mask_stride + b] = bits;
00589 }
00590 GdkBitmap *mask = gdk_bitmap_create_from_data(widget->window,
00591 mdata, w, h);
00592 delete mdata;
00593
00594 gtk_drag_set_icon_pixmap(context,
00595 gdk_window_get_colormap(widget->window), pixmap, mask,
00596 w - 2 - xright, h - 2 - ybelow);
00597 gdk_pixmap_unref(pixmap);
00598 gdk_bitmap_unref(mask);
00599 #endif
00600 return TRUE;
00601 }
00602
00603
00604
00605
00606
00607 void Chunk_chooser::drag_data_received
00608 (
00609 GtkWidget *widget,
00610 GdkDragContext *context,
00611 gint x,
00612 gint y,
00613 GtkSelectionData *seldata,
00614 guint info,
00615 guint time,
00616 gpointer udata
00617 )
00618 {
00619 Chunk_chooser *chooser = (Chunk_chooser *) udata;
00620 cout << "Chunk drag_data_received" << endl;
00621 if (seldata->type == gdk_atom_intern(U7_TARGET_CHUNKID_NAME, 0) &&
00622 seldata->format == 8 && seldata->length > 0)
00623 {
00624 int cnum;
00625 Get_u7_chunkid(seldata->data, cnum);
00626 chooser->group->add(cnum);
00627 chooser->render();
00628
00629 }
00630 }
00631
00632
00633
00634
00635
00636 void Chunk_chooser::enable_drop
00637 (
00638 )
00639 {
00640 if (drop_enabled)
00641 return;
00642 drop_enabled = true;
00643 gtk_widget_realize(draw);
00644 #ifndef WIN32
00645 GtkTargetEntry tents[1];
00646 tents[0].target = U7_TARGET_CHUNKID_NAME;
00647 tents[0].flags = 0;
00648 tents[0].info = U7_TARGET_CHUNKID;
00649 gtk_drag_dest_set(draw, GTK_DEST_DEFAULT_ALL, tents, 1,
00650 (GdkDragAction) (GDK_ACTION_COPY | GDK_ACTION_MOVE));
00651
00652 gtk_signal_connect(GTK_OBJECT(draw), "drag_data_received",
00653 GTK_SIGNAL_FUNC(drag_data_received), this);
00654 #endif
00655 }
00656
00657
00658
00659
00660
00661 void Chunk_chooser::scroll
00662 (
00663 int newindex
00664 )
00665 {
00666 int total = get_count();
00667 if (index0 < newindex)
00668 index0 = newindex < total ? newindex : total;
00669 else if (index0 > newindex)
00670 index0 = newindex >= 0 ? newindex : 0;
00671 render();
00672 show();
00673 }
00674
00675
00676
00677
00678
00679 void Chunk_chooser::scroll
00680 (
00681 bool upwards
00682 )
00683 {
00684 GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(vscroll));
00685 float delta = adj->step_increment;
00686 if (upwards)
00687 delta = -delta;
00688 adj->value += delta;
00689 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
00690 scroll((gint) adj->value);
00691 }
00692
00693
00694
00695
00696
00697 void Chunk_chooser::scrolled
00698 (
00699 GtkAdjustment *adj,
00700 gpointer data
00701 )
00702 {
00703 Chunk_chooser *chooser = (Chunk_chooser *) data;
00704 cout << "Scrolled to " << adj->value << '\n';
00705 gint newindex = (gint) adj->value;
00706 chooser->scroll(newindex);
00707 }
00708
00709
00710
00711
00712
00713 void Chunk_chooser::enable_controls
00714 (
00715 )
00716 {
00717 if (selected == -1)
00718 {
00719 gtk_widget_set_sensitive(loc_down, false);
00720 gtk_widget_set_sensitive(loc_up, false);
00721 if (!group)
00722 {
00723 gtk_widget_set_sensitive(move_down, false);
00724 gtk_widget_set_sensitive(move_up, false);
00725 }
00726 return;
00727 }
00728 gtk_widget_set_sensitive(loc_down, true);
00729 gtk_widget_set_sensitive(loc_up, true);
00730 if (!group)
00731 {
00732 gtk_widget_set_sensitive(move_down,
00733 info[selected].num < num_chunks - 1);
00734 gtk_widget_set_sensitive(move_up,
00735 info[selected].num > 0);
00736 }
00737 }
00738
00739
00740
00741
00742
00743 static void on_insert_empty
00744 (
00745 GtkMenuItem *item,
00746 gpointer udata
00747 )
00748 {
00749 Chunk_chooser *chooser = (Chunk_chooser *) udata;
00750 chooser->insert(false);
00751 }
00752
00753 static void on_insert_dup
00754 (
00755 GtkMenuItem *item,
00756 gpointer udata
00757 )
00758 {
00759 Chunk_chooser *chooser = (Chunk_chooser *) udata;
00760 chooser->insert(true);
00761 }
00762 static void on_delete
00763 (
00764 GtkMenuItem *item,
00765 gpointer udata
00766 )
00767 {
00768 Chunk_chooser *chooser = (Chunk_chooser *) udata;
00769 chooser->del();
00770 }
00771
00772
00773
00774
00775
00776 GtkWidget *Chunk_chooser::create_popup
00777 (
00778 )
00779 {
00780 ExultStudio *studio = ExultStudio::get_instance();
00781 Object_browser::create_popup();
00782 if (group != 0)
00783 return popup;
00784 GtkWidget *mitem = Add_menu_item(popup, "New...");
00785 GtkWidget *new_menu = gtk_menu_new();
00786 gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), new_menu);
00787 Add_menu_item(new_menu, "Empty", GTK_SIGNAL_FUNC(on_insert_empty),
00788 this);
00789 if (selected >= 0)
00790 {
00791 Add_menu_item(new_menu, "Duplicate",
00792 GTK_SIGNAL_FUNC(on_insert_dup), this);
00793 Add_menu_item(popup, "Delete",
00794 GTK_SIGNAL_FUNC(on_delete), this);
00795 }
00796 return popup;
00797 }
00798
00799
00800
00801
00802
00803 Chunk_chooser::Chunk_chooser
00804 (
00805 Vga_file *i,
00806 std::istream& cfile,
00807 unsigned char *palbuf,
00808 int w, int h,
00809 Shape_group *g
00810 ) : Object_browser(g), Shape_draw(i, palbuf, gtk_drawing_area_new()),
00811 chunkfile(cfile),
00812 info(0), info_cnt(0), sel_changed(0),
00813 locate_cx(-1), locate_cy(-1), drop_enabled(false), to_del(-1)
00814 {
00815 chunkfile.seekg(0, std::ios::end);
00816 num_chunks = chunkfile.tellg()/(c_tiles_per_chunk*c_tiles_per_chunk*2);
00817 chunklist.resize(num_chunks);
00818
00819 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
00820 set_widget(vbox);
00821 gtk_widget_show(vbox);
00822
00823 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
00824 gtk_widget_show(hbox);
00825 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
00826
00827
00828 GtkWidget *frame = gtk_frame_new(NULL);
00829 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
00830 gtk_widget_show(frame);
00831 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
00832
00833
00834 gtk_widget_set_events(draw, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
00835 | GDK_BUTTON_RELEASE_MASK
00836 | GDK_POINTER_MOTION_HINT_MASK |
00837 GDK_BUTTON1_MOTION_MASK);
00838
00839 gtk_signal_connect(GTK_OBJECT(draw), "configure_event",
00840 GTK_SIGNAL_FUNC(configure), this);
00841
00842 gtk_signal_connect(GTK_OBJECT(draw), "expose_event",
00843 GTK_SIGNAL_FUNC(expose), this);
00844
00845 gtk_signal_connect(GTK_OBJECT(draw), "button_press_event",
00846 GTK_SIGNAL_FUNC(mouse_press), this);
00847 gtk_signal_connect(GTK_OBJECT(draw), "button_release_event",
00848 GTK_SIGNAL_FUNC(Mouse_release), this);
00849
00850 gtk_signal_connect(GTK_OBJECT(draw), "drag_begin",
00851 GTK_SIGNAL_FUNC(drag_begin), this);
00852 #ifdef WIN32
00853
00854 gtk_signal_connect(GTK_OBJECT(draw), "motion_notify_event",
00855 GTK_SIGNAL_FUNC(win32_drag_motion), this);
00856 #else
00857 gtk_signal_connect(GTK_OBJECT(draw), "motion_notify_event",
00858 GTK_SIGNAL_FUNC(drag_motion), this);
00859 #endif
00860 gtk_signal_connect (GTK_OBJECT(draw), "drag_data_get",
00861 GTK_SIGNAL_FUNC(drag_data_get), this);
00862 gtk_signal_connect (GTK_OBJECT(draw), "selection_clear_event",
00863 GTK_SIGNAL_FUNC(selection_clear), this);
00864 gtk_container_add (GTK_CONTAINER (frame), draw);
00865 gtk_drawing_area_size(GTK_DRAWING_AREA(draw), w, h);
00866 gtk_widget_show(draw);
00867
00868 GtkObject *chunk_adj = gtk_adjustment_new(0, 0,
00869 num_chunks, 1,
00870 4, 1.0);
00871 vscroll = gtk_vscrollbar_new(GTK_ADJUSTMENT(chunk_adj));
00872
00873 gtk_range_set_update_policy(GTK_RANGE(vscroll),
00874 GTK_UPDATE_DELAYED);
00875 gtk_box_pack_start(GTK_BOX(hbox), vscroll, FALSE, TRUE, 0);
00876
00877 gtk_signal_connect(GTK_OBJECT(chunk_adj), "value_changed",
00878 GTK_SIGNAL_FUNC(scrolled), this);
00879 gtk_widget_show(vscroll);
00880
00881 GtkWidget *hbox1 = gtk_hbox_new(FALSE, 0);
00882 gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0);
00883 gtk_widget_show(hbox1);
00884
00885 sbar = gtk_statusbar_new();
00886 sbar_sel = gtk_statusbar_get_context_id(GTK_STATUSBAR(sbar),
00887 "selection");
00888 gtk_box_pack_start(GTK_BOX(hbox1), sbar, TRUE, TRUE, 0);
00889 gtk_widget_show(sbar);
00890
00891 gtk_box_pack_start(GTK_BOX(vbox),
00892 create_controls(locate_controls|(!group ? move_controls : 0)),
00893 FALSE, FALSE, 0);
00894 }
00895
00896
00897
00898
00899
00900 Chunk_chooser::~Chunk_chooser
00901 (
00902 )
00903 {
00904 gtk_widget_destroy(get_widget());
00905 delete [] info;
00906 int i;
00907 for (i = 0; i < num_chunks; i++)
00908 delete chunklist[i];
00909 }
00910
00911
00912
00913
00914
00915
00916
00917 bool Chunk_chooser::server_response
00918 (
00919 int id,
00920 unsigned char *data,
00921 int datalen
00922 )
00923 {
00924 switch ((Exult_server::Msg_type) id)
00925 {
00926 case Exult_server::locate_terrain:
00927 locate_response(data, datalen);
00928 return true;
00929 case Exult_server::insert_terrain:
00930 insert_response(data, datalen);
00931 return true;
00932 case Exult_server::delete_terrain:
00933 delete_response(data, datalen);
00934 return true;
00935 case Exult_server::swap_terrain:
00936 swap_response(data, datalen);
00937 return true;
00938 case Exult_server::send_terrain:
00939 set_chunk(data, datalen);
00940 render();
00941 show();
00942 return true;
00943 default:
00944 return false;
00945 }
00946 }
00947
00948
00949
00950
00951
00952 void Chunk_chooser::end_terrain_editing
00953 (
00954 )
00955 {
00956
00957 for (int i = 0; i < num_chunks; i++)
00958 {
00959 delete chunklist[i];
00960 chunklist[i] = 0;
00961 }
00962 render();
00963 show();
00964 }
00965
00966
00967
00968
00969
00970 void Chunk_chooser::unselect
00971 (
00972 bool need_render
00973 )
00974 {
00975 if (selected >= 0)
00976 {
00977 selected = -1;
00978 locate_cx = locate_cy = -1;
00979 if (need_render)
00980 {
00981 render();
00982 show();
00983 }
00984 if (sel_changed)
00985 (*sel_changed)();
00986 }
00987 enable_controls();
00988 char buf[150];
00989 if (info_cnt > 0)
00990 {
00991
00992 g_snprintf(buf, sizeof(buf), "Chunks %d to %d",
00993 info[0].num, info[info_cnt - 1].num);
00994 gtk_statusbar_push(GTK_STATUSBAR(sbar), sbar_sel, buf);
00995 }
00996 }
00997
00998
00999
01000
01001
01002
01003 void Chunk_chooser::locate
01004 (
01005 int dir
01006 )
01007 {
01008 if (selected < 0)
01009 return;
01010 bool upwards = false;
01011 unsigned char data[Exult_server::maxlength];
01012 unsigned char *ptr = &data[0];
01013 int tnum = info[selected].num;
01014 int cx = locate_cx, cy = locate_cy;
01015 if (dir == 0)
01016 {
01017 cx = cy = -1;
01018 }
01019 else if (dir == -1)
01020 upwards = true;
01021 Write2(ptr, tnum);
01022 Write2(ptr, cx);
01023 Write2(ptr, cy);
01024 *ptr++ = upwards ? 1 : 0;
01025 ExultStudio *studio = ExultStudio::get_instance();
01026 if (!studio->send_to_server(
01027 Exult_server::locate_terrain, data, ptr - data))
01028 to_del = -1;
01029 }
01030
01031 void Chunk_chooser::locate
01032 (
01033 bool upwards
01034 )
01035 {
01036 locate(upwards ? -1 : 1);
01037 }
01038
01039
01040
01041
01042
01043 void Chunk_chooser::locate_response
01044 (
01045 unsigned char *data,
01046 int datalen
01047 )
01048 {
01049 unsigned char *ptr = data;
01050 int tnum = Read2(ptr);
01051 if (selected < 0 || tnum != info[selected].num)
01052 {
01053 to_del = -1;
01054 return;
01055 }
01056 short cx = (short) Read2(ptr);
01057 short cy = (short) Read2(ptr);
01058 ptr++;
01059 if (!*ptr)
01060 {
01061 if (to_del >= 0 && to_del == tnum)
01062 {
01063 unsigned char data[Exult_server::maxlength];
01064 unsigned char *ptr = &data[0];
01065 Write2(ptr, tnum);
01066 ExultStudio *studio = ExultStudio::get_instance();
01067 studio->send_to_server(Exult_server::delete_terrain,
01068 data, ptr - data);
01069 }
01070 else
01071 EStudio::Alert("Terrain %d not found.", tnum);
01072 }
01073 else
01074 {
01075 locate_cx = cx;
01076 locate_cy = cy;
01077 if (to_del >= 0)
01078 EStudio::Alert("Terrain %d is still in use", tnum);
01079 }
01080 to_del = -1;
01081 }
01082
01083
01084
01085
01086
01087 void Chunk_chooser::insert
01088 (
01089 bool dup
01090 )
01091 {
01092 if (dup && selected < 0)
01093 return;
01094 unsigned char data[Exult_server::maxlength];
01095 unsigned char *ptr = &data[0];
01096 int tnum = selected >= 0 ? info[selected].num : -1;
01097 Write2(ptr, tnum);
01098 *ptr++ = dup ? 1 : 0;
01099 ExultStudio *studio = ExultStudio::get_instance();
01100 studio->send_to_server(
01101 Exult_server::insert_terrain, data, ptr - data);
01102 }
01103
01104
01105
01106
01107
01108 void Chunk_chooser::del
01109 (
01110 )
01111 {
01112 if (selected < 0)
01113 return;
01114 to_del = info[selected].num;
01115 locate(0);
01116 }
01117
01118
01119
01120
01121
01122 void Chunk_chooser::insert_response
01123 (
01124 unsigned char *data,
01125 int datalen
01126 )
01127 {
01128 unsigned char *ptr = data;
01129 int tnum = (short) Read2(ptr);
01130 bool dup = *ptr++ ? true : false;
01131 bool okay = *ptr ? true : false;
01132 if (!*ptr)
01133 EStudio::Alert("Terrain insert failed.");
01134 else
01135 {
01136 unsigned char *data = new unsigned char[512];
01137 if (dup && tnum >= 0 && tnum < num_chunks && chunklist[tnum])
01138 memcpy(data, chunklist[tnum], 512);
01139 else
01140 memset(data, 0, 512);
01141 if (tnum >= 0 && tnum < num_chunks - 1)
01142 chunklist.insert(chunklist.begin() + tnum + 1, data);
01143 else
01144 chunklist.push_back(data);
01145 update_num_chunks(num_chunks + 1);
01146 render();
01147 show();
01148 }
01149 }
01150
01151
01152
01153
01154
01155 void Chunk_chooser::delete_response
01156 (
01157 unsigned char *data,
01158 int datalen
01159 )
01160 {
01161 unsigned char *ptr = data;
01162 int tnum = (short) Read2(ptr);
01163 bool okay = *ptr ? true : false;
01164 if (!*ptr)
01165 EStudio::Alert("Terrain delete failed.");
01166 else
01167 {
01168 delete chunklist[tnum];
01169 chunklist.erase(chunklist.begin() + tnum);
01170 update_num_chunks(num_chunks - 1);
01171 render();
01172 show();
01173 }
01174 }
01175
01176
01177
01178
01179
01180 void Chunk_chooser::move
01181 (
01182 bool upwards
01183 )
01184 {
01185 if (selected < 0)
01186 return;
01187 unsigned char data[Exult_server::maxlength];
01188 unsigned char *ptr = &data[0];
01189 int tnum = info[selected].num;
01190 if ((tnum == 0 && upwards) || (tnum == num_chunks - 1 && !upwards))
01191 return;
01192 if (upwards)
01193 tnum--;
01194 Write2(ptr, tnum);
01195 ExultStudio *studio = ExultStudio::get_instance();
01196 studio->send_to_server(
01197 Exult_server::swap_terrain, data, ptr - data);
01198 }
01199
01200
01201
01202
01203
01204 void Chunk_chooser::swap_response
01205 (
01206 unsigned char *data,
01207 int datalen
01208 )
01209 {
01210 unsigned char *ptr = data;
01211 int tnum = (short) Read2(ptr);
01212 bool okay = *ptr ? true : false;
01213 if (!*ptr)
01214 cout << "Terrain insert failed." << endl;
01215 else if (tnum >= 0 && tnum < num_chunks - 1)
01216 {
01217 unsigned char *tmp = get_chunk(tnum);
01218 chunklist[tnum] = get_chunk(tnum + 1);
01219 chunklist[tnum + 1] = tmp;
01220 if (selected >= 0)
01221 {
01222 if (info[selected].num == tnum)
01223 {
01224 if (selected >= info_cnt - 1)
01225 scroll(false);
01226 select(selected + 1);
01227 }
01228 else if (info[selected].num == tnum + 1)
01229 {
01230 if (selected <= 0)
01231 scroll(true);
01232 select(selected - 1);
01233 }
01234 }
01235 render();
01236 show();
01237 }
01238 }