paledit.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2000 The Exult Team
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include <gtk/gtk.h>
00030 #ifdef XWIN
00031 #include <gdk/gdkx.h>
00032 #endif
00033 #include <glib.h>
00034 #include "paledit.h"
00035 #include "u7drag.h"
00036 #include "utils.h"
00037 #include <iostream>
00038 #include <iomanip>
00039 #include <ctype.h>
00040 #include <stdio.h>
00041 #include "studio.h"
00042 #include "shapefile.h"
00043 
00044 using std::cout;
00045 using std::endl;
00046 using std::string;
00047 using std::vector;
00048 using std::ostream;
00049 using std::ofstream;
00050 using std::setw;
00051 using std::ifstream;
00052 using EStudio::Prompt;
00053 using EStudio::Alert;
00054 
00055 /*
00056  *  Write out a single palette to a buffer.
00057  */
00058 
00059 static void Write_palette
00060   (
00061   unsigned char *buf,   // 3*256 bytes.
00062   GdkRgbCmap *pal     // Palette to write.
00063   )
00064   {
00065   for (int i = 0; i < 256; i++)
00066     {
00067     int r = (pal->colors[i]>>16)&255,
00068         g = (pal->colors[i]>>8)&255,
00069         b = pal->colors[i]&255;
00070     buf[3*i] = r/4;   // Range 0-63.
00071     buf[3*i + 1] = g/4;
00072     buf[3*i + 2] = b/4;
00073     }
00074   }
00075 
00076 /*
00077  *  Blit onto screen.
00078  */
00079 
00080 inline void Palette_edit::show
00081   (
00082   int x, int y, int w, int h  // Area to blit.
00083   )
00084   {
00085   int stride = draw->allocation.width;
00086   gdk_draw_indexed_image(draw->window, drawgc, x, y, w, h,
00087       GDK_RGB_DITHER_NORMAL,
00088       image + y*stride + x, 
00089       stride, palettes[cur_pal]);
00090   if (selected >= 0)    // Show selected.
00091           // Draw yellow box.
00092     gdk_draw_rectangle(draw->window, drawgc, FALSE, 
00093       selected_box.x, selected_box.y,
00094       selected_box.w, selected_box.h);
00095   }
00096 
00097 /*
00098  *  Select an entry.  This should be called after rendering
00099  *  the shape.
00100  */
00101 
00102 void Palette_edit::select
00103   (
00104   int new_sel
00105   )
00106   {
00107   selected = new_sel;
00108           // Remove prev. selection msg.
00109   gtk_statusbar_pop(GTK_STATUSBAR(sbar), sbar_sel);
00110   char buf[150];      // Show new selection.
00111   g_snprintf(buf, sizeof(buf), "Color %d (0x%02x)", new_sel, new_sel);
00112   gtk_statusbar_push(GTK_STATUSBAR(sbar), sbar_sel, buf);
00113   }
00114 
00115 /*
00116  *  Load/reload from file.
00117  */
00118 
00119 void Palette_edit::load
00120   (
00121   )
00122   {
00123           // Free old.
00124   for (vector<GdkRgbCmap*>::iterator it = palettes.begin();
00125           it != palettes.end(); ++it)
00126     gdk_rgb_cmap_free(*it);
00127   int cnt = flex_info->size();
00128   palettes.resize(cnt);   // Set size of list.
00129   if (!cnt)     // No palettes?
00130     new_palette();    // Create 1 blank palette.
00131   else
00132     {
00133     for (int pnum = 0; pnum < cnt; pnum++)
00134       {
00135       size_t len;
00136       unsigned char *buf = (unsigned char *)
00137             flex_info->get(pnum, len);
00138       assert(len = 3*256);
00139       guint32 colors[256];
00140       for (int i = 0; i < 256; i++)
00141         colors[i] = (buf[3*i]<<16)*4 + 
00142           (buf[3*i+1]<<8)*4 + buf[3*i+2]*4;
00143       palettes[pnum] = gdk_rgb_cmap_new(colors, 256);
00144       }
00145     }
00146   }
00147 
00148 /*
00149  *  Draw the palette.  This need only be called when it changes.
00150  */
00151 
00152 void Palette_edit::render
00153   (
00154   )
00155   {
00156   int neww = draw->allocation.width, newh = draw->allocation.height;
00157           // Changed size?
00158   if (neww != width || newh != height)
00159     {
00160     delete image;
00161     width = neww;
00162     height = newh;
00163     image = new guchar[width*height];
00164     }
00165           // Figure cell size.
00166   int eachw = width/16, eachh = height/16;
00167           // Figure extra pixels.
00168   int extraw = width%16, extrah = height%16;
00169   int color = 0;      // Color index.
00170   int cury = 0;
00171   unsigned char *out = image;
00172   for (int y = 0; y < 16; y++, color += 16)
00173     {
00174     int curx = 0;
00175     int stopy = cury + eachh + (y < extrah);
00176     for ( ; cury < stopy; cury++)
00177       for (int x = 0, c = color; x < 16; x++, c++)
00178         {
00179         int cntx = eachw + (x < extraw);
00180         while (cntx--)
00181           *out++ = c;
00182         }
00183     }
00184   if (selected >= 0)    // Update selected box.
00185     {
00186     int selx = selected%16, sely = selected/16;
00187     selected_box.x = selx*eachw;
00188     selected_box.y = sely*eachh;
00189     selected_box.w = eachw;
00190     selected_box.h = eachh;
00191     if (selx < extraw)  // Watch for extra pixels.
00192       { selected_box.w++; selected_box.x += selx; }
00193     else
00194       selected_box.x += extraw;
00195     if (sely < extrah)
00196       { selected_box.h++; selected_box.y += sely; }
00197     else
00198       selected_box.y += extrah;
00199     select(selected);
00200     }
00201   }
00202 
00203 /*
00204  *  Color box was closed.
00205  */
00206 
00207 int Palette_edit::color_closed
00208   (
00209   GtkWidget *dlg,
00210   GdkEvent *event,
00211   gpointer data
00212   )
00213   {
00214   cout << "color_closed" << endl;
00215   Palette_edit *paled = (Palette_edit *) data;
00216   paled->colorsel = 0;
00217   return FALSE;
00218   }
00219 
00220 /*
00221  *  'Cancel' was hit in the color selector.
00222  */
00223 
00224 void Palette_edit::color_cancel
00225   (
00226   GtkWidget *dlg,
00227   gpointer data
00228   )
00229   {
00230   Palette_edit *paled = (Palette_edit *) data;
00231   if (paled->colorsel)
00232     gtk_widget_destroy(GTK_WIDGET(paled->colorsel));
00233   paled->colorsel = 0;
00234   }
00235 
00236 /*
00237  *  'Okay' was hit in the color selector.
00238  */
00239 
00240 void Palette_edit::color_okay
00241   (
00242   GtkWidget *dlg,
00243   gpointer data
00244   )
00245   {
00246   Palette_edit *paled = (Palette_edit *) data;
00247   if (paled->colorsel)
00248     {
00249     gdouble rgb[3];
00250     gtk_color_selection_get_color(
00251       GTK_COLOR_SELECTION(paled->colorsel->colorsel), rgb);
00252     unsigned char r = (unsigned char) (rgb[0]*256),
00253             g = (unsigned char) (rgb[1]*256),
00254             b = (unsigned char) (rgb[2]*256);
00255     if (paled->selected >= 0)
00256       paled->palettes[paled->cur_pal]->colors[
00257               paled->selected] = 
00258               (r<<16) + (g<<8) + b;
00259     gtk_widget_destroy(GTK_WIDGET(paled->colorsel));
00260           // Send to flex file.
00261     paled->update_flex(paled->cur_pal);
00262     paled->render();
00263     paled->show();
00264     }
00265   paled->colorsel = 0;
00266   }
00267 
00268 /*
00269  *  Handle double-click on a color by bringing up a color-selector.
00270  */
00271 
00272 void Palette_edit::double_clicked
00273   (
00274   )
00275   {
00276   cout << "Double-clicked" << endl;
00277   if (selected < 0 || colorsel) // Only one at a time.
00278     return;     // Nothing selected.
00279   char buf[150];      // Show new selection.
00280   g_snprintf(buf, sizeof(buf), "Color %d (0x%02x)", selected, selected);
00281   colorsel = GTK_COLOR_SELECTION_DIALOG(
00282           gtk_color_selection_dialog_new(buf));
00283           // Set mouse click handler.
00284   gtk_signal_connect(GTK_OBJECT(colorsel->ok_button), "clicked",
00285         GTK_SIGNAL_FUNC(color_okay), this);
00286   gtk_signal_connect(GTK_OBJECT(colorsel->cancel_button), "clicked",
00287         GTK_SIGNAL_FUNC(color_cancel), this);
00288           // Set delete handler.
00289   gtk_signal_connect(GTK_OBJECT(colorsel), "delete_event",
00290         GTK_SIGNAL_FUNC(color_closed), this);
00291           // Get color.
00292   guint32 c = palettes[cur_pal]->colors[selected];
00293   gdouble rgb[3];
00294   rgb[0] = ((double) ((c>>16)&0xff))/256;
00295   rgb[1] = ((double) ((c>>8)&0xff))/256;
00296   rgb[2] = ((double) ((c>>0)&0xff))/256;
00297   gtk_color_selection_set_color(GTK_COLOR_SELECTION(colorsel->colorsel),
00298                 rgb);
00299   gtk_widget_show(GTK_WIDGET(colorsel));
00300   }
00301 
00302 /*
00303  *  Configure the viewing window.
00304  */
00305 
00306 gint Palette_edit::configure
00307   (
00308   GtkWidget *widget,    // The view window.
00309   GdkEventConfigure *event,
00310   gpointer data     // ->Palette_edit
00311   )
00312   {
00313   Palette_edit *paled = (Palette_edit *) data;
00314   if (!paled->width)    // First time?
00315     {
00316     paled->drawgc = gdk_gc_new(widget->window);
00317           // Foreground = yellow.
00318     gdk_rgb_gc_set_foreground(paled->drawgc,
00319               (255<<16) + (255<<8));
00320     }
00321   paled->render();
00322   return (TRUE);
00323   }
00324 
00325 /*
00326  *  Handle an expose event.
00327  */
00328 
00329 gint Palette_edit::expose
00330   (
00331   GtkWidget *widget,    // The view window.
00332   GdkEventExpose *event,
00333   gpointer data     // ->Palette_edit.
00334   )
00335   {
00336   Palette_edit *paled = (Palette_edit *) data;
00337   paled->show(event->area.x, event->area.y, event->area.width,
00338               event->area.height);
00339   return (TRUE);
00340   }
00341 
00342 /*
00343  *  Handle a mouse button press event.
00344  */
00345 
00346 gint Palette_edit::mouse_press
00347   (
00348   GtkWidget *widget,    // The view window.
00349   GdkEventButton *event,
00350   gpointer data     // ->Palette_edit.
00351   )
00352   {
00353   Palette_edit *paled = (Palette_edit *) data;
00354 
00355     if (event->button == 4 || event->button == 5) // mouse wheel
00356         return (TRUE);
00357 
00358   if (paled->colorsel)
00359     return (TRUE);    // Already editing a color.
00360   int old_selected = paled->selected;
00361   int width = paled->width, height = paled->height;
00362   int eventx = (int) event->x, eventy = (int) event->y;
00363           // Figure cell size.
00364   int eachw = width/16, eachh = height/16;
00365           // Figure extra pixels.
00366   int extraw = width%16, extrah = height%16;
00367   int extrax = extraw*(eachw + 1);// Total length of extra-sized boxes.
00368   int extray = extrah*(eachh + 1);
00369   int selx, sely;     // Gets box indices.
00370   if (eventx < extrax)
00371     selx = eventx/(eachw + 1);
00372   else
00373     selx = extraw + (eventx - extrax)/eachw;
00374   if (eventy < extray)
00375     sely = eventy/(eachh + 1);
00376   else
00377     sely = extrah + (eventy - extray)/eachh;
00378   paled->selected = sely*16 + selx;
00379   if (paled->selected == old_selected)
00380     {     // Same square.  Check for dbl-click.
00381     if (((GdkEvent *) event)->type == GDK_2BUTTON_PRESS)
00382       paled->double_clicked();
00383     }
00384   else
00385     {
00386     paled->render();
00387     paled->show();
00388     }
00389   if (event->button == 3)
00390     gtk_menu_popup(GTK_MENU(paled->create_popup()), 
00391         0, 0, 0, 0, event->button, event->time);
00392   return (TRUE);
00393   }
00394 
00395 /*
00396  *  Someone wants the dragged shape.
00397  */
00398 
00399 void Palette_edit::drag_data_get
00400   (
00401   GtkWidget *widget,    // The view window.
00402   GdkDragContext *context,
00403   GtkSelectionData *seldata,  // Fill this in.
00404   guint info,
00405   guint time,
00406   gpointer data     // ->Palette_edit.
00407   )
00408   {
00409   cout << "In DRAG_DATA_GET" << endl;
00410   Palette_edit *paled = (Palette_edit *) data;
00411 #if 0
00412   if (paled->selected < 0 || info != U7_TARGET_SHAPEID)
00413     return;     // Not sure about this.
00414   guchar buf[30];
00415   int file = U7_SHAPE_SHAPES; // +++++For now.
00416   Shape_info& shinfo = paled->info[paled->selected];
00417   int len = Store_u7_shapeid(buf, file, shinfo.shapenum, 
00418               shinfo.framenum);
00419   cout << "Setting selection data (" << shinfo.shapenum <<
00420       '/' << shinfo.framenum << ')' << endl;
00421           // Make us owner of xdndselection.
00422   gtk_selection_owner_set(widget, gdk_atom_intern("XdndSelection", 0),
00423                 time);
00424           // Set data.
00425   gtk_selection_data_set(seldata,
00426       gdk_atom_intern(U7_TARGET_SHAPEID_NAME, 0),
00427                                         8, buf, len);
00428 #endif
00429   }
00430 
00431 /*
00432  *  Another app. has claimed the selection.
00433  */
00434 
00435 gint Palette_edit::selection_clear
00436   (
00437   GtkWidget *widget,    // The view window.
00438   GdkEventSelection *event,
00439   gpointer data     // ->Palette_edit.
00440   )
00441   {
00442 //  Palette_edit *paled = (Palette_edit *) data;
00443   cout << "SELECTION_CLEAR" << endl;
00444   return TRUE;
00445   }
00446 
00447 /*
00448  *  Beginning of a drag.
00449  */
00450 
00451 gint Palette_edit::drag_begin
00452   (
00453   GtkWidget *widget,    // The view window.
00454   GdkDragContext *context,
00455   gpointer data     // ->Palette_edit.
00456   )
00457   {
00458   cout << "In DRAG_BEGIN" << endl;
00459   Palette_edit *paled = (Palette_edit *) data;
00460   // Maybe someday.
00461   return TRUE;
00462   }
00463 
00464 /*
00465  *  Handle a change to the 'Palette #' spin button.
00466  */
00467 
00468 void Palette_edit::palnum_changed
00469   (
00470   GtkAdjustment *adj,   // The adjustment.
00471   gpointer data     // ->Shape_chooser.
00472   )
00473   {
00474   Palette_edit *ed = (Palette_edit *) data;
00475   gint newnum = (gint) adj->value;
00476   ed->show_palette(newnum);
00477   ed->render();
00478   ed->show();
00479   ed->enable_controls();
00480   }
00481 
00482 /*
00483  *  Callbacks for buttons:
00484  */
00485 void
00486 on_exportbtn_clicked                   (GtkButton       *button,
00487                                         gpointer         user_data)
00488 {
00489   GtkFileSelection *fsel = Create_file_selection(
00490     "Export palette to text format", 
00491       (File_sel_okay_fun) Palette_edit::export_palette, 
00492               user_data);
00493   gtk_widget_show(GTK_WIDGET(fsel));
00494 }
00495 
00496 void
00497 on_importbtn_clicked                   (GtkButton       *button,
00498                                         gpointer         user_data)
00499 {
00500   GtkFileSelection *fsel = Create_file_selection(
00501     "Import palette from text format", 
00502       (File_sel_okay_fun) Palette_edit::import_palette, 
00503               user_data);
00504   gtk_widget_show(GTK_WIDGET(fsel));
00505 }
00506 
00507 void
00508 on_insert_btn_clicked                  (GtkButton       *button,
00509                                         gpointer         user_data)
00510 {
00511   Palette_edit *ed = (Palette_edit *) user_data;
00512   ed->add_palette();
00513 }
00514 void
00515 on_remove_btn_clicked                  (GtkButton       *button,
00516                                         gpointer         user_data)
00517 {
00518   Palette_edit *ed = (Palette_edit *) user_data;
00519   ed->remove_palette();
00520 }
00521 void
00522 on_up_btn_clicked                      (GtkButton       *button,
00523                                         gpointer         user_data)
00524 {
00525   Palette_edit *ed = (Palette_edit *) user_data;
00526   ed->move_palette(true);
00527 }
00528 void
00529 on_down_btn_clicked                  (GtkButton       *button,
00530                                         gpointer         user_data)
00531 {
00532   Palette_edit *ed = (Palette_edit *) user_data;
00533   ed->move_palette(false);
00534 }
00535 
00536 /*
00537  *  Create box with 'Palette #', 'Import', 'Move' controls.
00538  */
00539 
00540 GtkWidget *Palette_edit::create_controls
00541   (
00542   )
00543   {
00544           // Create main box.
00545   GtkWidget *topframe = gtk_frame_new (NULL);
00546   gtk_widget_show(topframe);
00547   GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
00548   gtk_widget_show(vbox);
00549   gtk_container_add (GTK_CONTAINER (topframe), vbox);
00550 
00551   GtkWidget *hbox0 = gtk_hbox_new(FALSE, 0);
00552   gtk_widget_show(hbox0);
00553   gtk_box_pack_start(GTK_BOX(vbox), hbox0, TRUE, TRUE, 2);
00554   /*
00555    *  The 'Edit' controls.
00556    */
00557   GtkWidget *frame = gtk_frame_new ("Edit");
00558   gtk_widget_show(frame);
00559   gtk_box_pack_start (GTK_BOX (hbox0), frame, FALSE, FALSE, 2);
00560   GtkWidget *hbuttonbox = gtk_hbutton_box_new ();
00561   gtk_widget_show (hbuttonbox);
00562   gtk_container_add (GTK_CONTAINER (frame), hbuttonbox);
00563   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), 
00564               GTK_BUTTONBOX_START);
00565   gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 0);
00566 
00567   insert_btn = gtk_button_new_with_label ("New");
00568   gtk_widget_show (insert_btn);
00569   gtk_container_add (GTK_CONTAINER (hbuttonbox), insert_btn);
00570   GTK_WIDGET_SET_FLAGS (insert_btn, GTK_CAN_DEFAULT);
00571 
00572   remove_btn = gtk_button_new_with_label ("Remove");
00573   gtk_widget_show (remove_btn);
00574   gtk_container_add (GTK_CONTAINER (hbuttonbox), remove_btn);
00575   GTK_WIDGET_SET_FLAGS (remove_btn, GTK_CAN_DEFAULT);
00576   gtk_signal_connect (GTK_OBJECT (insert_btn), "clicked",
00577       GTK_SIGNAL_FUNC (on_insert_btn_clicked),
00578       this);
00579   gtk_signal_connect (GTK_OBJECT (remove_btn), "clicked",
00580       GTK_SIGNAL_FUNC (on_remove_btn_clicked),
00581       this);
00582   /*
00583    *  The 'Move' controls.
00584    */
00585   frame = gtk_frame_new ("Move");
00586   gtk_widget_show(frame);
00587   gtk_box_pack_start (GTK_BOX (hbox0), frame, FALSE, FALSE, 2);
00588   GtkWidget *bbox = gtk_hbox_new(TRUE, 0);
00589   gtk_widget_show(bbox);
00590   gtk_container_add(GTK_CONTAINER (frame), bbox);
00591   down_btn = gtk_button_new();
00592   gtk_widget_show (down_btn);
00593   gtk_box_pack_start (GTK_BOX (bbox), down_btn, FALSE, FALSE, 0);
00594   GTK_WIDGET_SET_FLAGS (down_btn, GTK_CAN_DEFAULT);
00595   GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
00596   gtk_widget_show(arrow);
00597   gtk_container_add(GTK_CONTAINER(down_btn), arrow);
00598 
00599   up_btn = gtk_button_new();
00600   gtk_widget_show (up_btn);
00601   gtk_box_pack_start (GTK_BOX (bbox), up_btn, FALSE, FALSE, 0);
00602   GTK_WIDGET_SET_FLAGS (up_btn, GTK_CAN_DEFAULT);
00603   arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_OUT);
00604   gtk_widget_show(arrow);
00605   gtk_container_add(GTK_CONTAINER(up_btn), arrow);
00606   gtk_signal_connect (GTK_OBJECT (down_btn), "clicked",
00607       GTK_SIGNAL_FUNC (on_down_btn_clicked),
00608       this);
00609   gtk_signal_connect (GTK_OBJECT (up_btn), "clicked",
00610       GTK_SIGNAL_FUNC (on_up_btn_clicked),
00611       this);
00612   /*
00613    *  The 'File' controls.
00614    */
00615   frame = gtk_frame_new ("File");
00616   gtk_widget_show(frame);
00617   gtk_box_pack_start (GTK_BOX (hbox0), frame, FALSE, FALSE, 2);
00618   hbuttonbox = gtk_hbutton_box_new ();
00619   gtk_widget_show (hbuttonbox);
00620   gtk_container_add (GTK_CONTAINER (frame), hbuttonbox);
00621   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), 
00622               GTK_BUTTONBOX_START);
00623   gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 0);
00624 
00625   GtkWidget *importbtn = gtk_button_new_with_label ("Import");
00626   gtk_widget_show (importbtn);
00627   gtk_container_add (GTK_CONTAINER (hbuttonbox), importbtn);
00628   GTK_WIDGET_SET_FLAGS (importbtn, GTK_CAN_DEFAULT);
00629 
00630   GtkWidget *exportbtn = gtk_button_new_with_label ("Export");
00631   gtk_widget_show (exportbtn);
00632   gtk_container_add (GTK_CONTAINER (hbuttonbox), exportbtn);
00633   GTK_WIDGET_SET_FLAGS (exportbtn, GTK_CAN_DEFAULT);
00634   gtk_signal_connect (GTK_OBJECT (importbtn), "clicked",
00635       GTK_SIGNAL_FUNC (on_importbtn_clicked),
00636       this);
00637   gtk_signal_connect (GTK_OBJECT (exportbtn), "clicked",
00638       GTK_SIGNAL_FUNC (on_exportbtn_clicked),
00639       this);
00640   return topframe;
00641   }
00642 
00643 /*
00644  *  Enable/disable controls after changes.
00645  */
00646 
00647 void Palette_edit::enable_controls
00648   (
00649   )
00650   {
00651           // Can't delete last one.
00652   gtk_widget_set_sensitive(remove_btn, cur_pal >= 0 &&
00653           palettes.size() > 1);
00654   if (cur_pal == -1)    // No palette?
00655     {
00656     gtk_widget_set_sensitive(down_btn, false);
00657     gtk_widget_set_sensitive(up_btn, false);
00658     gtk_widget_set_sensitive(remove_btn, false);
00659     }
00660   else
00661     {
00662     gtk_widget_set_sensitive(down_btn,
00663           cur_pal < palettes.size() - 1);
00664     gtk_widget_set_sensitive(up_btn, cur_pal > 0);
00665     gtk_widget_set_sensitive(remove_btn, palettes.size() > 1);
00666     }
00667   }
00668 
00669 /*
00670  *  Set up box.
00671  */
00672 
00673 void Palette_edit::setup
00674   (
00675   )
00676   {
00677           // Put things in a vert. box.
00678   GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
00679   gtk_widget_show(vbox);
00680   set_widget(vbox);
00681           // A frame looks nice.
00682   GtkWidget *frame = gtk_frame_new(NULL);
00683   gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
00684   gtk_widget_show(frame);
00685   gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
00686   draw = gtk_drawing_area_new();  // Create drawing area window.
00687 //  gtk_drawing_area_size(GTK_DRAWING_AREA(draw), w, h);
00688           // Indicate the events we want.
00689   gtk_widget_set_events(draw, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
00690     | GDK_POINTER_MOTION_HINT_MASK |
00691     GDK_BUTTON1_MOTION_MASK);
00692           // Set "configure" handler.
00693   gtk_signal_connect(GTK_OBJECT(draw), "configure_event",
00694         GTK_SIGNAL_FUNC(configure), this);
00695           // Set "expose" handler.
00696   gtk_signal_connect(GTK_OBJECT(draw), "expose_event",
00697         GTK_SIGNAL_FUNC(expose), this);
00698           // Set mouse click handler.
00699   gtk_signal_connect(GTK_OBJECT(draw), "button_press_event",
00700         GTK_SIGNAL_FUNC(mouse_press), this);
00701           // Mouse motion.
00702   gtk_signal_connect(GTK_OBJECT(draw), "drag_begin",
00703         GTK_SIGNAL_FUNC(drag_begin), this);
00704   gtk_signal_connect (GTK_OBJECT(draw), "drag_data_get",
00705         GTK_SIGNAL_FUNC(drag_data_get), this);
00706   gtk_signal_connect (GTK_OBJECT(draw), "selection_clear_event",
00707         GTK_SIGNAL_FUNC(selection_clear), this);
00708   gtk_container_add (GTK_CONTAINER (frame), draw);
00709   gtk_widget_show(draw);
00710           // At bottom, a status bar.
00711   sbar = gtk_statusbar_new();
00712   sbar_sel = gtk_statusbar_get_context_id(GTK_STATUSBAR(sbar),
00713               "selection");
00714           // At the bottom, status bar & frame:
00715   GtkWidget *hbox1 = gtk_hbox_new(FALSE, 0);
00716   gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0);
00717   gtk_widget_show(hbox1);
00718   gtk_box_pack_start(GTK_BOX(hbox1), sbar, TRUE, TRUE, 0);
00719           // Palette # to right of sbar.
00720   GtkWidget *label = gtk_label_new("Palette #:");
00721   gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 4);
00722   gtk_widget_show(label);
00723           // A spin button for palette#.
00724   palnum_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 
00725         palettes.size() - 1, 1,
00726         2, 2));
00727   pspin = gtk_spin_button_new(palnum_adj, 1, 0);
00728   gtk_signal_connect(GTK_OBJECT(palnum_adj), "value_changed",
00729           GTK_SIGNAL_FUNC(palnum_changed), this);
00730   gtk_box_pack_start(GTK_BOX(hbox1), pspin, FALSE, FALSE, 0);
00731   gtk_widget_show(pspin);
00732 
00733           // Add edit controls to bottom.
00734   gtk_box_pack_start(GTK_BOX(vbox), create_controls(), FALSE, FALSE, 0);
00735   gtk_widget_show(sbar);
00736   enable_controls();
00737   }
00738 
00739 /*
00740  *  Create/add a new palette.
00741  */
00742 
00743 void Palette_edit::new_palette
00744   (
00745   )
00746   {
00747   guint32 colors[256];    // R, G, B, then all black.
00748   memset(&colors[0], 0, sizeof(colors));
00749   colors[0] = 255<<16;
00750   colors[1] = 255<<8;
00751   colors[2] = 255;
00752   GdkRgbCmap *newpal = gdk_rgb_cmap_new(colors, 256);
00753   int index = palettes.size();  // Index of new palette.
00754   palettes.push_back(newpal);
00755   update_flex(index);   // Add to file.
00756   }
00757 
00758 /*
00759  *  Update palette entry in flex file.
00760  */
00761 
00762 void Palette_edit::update_flex
00763   (
00764   int pnum      // Palette # to send to file.
00765   )
00766   {
00767   unsigned char *buf = new unsigned char[3*256];
00768   Write_palette(buf, palettes[pnum]);
00769           // Update or append file data.
00770   flex_info->set(pnum, (char *) buf, 3*256);
00771   flex_info->set_modified();
00772   }
00773 
00774 /*
00775  *  Create the list for a single palette.
00776  */
00777 
00778 Palette_edit::Palette_edit
00779   (
00780   Flex_file_info *flinfo    // Flex-file info.
00781   ) : Object_browser(0, flinfo),
00782     flex_info(flinfo), image(0), width(0), height(0),
00783     colorsel(0), cur_pal(0)
00784   {
00785   load();       // Load from file.
00786   setup();
00787   }
00788 
00789 /*
00790  *  Delete.
00791  */
00792 
00793 Palette_edit::~Palette_edit
00794   (
00795   )
00796   {
00797   for (vector<GdkRgbCmap*>::iterator it = palettes.begin();
00798           it != palettes.end(); ++it)
00799     gdk_rgb_cmap_free(*it);
00800   gtk_widget_destroy(get_widget());
00801   delete image;
00802   }
00803 
00804 /*
00805  *  Get i'th palette.
00806  */
00807 
00808 void Palette_edit::show_palette
00809   (
00810   int palnum
00811   )
00812   {
00813   cur_pal = palnum;
00814   }
00815 
00816 /*
00817  *  Unselect.
00818  */
00819 
00820 void Palette_edit::unselect
00821   (
00822   bool need_render      // 1 to render and show.
00823   )
00824   {
00825   if (selected >= 0)
00826     {
00827     selected = -1;
00828     if (need_render)
00829       {
00830       render();
00831       show();
00832       }
00833     }
00834   }
00835 
00836 /*
00837  *  Move a palette within the list.
00838  */
00839 
00840 void Palette_edit::move_palette
00841   (
00842   bool up
00843   )
00844   {
00845   if (cur_pal < 0)
00846     return;
00847   GdkRgbCmap *tmp;
00848   if (up)
00849     {
00850     if (cur_pal > 0)
00851       {
00852       tmp = palettes[cur_pal - 1];
00853       palettes[cur_pal - 1] = palettes[cur_pal];
00854       palettes[cur_pal] = tmp;
00855       cur_pal--;
00856       flex_info->swap(cur_pal);// Update flex-file list.
00857       }
00858     }
00859   else
00860     {
00861     if (cur_pal < palettes.size() - 1)
00862       {
00863       tmp = palettes[cur_pal + 1];
00864       palettes[cur_pal + 1] = palettes[cur_pal];
00865       palettes[cur_pal] = tmp;
00866       flex_info->swap(cur_pal);// Update flex-file list.
00867       cur_pal++;
00868       }
00869     }
00870   flex_info->set_modified();
00871   gtk_spin_button_set_value(GTK_SPIN_BUTTON(pspin), cur_pal);
00872   }
00873 
00874 /*
00875  *  Update upper bound of a range widget.
00876  */
00877 
00878 void Update_range_upper
00879   (
00880   GtkAdjustment *adj,
00881   int new_upper
00882   )
00883   {
00884   adj->upper = new_upper;
00885   gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
00886   }
00887 
00888 /*
00889  *  Add a new palette at the end of the list.
00890  */
00891 
00892 void Palette_edit::add_palette
00893   (
00894   )
00895   {
00896   new_palette();
00897   cur_pal = palettes.size() - 1;  // Set to display new palette.
00898   Update_range_upper(palnum_adj, palettes.size() - 1);
00899           // This will update the display:
00900   gtk_spin_button_set_value(GTK_SPIN_BUTTON(pspin), cur_pal);
00901   }
00902 
00903 /*
00904  *  Remove the current palette.
00905  */
00906 
00907 void Palette_edit::remove_palette
00908   (
00909   )
00910   {
00911           // Don't delete the last one.
00912   if (cur_pal < 0 || palettes.size() < 2)
00913     return;
00914   if (Prompt(
00915     "Do you really want to delete the palette you're viewing?",
00916               "Yes", "No") != 0)
00917     return;
00918   gdk_rgb_cmap_free(palettes[cur_pal]);
00919   palettes.erase(palettes.begin() + cur_pal);
00920   flex_info->remove(cur_pal);
00921   flex_info->set_modified();
00922   if (cur_pal >= palettes.size())
00923     cur_pal = palettes.size() - 1;
00924   Update_range_upper(palnum_adj, palettes.size() - 1);
00925           // This will update the display:
00926   gtk_spin_button_set_value(GTK_SPIN_BUTTON(pspin), cur_pal);
00927   render();     // Cur_pal may not have changed.
00928   show();
00929   }
00930 
00931 /*
00932  *  Export current palette.
00933  */
00934 
00935 void Palette_edit::export_palette
00936   (
00937   char *fname,
00938   gpointer user_data
00939   )
00940   {
00941   Palette_edit *ed = (Palette_edit *) user_data;
00942   if (U7exists(fname))
00943     {
00944     char *msg = g_strdup_printf(
00945       "'%s' already exists.  Overwrite?", fname);
00946     int answer = Prompt(msg, "Yes", "No");
00947     g_free(msg);
00948     if (answer != 0)
00949       return;
00950     }
00951           // Write out current palette.
00952   GdkRgbCmap *pal = ed->palettes[ed->cur_pal];
00953   ofstream out(fname);    // OKAY that it's a 'text' file.
00954   out << "Palette from ExultStudio" << endl;
00955   int i;        // Skip 0's at end.
00956   for (i = 255; i > 0; i--)
00957     if (pal->colors[i] != 0)
00958       break;
00959   int last_color = i;
00960   for (i = 0; i <= last_color; i++)
00961     {
00962     int r = (pal->colors[i]>>16)&255,
00963         g = (pal->colors[i]>>8)&255,
00964         b = pal->colors[i]&255;
00965     out << setw(3) << r << ' ' << setw(3) << g << ' ' <<
00966             setw(3) << b << endl;
00967     }
00968   out.close();
00969   }
00970 
00971 /*
00972  *  Import current palette.
00973  */
00974 
00975 void Palette_edit::import_palette
00976   (
00977   char *fname,
00978   gpointer user_data
00979   )
00980   {
00981   Palette_edit *ed = (Palette_edit *) user_data;
00982   char *msg = g_strdup_printf(
00983       "Overwrite current palette from '%s'?", fname);
00984   int answer = Prompt(msg, "Yes", "No");
00985   g_free(msg);
00986   if (answer != 0)
00987     return;
00988           // Read in current palette.
00989   GdkRgbCmap *pal = ed->palettes[ed->cur_pal];
00990   ifstream in(fname);   // OKAY that it's a 'text' file.
00991   char buf[256];
00992   in.getline(buf, sizeof(buf)); // Skip 1st line.
00993   if (!in.good())
00994     {
00995     Alert("Error reading '%s'", fname);
00996     return;
00997     }
00998   int i = 0;      // Color #.
00999   while (i < 256 && !in.eof())
01000     {
01001     in.getline(buf, sizeof(buf));
01002     char *ptr = &buf[0];
01003           // Skip spaces.
01004     while (ptr < buf + sizeof(buf) && *ptr && isspace(*ptr))
01005       ptr++;
01006     if (*ptr == '#')
01007       continue; // Comment.
01008     int r, g, b;
01009     if (sscanf(buf, "%d %d %d", &r, &g, &b) == 3)
01010       pal->colors[i++] = (r<<16) + (g<<8) + b;
01011     }
01012   in.close();
01013           // Add to file.
01014   ed->update_flex(ed->cur_pal);
01015   ed->render();
01016   ed->show();
01017   }
01018 

Generated on Mon Jul 9 14:42:48 2007 for ExultEngine by  doxygen 1.5.1