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 #include <windows.h>
00032 #endif
00033
00034 #include <gtk/gtk.h>
00035 #include <gdk/gdkkeysyms.h>
00036 #ifdef XWIN
00037 #include <gdk/gdkx.h>
00038 #endif
00039 #include <glib.h>
00040 #include <stdlib.h>
00041 #include <sys/stat.h>
00042 #include <unistd.h>
00043 #include "shapelst.h"
00044 #include "shapevga.h"
00045 #include "ibuf8.h"
00046 #include "Flex.h"
00047 #include "u7drag.h"
00048 #include "studio.h"
00049 #include "utils.h"
00050 #include "shapegroup.h"
00051 #include "shapefile.h"
00052 #include "pngio.h"
00053 #include "fontgen.h"
00054
00055 using std::cout;
00056 using std::endl;
00057 using std::strlen;
00058 using std::string;
00059 using EStudio::Prompt;
00060 using EStudio::Alert;
00061 using EStudio::Add_menu_item;
00062
00063 std::vector<Editing_file*> Shape_chooser::editing_files;
00064 int Shape_chooser::check_editing_timer = -1;
00065
00066
00067
00068
00069
00070 class Editing_file
00071 {
00072 string vga_basename;
00073 string pathname;
00074 time_t mtime;
00075 int shapenum, framenum;
00076 int tiles;
00077 bool bycolumns;
00078 public:
00079 friend class Shape_chooser;
00080
00081 Editing_file(const char *vganm, const char *pnm, time_t m,
00082 int sh, int fr)
00083 : vga_basename(vganm), pathname(pnm),
00084 mtime(m), shapenum(sh), framenum(fr), tiles(0)
00085 { }
00086
00087 Editing_file(const char *vganm, const char *pnm, time_t m, int sh,
00088 int ts, bool bycol)
00089 : vga_basename(vganm), pathname(pnm), mtime(m), shapenum(sh),
00090 framenum(0), tiles(ts), bycolumns(bycol)
00091 { }
00092 };
00093
00094
00095
00096
00097
00098 static void Shape_dropped_here
00099 (
00100 int file,
00101 int shape,
00102 int frame,
00103 void *udata
00104 )
00105 {
00106 ((Shape_chooser *) udata)->shape_dropped_here(file, shape, frame);
00107 }
00108
00109
00110
00111
00112
00113 void Shape_chooser::show
00114 (
00115 int x, int y, int w, int h
00116 )
00117 {
00118 Shape_draw::show(draw->window, x, y, w, h);
00119 if (selected >= 0)
00120 {
00121 Rectangle b = info[selected].box;
00122
00123 gdk_draw_rectangle(draw->window, drawgc, FALSE,
00124 b.x, b.y, b.w, b.h);
00125 }
00126 }
00127
00128
00129
00130
00131
00132 void Shape_chooser::tell_server_shape
00133 (
00134 )
00135 {
00136 int shnum = -1, frnum = 0;
00137 if (selected >= 0)
00138 {
00139 shnum = info[selected].shapenum;
00140 frnum = info[selected].framenum;
00141 }
00142 unsigned char buf[Exult_server::maxlength];
00143 unsigned char *ptr = &buf[0];
00144 Write2(ptr, shnum);
00145 Write2(ptr, frnum);
00146 ExultStudio *studio = ExultStudio::get_instance();
00147 studio->send_to_server(Exult_server::set_edit_shape, buf, ptr - buf);
00148 }
00149
00150
00151
00152
00153
00154
00155 void Shape_chooser::select
00156 (
00157 int new_sel
00158 )
00159 {
00160 selected = new_sel;
00161 tell_server_shape();
00162 int shapenum = info[selected].shapenum;
00163
00164 gtk_widget_set_sensitive(fspin, true);
00165 gtk_adjustment_set_value(frame_adj, info[selected].framenum);
00166 int nframes = ifile->get_num_frames(shapenum);
00167 frame_adj->upper = nframes - 1;
00168 gtk_adjustment_changed(frame_adj);
00169 gtk_widget_set_sensitive(fspin, true);
00170
00171
00172 char buf[150];
00173 g_snprintf(buf, sizeof(buf), "Shape %d (%d frames)",
00174 shapenum, nframes);
00175 ExultStudio *studio = ExultStudio::get_instance();
00176 if (shapes_file && studio->get_shape_name(shapenum))
00177 {
00178 int len = strlen(buf);
00179 g_snprintf(buf + len, sizeof(buf) - len,
00180 ": '%s'", studio->get_shape_name(shapenum));
00181 }
00182 gtk_statusbar_push(GTK_STATUSBAR(sbar), sbar_sel, buf);
00183 }
00184
00185 const int border = 4;
00186
00187
00188
00189
00190 void Shape_chooser::render
00191 (
00192 )
00193 {
00194 if (frames_mode)
00195 {
00196 render_frames();
00197 return;
00198 }
00199
00200 int selshape = -1, selframe = -1, new_selected = -1;
00201 if (selected >= 0)
00202 {
00203 selshape = info[selected].shapenum;
00204 selframe = info[selected].framenum;
00205 }
00206
00207
00208 delete [] info;
00209
00210 gint winw = draw->allocation.width, winh = draw->allocation.height;
00211
00212 info = new Shape_entry[1024];
00213
00214 iwin->fill8(255);
00215 int x = 0;
00216 info_cnt = 0;
00217 int curr_y = 0;
00218 int row_h = 0;
00219 int row = row0;
00220 int total_cnt = get_count();
00221 int index;
00222
00223 for (int index = index0; index < total_cnt; index++)
00224 {
00225 int shapenum = group ? (*group)[index] : index;
00226 int framenum = shapenum == selshape ? selframe : framenum0;
00227 Shape_frame *shape = ifile->get_shape(shapenum, framenum);
00228 if(shape)
00229 {
00230 int sh = shape->get_height(),
00231 sw = shape->get_width();
00232 if (sh>row_h)
00233 row_h = sh;
00234
00235 if (x + sw > winw)
00236 {
00237 curr_y += row_h + border;
00238 row_h = sh;
00239 x = 0;
00240 row++;
00241 if (row == row_indices.size())
00242 row_indices.push_back(index);
00243 else if (row < row_indices.size())
00244 row_indices[row] = index;
00245 if (curr_y + 36 >= winh)
00246 break;
00247 }
00248 int sy = curr_y+border;
00249 shape->paint(iwin, x + shape->get_xleft(),
00250 sy + shape->get_yabove());
00251 if (sh > winh)
00252 {
00253 sy += sh - winh;
00254 sh = winh;
00255 }
00256
00257 info[info_cnt].set(index,
00258 shapenum, framenum, x, sy, sw, sh);
00259 if (shapenum == selshape)
00260
00261 new_selected = info_cnt;
00262 x += sw + border;
00263 info_cnt++;
00264 }
00265 }
00266 nrows = row - row0;
00267 nrows += (x > 0);
00268 if (new_selected == -1)
00269 unselect(false);
00270 else
00271 select(new_selected);
00272 adjust_vscrollbar();
00273 }
00274
00275
00276
00277
00278
00279 static int Get_max_height
00280 (
00281 Shape *shape
00282 )
00283 {
00284 int cnt = shape->get_num_frames();
00285 int maxh = 0;
00286 for (int i = 0; i < cnt; i++)
00287 {
00288 Shape_frame *frame = shape->get_frame(i);
00289 int ht = frame ? frame->get_height() : -1;
00290 if (ht > maxh)
00291 maxh = ht;
00292 }
00293 return maxh;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302 static int Get_x_offset
00303 (
00304 Shape *shape,
00305 int framenum
00306 )
00307 {
00308 if (!shape)
00309 return 0;
00310 int nframes = shape->get_num_frames();
00311 if (framenum >= nframes)
00312 framenum = nframes - 1;
00313 int xoff = 0;
00314 for (int i = 0; i < framenum; i++)
00315 xoff += shape->get_frame(i)->get_width() + border;
00316 return xoff;
00317 }
00318
00319
00320
00321
00322
00323 void Shape_chooser::render_frames
00324 (
00325 )
00326 {
00327
00328 gint winw = draw->allocation.width, winh = draw->allocation.height;
00329
00330 int selshape = -1, selframe = -1, new_selected = -1;
00331 if (selected >= 0)
00332 {
00333 selshape = info[selected].shapenum;
00334 selframe = info[selected].framenum;
00335 }
00336
00337
00338 delete [] info;
00339 iwin->set_clip(0, 0, winw, winh);
00340
00341 info = new Shape_entry[4048];
00342
00343 iwin->fill8(255);
00344 info_cnt = 0;
00345 int curr_y = 0;
00346 int row = row0;
00347 int total_cnt = get_count();
00348 int index;
00349
00350 for (int index = index0; index < total_cnt; index++)
00351 {
00352 int shapenum = group ? (*group)[index] : index;
00353
00354 Shape *shape = ifile->extract_shape(shapenum);
00355 int nframes = shape ? shape->get_num_frames() : 0;
00356 if (!nframes)
00357 continue;
00358 int row_h = Get_max_height(shape);
00359 int x = -hoffset;
00360 int sw, sh;
00361 for (int framenum = 0; framenum < nframes; framenum++,
00362 x += sw + border)
00363 {
00364 if (x >= winw - 1)
00365 break;
00366 Shape_frame *frame = shape->get_frame(framenum);
00367 if (!frame)
00368 {
00369 sw = sh = 0;
00370 continue;
00371 }
00372 sh = frame->get_height();
00373 sw = frame->get_width();
00374 if (x < 0 && x + sw < sw/2)
00375 continue;
00376 int sy = curr_y+border;
00377 frame->paint(iwin, x + frame->get_xleft(),
00378 sy + frame->get_yabove());
00379 if (sh > winh)
00380 {
00381 sy += sh - winh;
00382 sh = winh;
00383 }
00384
00385 info[info_cnt].set(index,
00386 shapenum, framenum, x, sy, sw, sh);
00387 if (shapenum == selshape && framenum == selframe)
00388
00389 new_selected = info_cnt;
00390 info_cnt++;
00391 }
00392
00393 curr_y += row_h + border;
00394 x = 0;
00395 if (row == row_indices.size())
00396 row_indices.push_back(index);
00397 else if (row < row_indices.size())
00398 row_indices[row] = index;
00399 row++;
00400 if (curr_y + 36 >= winh)
00401 break;
00402 }
00403 int nrows = row - row0;
00404 if (new_selected == -1)
00405 unselect(false);
00406 else
00407 select(new_selected);
00408 iwin->clear_clip();
00409 adjust_vscrollbar();
00410 }
00411
00412
00413
00414
00415
00416
00417 void Shape_chooser::scroll_to_frame
00418 (
00419 )
00420 {
00421 if (selected >= 0)
00422 {
00423 int selshape = info[selected].shapenum;
00424 int selframe = info[selected].framenum;
00425 Shape *shape = ifile->extract_shape(selshape);
00426 int xoff = Get_x_offset(shape, selframe);
00427 if (xoff < hoffset)
00428 hoffset = xoff > border ? xoff - border : 0;
00429 else
00430 {
00431 gint winw = draw->allocation.width;
00432 int sw = shape->get_frame(selframe)->get_width();
00433 if (xoff + sw + border - hoffset > winw)
00434 hoffset = xoff + sw + border - winw;
00435 }
00436 GtkAdjustment *adj = gtk_range_get_adjustment(
00437 GTK_RANGE(hscroll));
00438 gtk_adjustment_set_value(adj, hoffset);
00439 }
00440 }
00441
00442
00443
00444
00445
00446
00447
00448 int Shape_chooser::next_row
00449 (
00450 int start
00451 )
00452 {
00453 int total_cnt = get_count();
00454 if (frames_mode)
00455 return start < total_cnt - 1 ? (start + 1) : -1;
00456 int selshape = -1, selframe = -1;
00457 if (selected >= 0)
00458 {
00459 selshape = info[selected].shapenum;
00460 selframe = info[selected].framenum;
00461 }
00462 gint winw = draw->allocation.width;
00463 int index = start;
00464 int x = 0;
00465 while (index < total_cnt)
00466 {
00467 int shapenum = group ? (*group)[index] : index;
00468 int framenum = shapenum == selshape ? selframe : framenum0;
00469 Shape_frame *shape = ifile->get_shape(shapenum, framenum);
00470 if(shape)
00471 {
00472 int sw = shape->get_width();
00473 if (x + sw > winw)
00474 break;
00475 x += sw + border;
00476 }
00477 index++;
00478 }
00479 if (index == start)
00480 index++;
00481 if (index == total_cnt)
00482 return -1;
00483 return index;
00484 }
00485
00486
00487
00488
00489
00490 void Shape_chooser::goto_index
00491 (
00492 int index
00493 )
00494 {
00495 int total = get_count();
00496 if (!total)
00497 return;
00498 assert (index >= 0 && index < total);
00499
00500 int last_index = index0 + (frames_mode ? nrows : info_cnt);
00501 if (index < index0)
00502 {
00503 do
00504 index0 = row_indices[--row0];
00505 while (index < index0);
00506 }
00507 else if (index >= last_index && last_index > 0)
00508 {
00509 do
00510 {
00511 if (row0 < row_indices.size() - 1)
00512 index0 = row_indices[++row0];
00513 else
00514 {
00515 int i = next_row(index0);
00516 if (i < 0)
00517 break;
00518 row_indices.push_back(i);
00519 row0++;
00520 index0 = i;
00521 }
00522 }
00523 while (index0 < index);
00524 if (index != index0)
00525 row0--;
00526 index0 = row_indices[row0];
00527 info_cnt = 0;
00528 }
00529
00530 GtkAdjustment *adj = gtk_range_get_adjustment(
00531 GTK_RANGE(vscroll));
00532 if (row0 >= adj->value)
00533 adjust_vscrollbar();
00534 gtk_adjustment_set_value(adj, row0);
00535 }
00536
00537
00538
00539
00540
00541 static gint Configure_chooser
00542 (
00543 GtkWidget *widget,
00544 GdkEventConfigure *event,
00545 gpointer data
00546 )
00547 {
00548 Shape_chooser *chooser = (Shape_chooser *) data;
00549 return chooser->configure(event);
00550 }
00551 gint Shape_chooser::configure
00552 (
00553 GdkEventConfigure *event
00554 )
00555 {
00556 Shape_draw::configure();
00557
00558 if (event->width != config_width || event->height != config_height)
00559 {
00560 row_indices.resize(1);
00561 row0 = 0;
00562 info_cnt = 0;
00563 int i0 = index0;
00564 index0 = 0;
00565 goto_index(i0);
00566 render();
00567 adjust_hscrollbar(-1);
00568 config_width = event->width;
00569 config_height = event->height;
00570 }
00571 else
00572 render();
00573
00574
00575 if (drop_callback != Shape_dropped_here)
00576 enable_drop(Shape_dropped_here, this);
00577 return (TRUE);
00578 }
00579
00580
00581
00582
00583
00584 gint Shape_chooser::expose
00585 (
00586 GtkWidget *widget,
00587 GdkEventExpose *event,
00588 gpointer data
00589 )
00590 {
00591 Shape_chooser *chooser = (Shape_chooser *) data;
00592 chooser->show(event->area.x, event->area.y, event->area.width,
00593 event->area.height);
00594 return (TRUE);
00595 }
00596
00597
00598
00599
00600
00601 #ifdef WIN32
00602
00603 static bool win32_button = false;
00604
00605 gint Shape_chooser::win32_drag_motion
00606 (
00607 GtkWidget *widget,
00608 GdkEventMotion *event,
00609 gpointer data
00610 )
00611 {
00612 if (win32_button)
00613 {
00614 win32_button = false;
00615
00616
00617 windragdata wdata;
00618
00619
00620
00621 drag_data_get(NULL, NULL, (GtkSelectionData *) &wdata,
00622 U7_TARGET_SHAPEID, 0, data);
00623
00624 POINT pnt;
00625 GetCursorPos(&pnt);
00626
00627 LPDROPSOURCE idsrc = (LPDROPSOURCE) new Windropsource(0,
00628 pnt.x, pnt.y);
00629 LPDATAOBJECT idobj = (LPDATAOBJECT) new Winstudioobj(wdata);
00630 DWORD dndout;
00631
00632 HRESULT res = DoDragDrop(idobj, idsrc, DROPEFFECT_COPY, &dndout);
00633 if (FAILED(res)) {
00634 g_warning ("Oops! Something is wrong with OLE2 DnD..");
00635 }
00636
00637 delete idsrc;
00638 idobj->Release();
00639 }
00640
00641 return true;
00642 };
00643 #else
00644 gint Shape_chooser::drag_motion
00645 (
00646 GtkWidget *widget,
00647 GdkEventMotion *event,
00648 gpointer data
00649 )
00650 {
00651 Shape_chooser *chooser = (Shape_chooser *) data;
00652 if (!chooser->dragging && chooser->selected >= 0)
00653 chooser->start_drag(U7_TARGET_SHAPEID_NAME,
00654 U7_TARGET_SHAPEID, (GdkEvent *) event);
00655 return true;
00656 }
00657 #endif
00658
00659
00660
00661
00662 gint Shape_chooser::mouse_press
00663 (
00664 GtkWidget *widget,
00665 GdkEventButton *event
00666 )
00667 {
00668 gtk_widget_grab_focus(widget);
00669
00670 if (event->button == 4) {
00671 if (row0 > 0)
00672 scroll_vertical(row0-1);
00673 return(TRUE);
00674 } else if (event->button == 5) {
00675 scroll_vertical(row0+1);
00676 return(TRUE);
00677 }
00678
00679 int old_selected = selected;
00680 int i;
00681 for (i = 0; i < info_cnt; i++)
00682 if (info[i].box.has_point(
00683 (int) event->x, (int) event->y))
00684 {
00685
00686 #ifdef WIN32
00687
00688
00689
00690
00691
00692 win32_button = true;
00693 #endif
00694 selected = i;
00695 render();
00696 show();
00697
00698 if (sel_changed)
00699 (*sel_changed)();
00700 break;
00701 }
00702 if (i == info_cnt && event->button == 1)
00703 unselect(true);
00704 else if (selected == old_selected && old_selected >= 0)
00705 {
00706 if (((GdkEvent *) event)->type == GDK_2BUTTON_PRESS)
00707 edit_shape_info();
00708 }
00709 if (event->button == 3)
00710 gtk_menu_popup(GTK_MENU(create_popup()),
00711 0, 0, 0, 0, event->button, event->time);
00712 return (TRUE);
00713 }
00714
00715
00716
00717
00718 static gint Mouse_press
00719 (
00720 GtkWidget *widget,
00721 GdkEventButton *event,
00722 gpointer data
00723 )
00724 {
00725 Shape_chooser *chooser = (Shape_chooser *) data;
00726 return chooser->mouse_press(widget, event);
00727 }
00728 static gint Mouse_release
00729 (
00730 GtkWidget *widget,
00731 GdkEventButton *event,
00732 gpointer data
00733 )
00734 {
00735 Shape_chooser *chooser = (Shape_chooser *) data;
00736 chooser->mouse_up();
00737 }
00738
00739
00740
00741
00742 C_EXPORT gboolean
00743 on_draw_key_press (GtkEntry *entry,
00744 GdkEventKey *event,
00745 gpointer user_data)
00746 {
00747 Shape_chooser *chooser = (Shape_chooser *) user_data;
00748 switch (event->keyval)
00749 {
00750 case GDK_Delete:
00751 chooser->del_frame();
00752 return TRUE;
00753 case GDK_Insert:
00754 chooser->new_frame();
00755 return TRUE;
00756 }
00757 return FALSE;
00758 }
00759
00760 const unsigned char transp = 255;
00761
00762
00763
00764
00765
00766
00767
00768 time_t Shape_chooser::export_png
00769 (
00770 const char *fname
00771 )
00772 {
00773 ExultStudio *studio = ExultStudio::get_instance();
00774 int shnum = info[selected].shapenum,
00775 frnum = info[selected].framenum;
00776 Shape_frame *frame = ifile->get_shape(shnum, frnum);
00777 int w = frame->get_width(), h = frame->get_height();
00778 Image_buffer8 img(w, h);
00779 img.fill8(transp);
00780 frame->paint(&img, frame->get_xleft(), frame->get_yabove());
00781 int xoff = 0, yoff = 0;
00782 if (frame->is_rle())
00783 {
00784 xoff = -frame->get_xright();
00785 yoff = -frame->get_ybelow();
00786 }
00787 return export_png(fname, img, xoff, yoff);
00788 }
00789
00790
00791
00792
00793
00794 static void Get_rgb_palette
00795 (
00796 GdkRgbCmap *palette,
00797 unsigned char *buf
00798 )
00799 {
00800 for (int i = 0; i < 256; i++)
00801 {
00802 buf[3*i] = (palette->colors[i]>>16)&0xff;
00803 buf[3*i + 1] = (palette->colors[i]>>8)&0xff;
00804 buf[3*i + 2] = palette->colors[i]&0xff;
00805 }
00806 }
00807
00808
00809
00810
00811
00812
00813
00814 time_t Shape_chooser::export_png
00815 (
00816 const char *fname,
00817 Image_buffer8& img,
00818 int xoff, int yoff
00819 )
00820 {
00821 unsigned char pal[3*256];
00822 Get_rgb_palette(palette, pal);
00823 int w = img.get_width(), h = img.get_height();
00824 struct stat fs;
00825
00826
00827 if (!Export_png8(fname, transp, w, h, w, xoff, yoff, img.get_bits(),
00828 &pal[0], 256, true) ||
00829 stat(fname, &fs) != 0)
00830 {
00831 Alert("Error creating '%s'", fname);
00832 return 0;
00833 }
00834 return fs.st_mtime;
00835 }
00836
00837
00838
00839
00840
00841
00842
00843 time_t Shape_chooser::export_tiled_png
00844 (
00845 const char *fname,
00846 int tiles,
00847
00848 bool bycols
00849 )
00850 {
00851 assert (selected >= 0);
00852 int shnum = info[selected].shapenum;
00853 ExultStudio *studio = ExultStudio::get_instance();
00854
00855 assert (shnum < 0x96 && file_info == studio->get_vgafile());
00856 Shape *shape = ifile->extract_shape(shnum);
00857 assert(shape != 0);
00858 cout << "Writing " << fname << " tiled"
00859 << (bycols ? ", by cols" : ", by rows") << " first" << endl;
00860 int nframes = shape->get_num_frames();
00861
00862 int dim1_cnt = (nframes + tiles - 1)/tiles;
00863 int w, h;
00864 if (bycols)
00865 { h = tiles*8; w = dim1_cnt*8; }
00866 else
00867 { w = tiles*8; h = dim1_cnt*8; }
00868 Image_buffer8 img(w, h);
00869 img.fill8(transp);
00870 for (int f = 0; f < nframes; f++)
00871 {
00872 Shape_frame *frame = shape->get_frame(f);
00873 if (!frame)
00874 continue;
00875 if (frame->is_rle() || frame->get_width() != 8 ||
00876 frame->get_height() != 8)
00877 {
00878 Alert("Can only tile 8x8 flat shapes");
00879 return 0;
00880 }
00881 int x, y;
00882 if (bycols)
00883 { y = f%tiles; x = f/tiles; }
00884 else
00885 { x = f%tiles; y = f/tiles; }
00886 frame->paint(&img, x*8 + frame->get_xleft(),
00887 y*8 + frame->get_yabove());
00888 }
00889
00890 return export_png(fname, img, 0, 0);
00891 }
00892
00893
00894
00895
00896
00897 void Shape_chooser::edit_shape_info
00898 (
00899 )
00900 {
00901 ExultStudio *studio = ExultStudio::get_instance();
00902 int shnum = info[selected].shapenum,
00903 frnum = info[selected].framenum;
00904 Shape_info *info = 0;
00905 char *name = 0;
00906 if (shapes_file)
00907 {
00908 shapes_file->read_info(false, true);
00909 info = &shapes_file->get_info(shnum);
00910 name = studio->get_shape_name(shnum);
00911 }
00912 studio->open_shape_window(shnum, frnum, file_info, name, info);
00913 }
00914
00915
00916
00917
00918
00919 void Shape_chooser::edit_shape
00920 (
00921 int tiles,
00922
00923 bool bycols
00924 )
00925 {
00926 ExultStudio *studio = ExultStudio::get_instance();
00927 int shnum = info[selected].shapenum,
00928 frnum = info[selected].framenum;
00929 string filestr("<GAME>");
00930 filestr += "/itmp";
00931 U7mkdir(filestr.c_str(), 0755);
00932
00933 filestr = get_system_path(filestr);
00934 char *ext;
00935 if (!tiles)
00936 ext = g_strdup_printf("/%s.s%d_f%d.png",
00937 file_info->get_basename(), shnum, frnum);
00938 else
00939 ext = g_strdup_printf("/%s.s%d_%c%d.png",
00940 file_info->get_basename(), shnum,
00941 (bycols ? 'c' : 'r'), tiles);
00942 filestr += ext;
00943 g_free(ext);
00944 const char *fname = filestr.c_str();
00945 cout << "Writing image '" << fname << "'" << endl;
00946 time_t mtime;
00947 if (!tiles)
00948 {
00949 mtime = export_png(fname);
00950 if (!mtime)
00951 return;
00952
00953 editing_files.push_back(new Editing_file(
00954 file_info->get_basename(), fname, mtime, shnum, frnum));
00955 }
00956 else
00957 {
00958 mtime = export_tiled_png(fname, tiles, bycols);
00959 if (!mtime)
00960 return;
00961 editing_files.push_back(new Editing_file(
00962 file_info->get_basename(), fname, mtime, shnum,
00963 tiles, bycols));
00964 }
00965 string cmd(studio->get_image_editor());
00966 cmd += ' ';
00967 cmd += fname;
00968 cmd += " &";
00969 #ifndef WIN32
00970 int ret = system(cmd.c_str());
00971 if (ret == 127 || ret == -1)
00972 Alert("Can't launch '%s'", studio->get_image_editor());
00973 #else
00974 PROCESS_INFORMATION pi;
00975 STARTUPINFO si;
00976 std::memset (&si, 0, sizeof(si));
00977 si.cb = sizeof(si);
00978 int ret = CreateProcess (NULL, const_cast<char *>(cmd.c_str()),
00979 NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
00980 if (!ret)
00981 Alert("Can't launch '%s'", studio->get_image_editor());
00982 #endif
00983 if (check_editing_timer == -1)
00984 check_editing_timer = gtk_timeout_add(6000,
00985 Shape_chooser::check_editing_files_cb, 0L);
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995 gint Shape_chooser::check_editing_files_cb
00996 (
00997 gpointer
00998 )
00999 {
01000 ExultStudio *studio = ExultStudio::get_instance();
01001
01002 if (studio->has_focus())
01003 check_editing_files();
01004 return 1;
01005 }
01006
01007 gint Shape_chooser::check_editing_files
01008 (
01009 )
01010 {
01011 bool modified = false;
01012 for (std::vector<Editing_file*>::iterator it = editing_files.begin();
01013 it != editing_files.end(); it++)
01014 {
01015 Editing_file *ed = *it;
01016 struct stat fs;
01017 if (stat(ed->pathname.c_str(), &fs) != 0)
01018 {
01019 delete ed;
01020 it = editing_files.erase(it);
01021 continue;
01022 }
01023 if (fs.st_mtime <= ed->mtime)
01024 continue;
01025 ed->mtime = fs.st_mtime;
01026 read_back_edited(ed);
01027 modified = true;
01028 }
01029 if (modified)
01030 {
01031 ExultStudio *studio = ExultStudio::get_instance();
01032 Object_browser *browser = studio->get_browser();
01033 if (browser)
01034 {
01035 browser->render();
01036 browser->show();
01037 }
01038 studio->update_group_windows(0);
01039 }
01040 return 1;
01041 }
01042
01043
01044
01045
01046
01047
01048
01049 static int Find_closest_color
01050 (
01051 unsigned char *pal,
01052 int r, int g, int b
01053 )
01054 {
01055 int best_index = -1;
01056 long best_distance = 0xfffffff;
01057
01058 for (int i = 0; i < 0xe0; i++)
01059 {
01060 long dr = r - pal[3*i], dg = g - pal[3*i + 1],
01061 db = b - pal[3*i + 2];
01062
01063 long dist = dr*dr + dg*dg + db*db;
01064 if (dist < best_distance)
01065 {
01066 best_index = i;
01067 best_distance = dist;
01068 }
01069 }
01070 return best_index;
01071 }
01072
01073
01074
01075
01076
01077 static void Convert_indexed_image
01078 (
01079 unsigned char *pixels,
01080 int count,
01081 unsigned char *oldpal,
01082 int oldpalsize,
01083 unsigned char *newpal
01084 )
01085 {
01086 if (memcmp(oldpal, newpal, oldpalsize) == 0)
01087 return;
01088 int map[256];
01089 int i;
01090 for (i = 0; i < 256; i++)
01091 map[i] = -1;
01092
01093 for (i = 0; i < count; i++)
01094 {
01095 unsigned char pix = *pixels;
01096 if (map[pix] == -1)
01097 map[pix] = Find_closest_color(newpal, oldpal[3*pix],
01098 oldpal[3*pix+1], oldpal[3*pix+2]);
01099 *pixels++ = map[pix];
01100 }
01101 }
01102
01103
01104
01105
01106
01107 static void Import_png
01108 (
01109 const char *fname,
01110 Shape_file_info *finfo,
01111 unsigned char *pal,
01112 int shapenum, int framenum
01113 )
01114 {
01115 ExultStudio *studio = ExultStudio::get_instance();
01116 Vga_file *ifile = finfo->get_ifile();
01117 if (!ifile)
01118 return;
01119 Shape *shape = ifile->extract_shape(shapenum);
01120 if (!shape)
01121 return;
01122 int w, h, rowsize, xoff, yoff, palsize;
01123 unsigned char *pixels, *oldpal;
01124
01125 if (!Import_png8(fname, 255, w, h, rowsize, xoff, yoff,
01126 pixels, oldpal, palsize))
01127 return;
01128
01129 Convert_indexed_image(pixels, h*rowsize, oldpal, palsize, pal);
01130 delete oldpal;
01131
01132 bool flat = shapenum < 0x96 && finfo == studio->get_vgafile();
01133 int xleft, yabove;
01134 if (flat)
01135 {
01136 xleft = yabove = 8;
01137 if (w != 8 || h != 8 || rowsize != 8)
01138 {
01139 char *msg = g_strdup_printf(
01140 "Shape %d must be 8x8", shapenum);
01141 studio->prompt(msg, "Continue");
01142 g_free(msg);
01143 delete pixels;
01144 return;
01145 }
01146 }
01147 else
01148 {
01149 xleft = w + xoff - 1;
01150 yabove = h + yoff - 1;
01151 }
01152 shape->set_frame(new Shape_frame(pixels,
01153 w, h, xleft, yabove, !flat), framenum);
01154 delete pixels;
01155 finfo->set_modified();
01156 }
01157
01158
01159
01160
01161
01162 static void Import_png_tiles
01163 (
01164 const char *fname,
01165 Shape_file_info *finfo,
01166 unsigned char *pal,
01167 int shapenum,
01168 int tiles,
01169 bool bycols
01170 )
01171 {
01172 ExultStudio *studio = ExultStudio::get_instance();
01173 Vga_file *ifile = finfo->get_ifile();
01174 if (!ifile)
01175 return;
01176 Shape *shape = ifile->extract_shape(shapenum);
01177 if (!shape)
01178 return;
01179 int nframes = shape->get_num_frames();
01180 cout << "Reading " << fname << " tiled"
01181 << (bycols ? ", by cols" : ", by rows") << " first" << endl;
01182
01183 int dim0_cnt = tiles;
01184 int dim1_cnt = (nframes + dim0_cnt - 1)/dim0_cnt;
01185 int needw, needh;
01186 if (bycols)
01187 { needh = dim0_cnt*8; needw = dim1_cnt*8; }
01188 else
01189 { needw = dim0_cnt*8; needh = dim1_cnt*8; }
01190 int w, h, rowsize, xoff, yoff, palsize;
01191 unsigned char *pixels, *oldpal;
01192
01193 if (!Import_png8(fname, 255, w, h, rowsize, xoff, yoff,
01194 pixels, oldpal, palsize))
01195 {
01196 Alert("Error reading '%s'", fname);
01197 return;
01198 }
01199
01200 Convert_indexed_image(pixels, h*rowsize, oldpal, palsize, pal);
01201 delete oldpal;
01202 if (w < needw || h < needh)
01203 {
01204 Alert("File '%s' image is too small. %dx%d required.",
01205 fname, needw, needh);
01206 return;
01207 }
01208 for (int frnum = 0; frnum < nframes; frnum++)
01209 {
01210 int x, y;
01211 if (bycols)
01212 { y = frnum%dim0_cnt; x = frnum/dim0_cnt; }
01213 else
01214 { x = frnum%dim0_cnt; y = frnum/dim0_cnt; }
01215 unsigned char *src = pixels + w*8*y + 8*x;
01216 unsigned char buf[8*8];
01217 unsigned char *ptr = &buf[0];
01218 for (int row = 0; row < 8; row++)
01219 {
01220 memcpy(ptr, src, 8);
01221 ptr += 8;
01222 src += w;
01223 }
01224 shape->set_frame(new Shape_frame(&buf[0], 8, 8, 8, 8, false),
01225 frnum);
01226 }
01227 delete pixels;
01228 finfo->set_modified();
01229 }
01230
01231
01232
01233
01234
01235 void Shape_chooser::read_back_edited
01236 (
01237 Editing_file *ed
01238 )
01239 {
01240 ExultStudio *studio = ExultStudio::get_instance();
01241 Shape_file_info *finfo = studio->open_shape_file(
01242 ed->vga_basename.c_str());
01243 if (!finfo)
01244 return;
01245 unsigned char pal[3*256];
01246 unsigned char *palbuf = studio->get_palbuf();
01247 for (int i = 0; i < 3*256; i++)
01248 pal[i] = palbuf[i]*4;
01249 if (!ed->tiles)
01250 Import_png(ed->pathname.c_str(), finfo, pal,
01251 ed->shapenum, ed->framenum);
01252 else
01253 Import_png_tiles(ed->pathname.c_str(), finfo, pal,
01254 ed->shapenum, ed->tiles, ed->bycolumns);
01255 }
01256
01257
01258
01259
01260
01261 void Shape_chooser::clear_editing_files
01262 (
01263 )
01264 {
01265 check_editing_files();
01266 while (!editing_files.empty())
01267 {
01268 Editing_file *ed = editing_files.back();
01269 editing_files.pop_back();
01270 unlink(ed->pathname.c_str());
01271 delete ed;
01272 }
01273 if (check_editing_timer != -1)
01274 gtk_timeout_remove(check_editing_timer);
01275 check_editing_timer = -1;
01276 }
01277
01278
01279
01280
01281
01282 void Shape_chooser::export_frame
01283 (
01284 char *fname,
01285 gpointer user_data
01286 )
01287 {
01288 Shape_chooser *ed = (Shape_chooser *) user_data;
01289 if (U7exists(fname))
01290 {
01291 char *msg = g_strdup_printf(
01292 "'%s' already exists. Overwrite?", fname);
01293 int answer = Prompt(msg, "Yes", "No");
01294 g_free(msg);
01295 if (answer != 0)
01296 return;
01297 }
01298 if (ed->selected < 0)
01299 return;
01300 ed->export_png(fname);
01301 }
01302
01303
01304
01305
01306
01307 void Shape_chooser::import_frame
01308 (
01309 char *fname,
01310 gpointer user_data
01311 )
01312 {
01313 Shape_chooser *ed = (Shape_chooser *) user_data;
01314 if (ed->selected < 0)
01315 return;
01316 int shnum = ed->info[ed->selected].shapenum,
01317 frnum = ed->info[ed->selected].framenum;
01318 unsigned char pal[3*256];
01319 Get_rgb_palette(ed->palette, pal);
01320 Import_png(fname, ed->file_info, pal, shnum, frnum);
01321 ed->render();
01322 ed->show();
01323 ExultStudio *studio = ExultStudio::get_instance();
01324 studio->update_group_windows(0);
01325 }
01326
01327
01328
01329
01330
01331 void Shape_chooser::new_frame
01332 (
01333 )
01334 {
01335 if (selected < 0)
01336 return;
01337 int shnum = info[selected].shapenum,
01338 frnum = info[selected].framenum;
01339 Vga_file *ifile = file_info->get_ifile();
01340
01341 Shape *shape = ifile->extract_shape(shnum);
01342 if (!shape ||
01343
01344 frnum > shape->get_num_frames())
01345 return;
01346
01347 ExultStudio *studio = ExultStudio::get_instance();
01348 bool flat = shnum < 0x96 && file_info == studio->get_vgafile();
01349 int w = 0, h = 0;
01350 int xleft, yabove;
01351 if (flat)
01352 w = h = xleft = yabove = 8;
01353 else
01354 {
01355 int cnt = shape->get_num_frames();
01356 for (int i = 0; i < cnt; i++)
01357 {
01358 int ht = shape->get_frame(i)->get_height();
01359 if (ht > h)
01360 h = ht;
01361 int wd = shape->get_frame(i)->get_width();
01362 if (wd > w)
01363 w = wd;
01364 }
01365 if (h == 0)
01366 h = 8;
01367 if (w == 0)
01368 w = 8;
01369 xleft = w - 1;
01370 yabove = h - 1;
01371 }
01372 Image_buffer8 img(w, h);
01373 img.fill8(1);
01374 if (w > 2 && h > 2)
01375 img.fill8(2, w - 2, h - 2, 1, 1);
01376 Shape_frame *frame = new Shape_frame(img.get_bits(),
01377 w, h, xleft, yabove, !flat);
01378 shape->add_frame(frame, frnum + 1);
01379 file_info->set_modified();
01380 Object_browser *browser = studio->get_browser();
01381 if (browser)
01382 {
01383 browser->render();
01384 browser->show();
01385 }
01386 studio->update_group_windows(0);
01387 }
01388
01389
01390
01391
01392 C_EXPORT void
01393 on_new_shape_okay_clicked (GtkButton *button,
01394 gpointer user_data)
01395 {
01396 GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(button));
01397 Shape_chooser *chooser = (Shape_chooser *)
01398 gtk_object_get_user_data(GTK_OBJECT(win));
01399 chooser->create_new_shape();
01400 gtk_widget_hide(win);
01401 }
01402
01403 C_EXPORT void on_new_shape_font_toggled
01404 (
01405 GtkToggleButton *btn,
01406 gpointer user_data
01407 )
01408 {
01409 bool on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn));
01410 GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(btn));
01411 Shape_chooser *chooser = (Shape_chooser *)
01412 gtk_object_get_user_data(GTK_OBJECT(win));
01413 chooser->from_font_toggled(on);
01414 }
01415 C_EXPORT gboolean on_new_shape_font_color_draw_expose_event
01416 (
01417 GtkWidget *widget,
01418 GdkEventExpose *event,
01419 gpointer data
01420 )
01421 {
01422 ExultStudio *studio = ExultStudio::get_instance();
01423 int index = studio->get_spin("new_shape_font_color");
01424 Shape_chooser *ed = (Shape_chooser *)
01425 gtk_object_get_user_data(GTK_OBJECT(widget));
01426 guint32 color = ed->get_color(index);
01427 GdkGC *gc = (GdkGC *)
01428 gtk_object_get_data(GTK_OBJECT(widget), "color_gc");
01429 if (!gc)
01430 {
01431 gc = gdk_gc_new(widget->window);
01432 gtk_object_set_data(GTK_OBJECT(widget), "color_gc", gc);
01433 }
01434 gdk_rgb_gc_set_foreground(gc, color);
01435 gdk_draw_rectangle(widget->window, gc, TRUE, event->area.x,
01436 event->area.y, event->area.width, event->area.height);
01437 return (TRUE);
01438 }
01439 C_EXPORT void on_new_shape_font_color_changed
01440 (
01441 GtkSpinButton *button,
01442 gpointer user_data
01443 )
01444 {
01445 ExultStudio *studio = ExultStudio::get_instance();
01446
01447 GtkWidget *draw = glade_xml_get_widget(studio->get_xml(),
01448 "new_shape_font_color_draw");
01449 GdkRectangle area = {0, 0, draw->allocation.width,
01450 draw->allocation.height};
01451 gtk_widget_draw(draw, &area);
01452 }
01453
01454
01455
01456
01457
01458 static void font_file_chosen
01459 (
01460 const char *fname,
01461 gpointer user_data
01462 )
01463 {
01464 ExultStudio *studio = ExultStudio::get_instance();
01465 studio->set_entry("new_shape_font_name", fname);
01466 studio->set_spin("new_shape_nframes", 128);
01467 }
01468
01469
01470
01471
01472
01473 void Shape_chooser::from_font_toggled
01474 (
01475 bool on
01476 )
01477 {
01478 ExultStudio *studio = ExultStudio::get_instance();
01479 studio->set_sensitive("new_shape_font_name", on);
01480 if (!on)
01481 return;
01482 studio->set_sensitive("new_shape_font_color", true);
01483 studio->set_sensitive("new_shape_font_height", true);
01484 GtkFileSelection *fsel = Create_file_selection(
01485 "Choose font file", font_file_chosen, 0L);
01486 gtk_widget_show(GTK_WIDGET(fsel));
01487 }
01488
01489
01490
01491
01492
01493 void Shape_chooser::new_shape
01494 (
01495 )
01496 {
01497 ExultStudio *studio = ExultStudio::get_instance();
01498 GladeXML *xml = studio->get_xml();
01499 GtkWidget *win = glade_xml_get_widget(xml, "new_shape_window");
01500 gtk_window_set_modal(GTK_WINDOW(win), true);
01501 gtk_object_set_user_data(GTK_OBJECT(win), this);
01502
01503 int shnum = selected >= 0 ? info[selected].shapenum : 0,
01504 frnum = selected >= 0 ? info[selected].framenum : 0;
01505 GtkWidget *spin = glade_xml_get_widget(xml, "new_shape_num");
01506 GtkAdjustment *adj = gtk_spin_button_get_adjustment(
01507 GTK_SPIN_BUTTON(spin));
01508 adj->upper = 2047;
01509 gtk_adjustment_changed(adj);
01510 Vga_file *ifile = file_info->get_ifile();
01511 int shstart;
01512 for (shstart = shnum; shstart <= adj->upper; shstart++)
01513 if (shstart >= ifile->get_num_shapes() ||
01514 !ifile->get_num_frames(shstart))
01515 break;
01516 if (shstart > adj->upper)
01517 {
01518 for (shstart = shnum - 1; shstart >= 0; shstart--)
01519 if (!ifile->get_num_frames(shstart))
01520 break;
01521 if (shstart < 0)
01522 shstart = shnum;
01523 }
01524 gtk_adjustment_set_value(adj, shstart);
01525 spin = glade_xml_get_widget(xml, "new_shape_nframes");
01526 adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spin));
01527 bool flat = shnum < 0x96 && file_info == studio->get_vgafile();
01528 if (flat)
01529 adj->upper = 31;
01530 else
01531 adj->upper = 255;
01532 gtk_adjustment_changed(adj);
01533 spin = glade_xml_get_widget(xml, "new_shape_font_height");
01534 studio->set_sensitive("new_shape_font_height", false);
01535 adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spin));
01536 adj->lower = 4;
01537 adj->upper = 64;
01538 gtk_adjustment_changed(adj);
01539 spin = glade_xml_get_widget(xml, "new_shape_font_color");
01540 studio->set_sensitive("new_shape_font_color", false);
01541 adj = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(spin));
01542 adj->lower = 0;
01543 adj->upper = 255;
01544 gtk_adjustment_changed(adj);
01545
01546 studio->set_toggle("new_shape_font", false);
01547 #ifndef HAVE_FREETYPE2
01548 studio->set_sensitive("new_shape_font", false);
01549 #endif
01550
01551 GtkWidget *draw = glade_xml_get_widget(xml,
01552 "new_shape_font_color_draw");
01553 gtk_object_set_user_data(GTK_OBJECT(draw), this);
01554 gtk_widget_show(win);
01555 }
01556
01557
01558
01559
01560
01561
01562 void Shape_chooser::create_new_shape
01563 (
01564 )
01565 {
01566 ExultStudio *studio = ExultStudio::get_instance();
01567 int shnum = studio->get_spin("new_shape_num");
01568 int nframes = studio->get_spin("new_shape_nframes");
01569 if (nframes <= 0)
01570 nframes = 1;
01571 else if (nframes > 256)
01572 nframes = 256;
01573 Vga_file *ifile = file_info->get_ifile();
01574 if (shnum < ifile->get_num_shapes() && ifile->get_num_frames(shnum))
01575 {
01576 if (Prompt("Replace existing shape?", "Yes", "No") != 0)
01577 return;
01578 }
01579 Shape *shape = ifile->new_shape(shnum);
01580 if (!shape)
01581 {
01582 Alert("Can't create shape %d", shnum);
01583 return;
01584 }
01585
01586 bool flat = shnum < 0x96 && file_info == studio->get_vgafile();
01587 bool use_font = false;
01588 #ifdef HAVE_FREETYPE2
01589
01590 use_font = studio->get_toggle("new_shape_font");
01591 const char *fontname = studio->get_text_entry("new_shape_font_name");
01592 use_font = use_font && (fontname != 0) && *fontname != 0;
01593 if (use_font)
01594 {
01595 if (flat)
01596 {
01597 Alert("Can't load font into a 'flat' shape");
01598 return;
01599 }
01600 int ht = studio->get_spin("new_shape_font_height");
01601 int fg = studio->get_spin("new_shape_font_color");
01602 if (!Gen_font_shape(shape, fontname, nframes,
01603
01604 ht, fg, 255))
01605 Alert("Error loading font file '%s'", fontname);
01606 }
01607 #endif
01608 if (!use_font)
01609 {
01610 int w = 8, h = 8;
01611 int xleft = flat ? 8 : w - 1;
01612 int yabove = flat ? 8 : h - 1;
01613 Image_buffer8 img(w, h);
01614 img.fill8(1);
01615 img.fill8(2, w - 2, h - 2, 1, 1);
01616
01617 img.fill8(255, w/2, h/2, w/4, h/4);
01618 for (int i = 0; i < nframes; i++)
01619 shape->add_frame(new Shape_frame(img.get_bits(),
01620 w, h, xleft, yabove, !flat), i);
01621 }
01622 file_info->set_modified();
01623 Object_browser *browser = studio->get_browser();
01624 if (browser)
01625 {
01626 browser->render();
01627 browser->show();
01628 }
01629 studio->update_group_windows(0);
01630 }
01631
01632
01633
01634
01635
01636 void Shape_chooser::del_frame
01637 (
01638 )
01639 {
01640 if (selected < 0)
01641 return;
01642 int shnum = info[selected].shapenum,
01643 frnum = info[selected].framenum;
01644 Vga_file *ifile = file_info->get_ifile();
01645
01646 Shape *shape = ifile->extract_shape(shnum);
01647 if (!shape ||
01648 frnum > shape->get_num_frames() - 1)
01649 return;
01650
01651 if (!ifile->is_flex() && shape->get_num_frames() == 1)
01652 return;
01653 shape->del_frame(frnum);
01654 file_info->set_modified();
01655 ExultStudio *studio = ExultStudio::get_instance();
01656 Object_browser *browser = studio->get_browser();
01657 if (browser)
01658 {
01659 browser->render();
01660 browser->show();
01661 }
01662 studio->update_group_windows(0);
01663 }
01664
01665
01666
01667
01668
01669 void Shape_chooser::drag_data_get
01670 (
01671 GtkWidget *widget,
01672 GdkDragContext *context,
01673 GtkSelectionData *seldata,
01674 guint info,
01675 guint time,
01676 gpointer data
01677 )
01678 {
01679 cout << "In DRAG_DATA_GET" << endl;
01680 Shape_chooser *chooser = (Shape_chooser *) data;
01681 if (chooser->selected < 0 || info != U7_TARGET_SHAPEID)
01682 return;
01683 guchar buf[30];
01684 int file = chooser->ifile->get_u7drag_type();
01685 if (file == U7_SHAPE_UNK)
01686 U7_SHAPE_SHAPES;
01687 Shape_entry& shinfo = chooser->info[chooser->selected];
01688 int len = Store_u7_shapeid(buf, file, shinfo.shapenum,
01689 shinfo.framenum);
01690 cout << "Setting selection data (" << shinfo.shapenum <<
01691 '/' << shinfo.framenum << ')' << endl;
01692 #ifdef WIN32
01693 windragdata *wdata = (windragdata *)seldata;
01694 wdata->assign(info, len, buf);
01695 #else
01696
01697 gtk_selection_owner_set(widget, gdk_atom_intern("XdndSelection", 0),
01698 time);
01699
01700 gtk_selection_data_set(seldata,
01701 gdk_atom_intern(U7_TARGET_SHAPEID_NAME, 0),
01702 8, buf, len);
01703 #endif
01704 }
01705
01706
01707
01708
01709
01710 gint Shape_chooser::selection_clear
01711 (
01712 GtkWidget *widget,
01713 GdkEventSelection *event,
01714 gpointer data
01715 )
01716 {
01717
01718 cout << "SELECTION_CLEAR" << endl;
01719 return TRUE;
01720 }
01721
01722
01723
01724
01725
01726 gint Shape_chooser::drag_begin
01727 (
01728 GtkWidget *widget,
01729 GdkDragContext *context,
01730 gpointer data
01731 )
01732 {
01733 cout << "In DRAG_BEGIN" << endl;
01734 Shape_chooser *chooser = (Shape_chooser *) data;
01735 if (chooser->selected < 0)
01736 return FALSE;
01737
01738 Shape_entry& shinfo = chooser->info[chooser->selected];
01739 Shape_frame *shape = chooser->ifile->get_shape(shinfo.shapenum,
01740 shinfo.framenum);
01741 if (!shape)
01742 return FALSE;
01743 chooser->set_drag_icon(context, shape);
01744 return TRUE;
01745 }
01746
01747
01748
01749
01750
01751 void Shape_chooser::scroll_vertical
01752 (
01753 int newindex
01754 )
01755 {
01756
01757 if (newindex < row_indices.size())
01758 {
01759 index0 = row_indices[newindex];
01760 row0 = newindex;
01761 }
01762 else
01763 {
01764 row0 = row_indices.size() - 1;
01765 int index = row_indices[row0];
01766 while (row0 < newindex && (index = next_row(index)) >= 0)
01767 {
01768 index0 = index;
01769 row0++;
01770 row_indices.push_back(index);
01771 }
01772 }
01773 int total = get_count();
01774 render();
01775 show();
01776 }
01777
01778
01779
01780
01781
01782 void Shape_chooser::adjust_vscrollbar
01783 (
01784 )
01785 {
01786 GtkAdjustment *adj = gtk_range_get_adjustment(
01787 GTK_RANGE(vscroll));
01788 int known_rows = row_indices.size() - 1;
01789 float num_per_row = known_rows > 0 ?
01790 ((float) row_indices[known_rows])/known_rows : 1;
01791
01792 adj->upper = 1 + get_count()/num_per_row;
01793 adj->step_increment = 1;
01794 adj->page_increment = nrows;
01795 adj->page_size = nrows;
01796 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
01797 }
01798
01799
01800
01801
01802
01803 void Shape_chooser::adjust_hscrollbar
01804 (
01805 int newmax
01806 )
01807 {
01808 GtkAdjustment *adj = gtk_range_get_adjustment(
01809 GTK_RANGE(hscroll));
01810 if (newmax > 0)
01811 adj->upper = newmax;
01812 adj->page_increment = draw->allocation.width;
01813 adj->page_size = draw->allocation.width;
01814 if (adj->page_size > adj->upper)
01815 adj->upper = adj->page_size;
01816 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
01817 }
01818
01819
01820
01821
01822
01823 void Shape_chooser::vscrolled
01824 (
01825 GtkAdjustment *adj,
01826 gpointer data
01827 )
01828 {
01829 Shape_chooser *chooser = (Shape_chooser *) data;
01830 cout << "Scrolled to " << adj->value << '\n';
01831 gint newindex = (gint) adj->value;
01832 chooser->scroll_vertical(newindex);
01833 }
01834 void Shape_chooser::hscrolled
01835 (
01836 GtkAdjustment *adj,
01837 gpointer data
01838 )
01839 {
01840 Shape_chooser *chooser = (Shape_chooser *) data;
01841 chooser->hoffset = (gint) adj->value;
01842 chooser->render_frames();
01843 chooser->show();
01844 }
01845
01846
01847
01848
01849
01850 void Shape_chooser::frame_changed
01851 (
01852 GtkAdjustment *adj,
01853 gpointer data
01854 )
01855 {
01856 Shape_chooser *chooser = (Shape_chooser *) data;
01857 gint newframe = (gint) adj->value;
01858 if (chooser->selected >= 0)
01859 {
01860 Shape_entry& shinfo = chooser->info[chooser->selected];
01861 int nframes = chooser->ifile->get_num_frames(shinfo.shapenum);
01862 if (newframe >= nframes)
01863 return;
01864 shinfo.framenum = newframe;
01865 if (chooser->frames_mode)
01866 chooser->scroll_to_frame();
01867 chooser->render();
01868 chooser->show();
01869 }
01870 }
01871
01872
01873
01874
01875
01876 void Shape_chooser::all_frames_toggled
01877 (
01878 GtkToggleButton *btn,
01879 gpointer data
01880 )
01881 {
01882 Shape_chooser *chooser = (Shape_chooser *) data;
01883 bool on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn));
01884 chooser->frames_mode = on;
01885 if (on)
01886 gtk_widget_show(chooser->hscroll);
01887 else
01888 gtk_widget_hide(chooser->hscroll);
01889 chooser->row_indices.resize(1);
01890 chooser->row0 = 0;
01891 chooser->info_cnt = 0;
01892
01893 int indx = chooser->selected >= 0 ?
01894 chooser->info[chooser->selected].index : chooser->index0;
01895 chooser->index0 = 0;
01896 chooser->goto_index(indx);
01897
01898
01899 }
01900
01901
01902
01903
01904
01905 void Shape_chooser::on_shapes_popup_info_activate
01906 (
01907 GtkMenuItem *item,
01908 gpointer udata
01909 )
01910 {
01911 ((Shape_chooser *) udata)->edit_shape_info();
01912 }
01913
01914 void Shape_chooser::on_shapes_popup_edit_activate
01915 (
01916 GtkMenuItem *item,
01917 gpointer udata
01918 )
01919 {
01920 ((Shape_chooser *) udata)->edit_shape();
01921 }
01922
01923 void Shape_chooser::on_shapes_popup_edtiles_activate
01924 (
01925 GtkMenuItem *item,
01926 gpointer udata
01927 )
01928 {
01929 Shape_chooser *ch = (Shape_chooser *) udata;
01930 if (ch->selected < 0)
01931 return;
01932 ExultStudio *studio = ExultStudio::get_instance();
01933 GladeXML *xml = studio->get_xml();
01934 GtkWidget *win = glade_xml_get_widget(xml, "export_tiles_window");
01935 gtk_window_set_modal(GTK_WINDOW(win), true);
01936 gtk_object_set_user_data(GTK_OBJECT(win), ch);
01937
01938 int shnum = ch->info[ch->selected].shapenum;
01939 Vga_file *ifile = ch->file_info->get_ifile();
01940 int nframes = ifile->get_num_frames(shnum);
01941 GtkWidget *spin = glade_xml_get_widget(xml, "export_tiles_count");
01942 GtkAdjustment *adj = gtk_spin_button_get_adjustment(
01943 GTK_SPIN_BUTTON(spin));
01944 adj->lower = 1;
01945 adj->upper = nframes;
01946 gtk_adjustment_changed(adj);
01947 gtk_widget_show(win);
01948 }
01949
01950 static void on_shapes_popup_import
01951 (
01952 GtkMenuItem *item,
01953 gpointer udata
01954 )
01955 {
01956 GtkFileSelection *fsel = Create_file_selection(
01957 "Import frame from a .png file",
01958 (File_sel_okay_fun) Shape_chooser::import_frame,
01959 udata);
01960 gtk_widget_show(GTK_WIDGET(fsel));
01961 }
01962 static void on_shapes_popup_export
01963 (
01964 GtkMenuItem *item,
01965 gpointer udata
01966 )
01967 {
01968 GtkFileSelection *fsel = Create_file_selection(
01969 "Export frame to a .png file",
01970 (File_sel_okay_fun) Shape_chooser::export_frame,
01971 udata);
01972 gtk_widget_show(GTK_WIDGET(fsel));
01973 }
01974 static void on_shapes_popup_new_frame
01975 (
01976 GtkMenuItem *item,
01977 gpointer udata
01978 )
01979 {
01980 ((Shape_chooser *) udata)->new_frame();
01981 }
01982 static void on_shapes_popup_new_shape
01983 (
01984 GtkMenuItem *item,
01985 gpointer udata
01986 )
01987 {
01988 ((Shape_chooser *) udata)->new_shape();
01989 }
01990
01991
01992
01993
01994 C_EXPORT void
01995 on_export_tiles_okay_clicked (GtkButton *button,
01996 gpointer user_data)
01997 {
01998 GtkWidget *win = gtk_widget_get_toplevel(GTK_WIDGET(button));
01999 Shape_chooser *chooser = (Shape_chooser *)
02000 gtk_object_get_user_data(GTK_OBJECT(win));
02001 ExultStudio *studio = ExultStudio::get_instance();
02002 int tiles = studio->get_spin("export_tiles_count");
02003 bool bycol = studio->get_toggle("tiled_by_columns");
02004 chooser->edit_shape(tiles, bycol);
02005 gtk_widget_hide(win);
02006 }
02007
02008
02009
02010
02011
02012 void Shape_chooser::shape_dropped_here
02013 (
02014 int file,
02015 int shape,
02016 int frame
02017 )
02018 {
02019
02020 if (ifile->get_u7drag_type() == file && group != 0)
02021 {
02022 group->add(shape);
02023
02024 ExultStudio::get_instance()->update_group_windows(group);
02025 }
02026 }
02027
02028
02029
02030
02031
02032 int Shape_chooser::get_count
02033 (
02034 )
02035 {
02036 return group ? group->size() : ifile->get_num_shapes();
02037 }
02038
02039
02040
02041
02042
02043 void Shape_chooser::search
02044 (
02045 const char *srch,
02046 int dir
02047 )
02048 {
02049 if (!shapes_file)
02050 return;
02051 int total = get_count();
02052 if (!total)
02053 return;
02054 ExultStudio *studio = ExultStudio::get_instance();
02055
02056 int start = selected >= 0 ? info[selected].index : index0;
02057 int i;
02058 start += dir;
02059 int stop = dir == -1 ? -1 : total;
02060 for (i = start; i != stop; i += dir)
02061 {
02062 int shnum = group ? (*group)[i] : i;
02063 char *nm = studio->get_shape_name(shnum);
02064 if (nm && search_name(nm, srch))
02065 break;
02066 }
02067 if (i == stop)
02068 return;
02069 goto_index(i);
02070 int newsel;
02071 if (!frames_mode)
02072 newsel = i - row_indices[row0];
02073 else
02074 {
02075 int shnum = group ? (*group)[i] : i;
02076 for (newsel = 0; newsel < info_cnt &&
02077 info[newsel].shapenum != shnum; newsel++)
02078 ;
02079 }
02080 if (newsel >= 0 && newsel < info_cnt)
02081 select(newsel);
02082 show();
02083 }
02084
02085
02086
02087
02088
02089 void Shape_chooser::locate
02090 (
02091 bool upwards
02092 )
02093 {
02094 if (selected < 0)
02095 return;
02096 unsigned char data[Exult_server::maxlength];
02097 unsigned char *ptr = &data[0];
02098 Write2(ptr, info[selected].shapenum);
02099 *ptr++ = upwards ? 1 : 0;
02100 ExultStudio *studio = ExultStudio::get_instance();
02101 studio->send_to_server(
02102 Exult_server::locate_shape, data, ptr - data);
02103 }
02104
02105
02106
02107
02108
02109 GtkWidget *Shape_chooser::create_popup
02110 (
02111 )
02112 {
02113 ExultStudio *studio = ExultStudio::get_instance();
02114 Object_browser::create_popup();
02115 if (selected >= 0)
02116 {
02117 Add_menu_item(popup, "Info...",
02118 GTK_SIGNAL_FUNC(on_shapes_popup_info_activate), this);
02119 if (studio->get_image_editor())
02120 {
02121 Add_menu_item(popup, "Edit...",
02122 GTK_SIGNAL_FUNC(on_shapes_popup_edit_activate),
02123 this);
02124 if (info[selected].shapenum < 0x96 &&
02125 file_info == studio->get_vgafile())
02126 Add_menu_item(popup, "Edit tiled...",
02127 GTK_SIGNAL_FUNC(
02128 on_shapes_popup_edtiles_activate), this);
02129 }
02130
02131 Add_menu_item(popup);
02132
02133 Add_menu_item(popup, "New frame",
02134 GTK_SIGNAL_FUNC(on_shapes_popup_new_frame), this);
02135
02136 Add_menu_item(popup, "Export frame...",
02137 GTK_SIGNAL_FUNC(on_shapes_popup_export), this);
02138 Add_menu_item(popup, "Import frame...",
02139 GTK_SIGNAL_FUNC(on_shapes_popup_import), this);
02140 }
02141 if (ifile->is_flex())
02142 {
02143
02144 Add_menu_item(popup);
02145 Add_menu_item(popup, "New shape",
02146 GTK_SIGNAL_FUNC(on_shapes_popup_new_shape), this);
02147 }
02148 return popup;
02149 }
02150
02151
02152
02153
02154
02155 Shape_chooser::Shape_chooser
02156 (
02157 Vga_file *i,
02158 unsigned char *palbuf,
02159 int w, int h,
02160 Shape_group *g,
02161 Shape_file_info *fi
02162 ) : Object_browser(g, fi),
02163 Shape_draw(i, palbuf, gtk_drawing_area_new()),
02164 shapes_file(0), framenum0(0),
02165 info(0), info_cnt(0), row0(0), nrows(0),
02166 sel_changed(0), frames_mode(false), hoffset(0)
02167 {
02168 row_indices.reserve(40);
02169 row_indices.push_back(0);
02170
02171 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
02172 set_widget(vbox);
02173 gtk_widget_show(vbox);
02174
02175 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
02176 gtk_widget_show(hbox);
02177 gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
02178
02179
02180 GtkWidget *frame = gtk_frame_new(NULL);
02181 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
02182 gtk_widget_show(frame);
02183 gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, TRUE, 0);
02184
02185
02186 gtk_widget_set_events(draw, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
02187 | GDK_BUTTON_RELEASE_MASK
02188 | GDK_POINTER_MOTION_HINT_MASK |
02189 GDK_BUTTON1_MOTION_MASK | GDK_KEY_PRESS_MASK);
02190
02191 gtk_signal_connect(GTK_OBJECT(draw), "configure_event",
02192 GTK_SIGNAL_FUNC(Configure_chooser), this);
02193
02194 gtk_signal_connect(GTK_OBJECT(draw), "expose_event",
02195 GTK_SIGNAL_FUNC(expose), this);
02196
02197 gtk_signal_connect(GTK_OBJECT(draw), "key-press-event",
02198 GTK_SIGNAL_FUNC (on_draw_key_press),
02199 this);
02200 GTK_WIDGET_SET_FLAGS(draw, GTK_CAN_FOCUS);
02201
02202 gtk_signal_connect(GTK_OBJECT(draw), "button_press_event",
02203 GTK_SIGNAL_FUNC(Mouse_press), this);
02204 gtk_signal_connect(GTK_OBJECT(draw), "button_release_event",
02205 GTK_SIGNAL_FUNC(Mouse_release), this);
02206
02207 gtk_signal_connect(GTK_OBJECT(draw), "drag_begin",
02208 GTK_SIGNAL_FUNC(drag_begin), this);
02209 #ifdef WIN32
02210
02211 gtk_signal_connect(GTK_OBJECT(draw), "motion_notify_event",
02212 GTK_SIGNAL_FUNC(win32_drag_motion), this);
02213 #else
02214 gtk_signal_connect(GTK_OBJECT(draw), "motion_notify_event",
02215 GTK_SIGNAL_FUNC(drag_motion), this);
02216 #endif
02217
02218
02219 gtk_signal_connect (GTK_OBJECT(draw), "drag_data_get",
02220 GTK_SIGNAL_FUNC(drag_data_get), this);
02221 gtk_signal_connect (GTK_OBJECT(draw), "selection_clear_event",
02222 GTK_SIGNAL_FUNC(selection_clear), this);
02223 gtk_container_add (GTK_CONTAINER (frame), draw);
02224 gtk_drawing_area_size(GTK_DRAWING_AREA(draw), w, h);
02225 gtk_widget_show(draw);
02226
02227 GtkObject *shape_adj = gtk_adjustment_new(0, 0,
02228 get_count()/4, 1, 1, 1);
02229 vscroll = gtk_vscrollbar_new(GTK_ADJUSTMENT(shape_adj));
02230
02231 gtk_range_set_update_policy(GTK_RANGE(vscroll),
02232 GTK_UPDATE_DELAYED);
02233 gtk_box_pack_start(GTK_BOX(hbox), vscroll, FALSE, TRUE, 0);
02234
02235 gtk_signal_connect(GTK_OBJECT(shape_adj), "value_changed",
02236 GTK_SIGNAL_FUNC(vscrolled), this);
02237 gtk_widget_show(vscroll);
02238
02239 shape_adj = gtk_adjustment_new(0, 0, 1600, 8, 16, 16);
02240 hscroll = gtk_hscrollbar_new(GTK_ADJUSTMENT(shape_adj));
02241
02242 gtk_range_set_update_policy(GTK_RANGE(hscroll),
02243 GTK_UPDATE_DELAYED);
02244 gtk_box_pack_start(GTK_BOX(vbox), hscroll, FALSE, TRUE, 0);
02245
02246 gtk_signal_connect(GTK_OBJECT(shape_adj), "value_changed",
02247 GTK_SIGNAL_FUNC(hscrolled), this);
02248
02249
02250 GtkWidget *hbox1 = gtk_hbox_new(FALSE, 0);
02251 gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0);
02252 gtk_widget_show(hbox1);
02253
02254 sbar = gtk_statusbar_new();
02255 sbar_sel = gtk_statusbar_get_context_id(GTK_STATUSBAR(sbar),
02256 "selection");
02257 gtk_box_pack_start(GTK_BOX(hbox1), sbar, TRUE, TRUE, 0);
02258 gtk_widget_show(sbar);
02259 GtkWidget *label = gtk_label_new("Frame:");
02260 gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 4);
02261 gtk_widget_show(label);
02262
02263 frame_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0,
02264 16, 1,
02265 4, 1.0));
02266 fspin = gtk_spin_button_new(GTK_ADJUSTMENT(frame_adj),
02267 1, 0);
02268 gtk_signal_connect(GTK_OBJECT(frame_adj), "value_changed",
02269 GTK_SIGNAL_FUNC(frame_changed), this);
02270 gtk_box_pack_start(GTK_BOX(hbox1), fspin, FALSE, FALSE, 0);
02271 gtk_widget_show(fspin);
02272
02273 GtkWidget *allframes = gtk_toggle_button_new_with_label("Frames");
02274 gtk_box_pack_start(GTK_BOX(hbox1), allframes, FALSE, FALSE, 4);
02275 gtk_widget_show(allframes);
02276 gtk_signal_connect(GTK_OBJECT(allframes), "toggled",
02277 GTK_SIGNAL_FUNC(all_frames_toggled), this);
02278
02279 gtk_box_pack_start(GTK_BOX(vbox),
02280 create_controls(find_controls | locate_controls),
02281 FALSE, FALSE, 0);
02282 }
02283
02284
02285
02286
02287
02288 Shape_chooser::~Shape_chooser
02289 (
02290 )
02291 {
02292 gtk_widget_destroy(get_widget());
02293 delete [] info;
02294 }
02295
02296
02297
02298
02299
02300 void Shape_chooser::unselect
02301 (
02302 bool need_render
02303 )
02304 {
02305 if (selected >= 0)
02306 {
02307 selected = -1;
02308
02309 gtk_adjustment_set_value(frame_adj, 0);
02310 gtk_widget_set_sensitive(fspin, false);
02311 if (need_render)
02312 {
02313 render();
02314 show();
02315 }
02316 if (sel_changed)
02317 (*sel_changed)();
02318 }
02319 char buf[150];
02320 if (info_cnt > 0)
02321 {
02322
02323 g_snprintf(buf, sizeof(buf), "Shapes %d to %d",
02324 info[0].shapenum, info[info_cnt - 1].shapenum);
02325 gtk_statusbar_push(GTK_STATUSBAR(sbar), sbar_sel, buf);
02326 }
02327 }
02328
02329