//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // mapedit.cc // // Vincent LE PRINCE // Copyright (C) 2000-2001 Vincent LE PRINCE // This file is part of the TRUEVISION Package // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ //******************************************************************************************* #include "include/mapedit.h" #include "include/dlgutils.h" #include "include/tvio.h" const float diff = 0.0000001; //******************************************** // MAP ITEM //******************************************** MapItem::MapItem( char *nom, float val = -1 ) { name = nom; value = val; button = NULL; } MapItem::MapItem( MapItem & res ) { name = res.name; value = res.value; button = NULL; } void MapItem::get_widget( GtkWidget *tbox, bool tt, TvWidget_map_editor *mother ) { refresh_name(); button = gtk_toggle_button_new_with_label( name ); gtk_button_set_relief( GTK_BUTTON(button), GTK_RELIEF_HALF ); gtk_box_pack_start( GTK_BOX(tbox), button, TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_mapedit_selection), mother ); } void MapItem::save( ofstream & file ) { file << "\nMAPITEM{ PARAMS{ VALUE=" << value; file << " R=" << (int)color[0] << " G=" << (int)color[1] << " B=" << (int)color[2] << " A=" << (int)color[3] << " } "; } bool MapItem::load( ifstream & file, char * tag ) { if ( strcmp( "PARAMS", tag ) ) return false; char * val = NULL; do { val = tvio_get_next_val( file ); if ( val == NULL ) return true; if ( ! strcmp( val, "VALUE" ) ) { value = tvio_get_value_as_float( file ); continue; } if ( ! strcmp( val, "R" ) ) { color[0] = tvio_get_value_as_int( file ); continue; } if ( ! strcmp( val, "G" ) ) { color[1] = tvio_get_value_as_int( file ); continue; } if ( ! strcmp( val, "B" ) ) { color[2] = tvio_get_value_as_int( file ); continue; } if ( ! strcmp( val, "A" ) ) { color[3] = tvio_get_value_as_int( file ); continue; } } while( val != NULL ); return true; } //******************************************** // MAP EDITOR //******************************************** // Constantes const int grad_x = 15; const int grad_y = 3; const int grad_w = 50; const int linebreak2 = grad_x + grad_w + 1; const guchar fond_col1[3] = { 180, 180, 180 }; const guchar fond_col2[3] = { 120, 120, 120 }; // Constructeur TvWidget_map_editor::TvWidget_map_editor( const char *name, const char *sname, const char *tooltip, app_objs *appref, MapItem* (*func)(gpointer), gpointer par ) : TvWidget( name, sname, tooltip, appref ) { widget = NULL; cursor = NULL; pointer = NULL; grad_image = NULL; drawing_pix = NULL; items_box = NULL; in_change = false; selected = 0; item_feeder = func; item_feeder_param = par; tree_store = NULL; editor_box = NULL; in_drag = false; } // Copy Constructor TvWidget_map_editor::TvWidget_map_editor( TvWidget_map_editor & res ) : TvWidget( res ) { widget = NULL; cursor = NULL; pointer = NULL; grad_image = NULL; drawing_pix = NULL; items_box = NULL; in_change = false; selected = 0; item_feeder = res.item_feeder; item_feeder_param = res.item_feeder_param; tree_store = NULL; editor_box = NULL; in_drag = false; for ( unsigned int i = 0 ; i < res.item_list.size() ; i++ ) { MapItem *nitem = res.item_list[i]->duplicate_yourself(); item_list.push_back( nitem ); } } // Destructeur TvWidget_map_editor::~TvWidget_map_editor() { clear_widget(); for ( unsigned int i = 0 ; i < item_list.size() ; i++ ) delete item_list[i]; } // Nettoyage void TvWidget_map_editor::clear_widget() { if ( drawing_pix != NULL ) gdk_pixmap_unref( drawing_pix ); if ( cursor != NULL ) { gdk_pixmap_unref( cursor ); gdk_pixmap_unref( cursor_mask ); } if ( pointer != NULL ) gdk_cursor_destroy( pointer ); if ( grad_image != NULL ) delete grad_image; widget = NULL; drawing_pix = NULL; cursor = NULL; pointer = NULL; grad_image = NULL; items_box = NULL; editor_box = NULL; in_drag = false; //for ( unsigned int i = 0 ; i < item_list.size() ; i++ ) // item_list[i]->destroy_editor(); } //************************************* // GET WIDGET //************************************* void TvWidget_map_editor::get_widget( GtkWidget *box, bool tt ) { // Frame widget = dlg_simple_box_frame( name, box ); gtk_container_set_border_width( GTK_CONTAINER(widget), 3 ); // Bouttons GtkWidget *hbox = gtk_hbox_new( TRUE, 3 ); gtk_box_pack_start( GTK_BOX(widget), hbox, TRUE, TRUE, 1 ); GtkWidget *button = gtk_button_new_with_label( _("Append") ); gtk_box_pack_start( GTK_BOX(hbox), button, TRUE, TRUE, 1 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_mapedit_append_item), this ); button = gtk_button_new_with_label( _("Prepend") ); gtk_box_pack_start( GTK_BOX(hbox), button, TRUE, TRUE, 1 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_mapedit_prepend_item), this ); button = gtk_button_new_with_label( _("Duplicate") ); gtk_box_pack_start( GTK_BOX(hbox), button, TRUE, TRUE, 1 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_mapedit_duplicate_item), this ); button = gtk_button_new_with_label( _("Delete") ); gtk_box_pack_start( GTK_BOX(hbox), button, TRUE, TRUE, 1 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_mapedit_delete_item), this ); // Status //status = gtk_label_new( "" ); //gtk_box_pack_start( GTK_BOX(widget), status, TRUE, FALSE, 0 ); // Conteneur horizontal horbox = gtk_hbox_new( TRUE, 0 ); gtk_box_pack_start( GTK_BOX(widget), horbox, TRUE, TRUE, 2 ); // Gradient drawing_area = gtk_drawing_area_new(); gtk_widget_set_events( drawing_area, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ); gtk_signal_connect( GTK_OBJECT(drawing_area), "realize", GTK_SIGNAL_FUNC(sign_mapedit_realize), this ); gtk_signal_connect( GTK_OBJECT(drawing_area), "expose_event", GTK_SIGNAL_FUNC(sign_mapedit_expose), this ); gtk_signal_connect( GTK_OBJECT(drawing_area), "configure_event", GTK_SIGNAL_FUNC(sign_mapedit_configure), this ); gtk_signal_connect( GTK_OBJECT(drawing_area), "button_press_event", GTK_SIGNAL_FUNC(sign_mapedit_mouse_click), this ); gtk_signal_connect( GTK_OBJECT(drawing_area), "button_release_event", GTK_SIGNAL_FUNC(sign_mapedit_mouse_release), this ); gtk_signal_connect( GTK_OBJECT(drawing_area), "motion_notify_event", GTK_SIGNAL_FUNC(sign_mapedit_mouse_moved), this ); gtk_widget_set_usize( drawing_area, -1, 200 ); gtk_box_pack_start( GTK_BOX(horbox), drawing_area, TRUE, TRUE, 0 ); // Edition de la valeur dans le gradient GtkWidget *valbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(widget), valbox, TRUE, TRUE, 0 ); GtkWidget *vallabel = gtk_label_new( _("Value") ); gtk_box_pack_start( GTK_BOX(valbox), vallabel, TRUE, TRUE, 0 ); GtkObject *adj = gtk_adjustment_new( 0, 0, 1, 0.01, 0.1, 0 ); value_entry = gtk_spin_button_new( GTK_ADJUSTMENT(adj), 0, 4 ); gtk_box_pack_start( GTK_BOX(valbox), value_entry, TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT(value_entry), "changed", GTK_SIGNAL_FUNC(sign_mapedit_valentry_changed), this ); rebuild_item_list(); set_item_editor(); //char text[30]; valentry_inchange = true; //sprintf( text, "%f", item_list[selected]->value ); //gtk_entry_set_text( GTK_ENTRY(value_entry), text ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(value_entry) , item_list[selected]->value ); valentry_inchange = false; } // Set Editor void TvWidget_map_editor::set_item_editor() { valentry_inchange = true; //char str[25]; //snprintf( str, 24, "%f", (item_list[selected]->value) ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(value_entry) , item_list[selected]->value ); valentry_inchange = false; if ( editor_box != NULL ) gtk_widget_destroy( editor_box ); editor_box = gtk_hbox_new( TRUE, 0 ); gtk_box_pack_start( GTK_BOX(widget), editor_box, TRUE, TRUE, 0 ); item_list[selected]->get_editor( editor_box, true ); item_list[selected]->connect_signal( &sign_mapedit_item_changed, (gpointer)this ); gtk_widget_show_all( editor_box ); } // Item List void TvWidget_map_editor::rebuild_item_list() { if ( items_box != NULL ) gtk_widget_destroy( items_box ); items_box = gtk_vbox_new( TRUE, 1 ); gtk_box_pack_start( GTK_BOX(horbox), items_box, TRUE, TRUE, 0 ); for ( unsigned int i = 0 ; i < item_list.size() ; i++ ) (item_list[i])->get_widget( items_box, true, this ); in_change = true; item_list[selected]->toggle(); set_item_editor(); in_change = false; gtk_widget_show_all( items_box ); } void TvWidget_map_editor::flush() { //for ( unsigned int i = 0 ; i < item_list.size() ; i++ ) // (item_list[i])->flush(); (item_list[selected])->flush(); } //************************************* // DRAW //************************************* void TvWidget_map_editor::expose( GdkEventExpose *ev ) { // Nettoyage //gdk_draw_rectangle( drawing_pix, drawing_area->style->bg_gc[drawing_area->state], TRUE, ev->area.x, ev->area.y, ev->area.width, ev->area.height ); gdk_draw_rectangle( drawing_pix, drawing_area->style->bg_gc[drawing_area->state], TRUE, 0, 0, width, height ); // Cadre du gradient gdk_draw_rectangle( drawing_pix, drawing_area->style->fg_gc[drawing_area->state], FALSE, grad_x, grad_y, grad_w, grad_h ); // Labels gdk_draw_text( drawing_pix, gtk_style_get_font(drawing_area->style), drawing_area->style->fg_gc[drawing_area->state], grad_x-11, grad_y+11, "0", 1 ); gdk_draw_text( drawing_pix, gtk_style_get_font(drawing_area->style), drawing_area->style->fg_gc[drawing_area->state], grad_x-11, grad_h, "1", 1 ); update_gradient(); // Items unsigned int size = item_list.size(); int item_widget_height = height / size; for ( register unsigned int i = 0 ; i < size ; i++ ) { int point = (int)( (float)(grad_h-2) * item_list[i]->value ) + grad_y + 1; int base = item_widget_height * i + item_widget_height / 2; item_list[i]->cursor_pos = point-5; if ( (int)i == selected ) { gdk_draw_line( drawing_pix, drawing_area->style->fg_gc[drawing_area->state], linebreak1, base, height-1, base ); gdk_draw_line( drawing_pix, drawing_area->style->fg_gc[drawing_area->state], linebreak2, point, linebreak1, point ); gdk_draw_line( drawing_pix, drawing_area->style->fg_gc[drawing_area->state], linebreak1, point, linebreak1, base ); } gdk_draw_pixmap( drawing_pix, drawing_area->style->fg_gc[drawing_area->state], cursor, 0, 0, linebreak2+1, point-5, 6, 11 ); } //GdkRectangle rect; rect.width = width - 1; rect.height = height-1; //cout << "\nredraw x->" << ev->area.x << " - y->" << ev->area.y ; cout.flush(); //gdk_gc_set_clip_origin( drawing_area->style->fg_gc[drawing_area->state], 0, 0 ); //gdk_gc_set_clip_rectangle( drawing_area->style->fg_gc[drawing_area->state], &rect ); //gdk_draw_pixmap( drawing_area->window, drawing_area->style->fg_gc[drawing_area->state], drawing_pix, 0, 0, 0, 0, width, height ); //gdk_gc_set_clip_rectangle( drawing_area->style->fg_gc[drawing_area->state], NULL ); gdk_gc_set_clip_rectangle( drawing_area->style->fg_gc[drawing_area->state], &ev->area ); gdk_draw_pixmap( drawing_area->window, drawing_area->style->fg_gc[drawing_area->state], drawing_pix, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height ); gdk_gc_set_clip_rectangle( drawing_area->style->fg_gc[drawing_area->state], NULL ); } //***************************************** // Gradient //***************************************** // Draw line void TvWidget_map_editor::draw_gradient_line( int pos, guint8 *col ) { int cols = ( grad_w - 3 ) * 3; guchar colpond[3]; guchar coltemp[3]; guchar prev = 0; float alphapond = 255 - col[3]; for ( register int i = 0 ; i < 3 ; i++ ) colpond[i] = (guchar)(( (float)col[i] * col[3] ) / 255.0); int line = pos * cols; for ( register int w = 0 ; w < cols ; w += 3 ) { int pt = line + w; if ( prev != grad_image[pt] ) { prev = grad_image[pt]; guchar pond = (guchar)( ( (float)grad_image[pt] * alphapond ) / 255.0 ); for ( int i = 0 ; i < 3 ; i++ ) coltemp[i] = grad_image[pt++] = colpond[i] + pond; } else { grad_image[pt++] = coltemp[0]; grad_image[pt++] = coltemp[1]; grad_image[pt] = coltemp[2]; } } } // Update void TvWidget_map_editor::update_gradient() { register int pos = 0; int lines = grad_h-3; // Fond int cols = ( grad_w - 3 ) * 3 ; int hcols = (cols / 2); guchar line1[cols], line2[cols]; for ( register int w = 0 ; w < hcols ; w += 3 ) { line1[w] = fond_col1[0]; line2[w] = fond_col2[0]; line1[w+1] = fond_col1[1]; line2[w+1] = fond_col2[1]; line1[w+2] = fond_col1[2]; line2[w+2] = fond_col2[2]; } memcpy( line1 + hcols + 1, line2, sizeof(guchar)*hcols ); memcpy( line2 + hcols + 1, line1, sizeof(guchar)*hcols ); while ( pos < lines-5 ) { for ( int i = 0 ; i < 32 ; i++ ) { if ( pos == lines ) break; memcpy( grad_image + pos*cols, line1, sizeof(guchar)*cols ); pos++; } for ( int i = 0 ; i < 32 ; i++ ) { if ( pos == lines ) break; memcpy( grad_image + pos*cols, line2, sizeof(guchar)*cols ); pos++; } } // Premiere couleur int next_pos = (int)( item_list[0]->value * (float)(lines) ) - 1; guint8 *col = item_list[0]->get_color(); for ( pos = 0 ; pos < next_pos ; pos++ ) draw_gradient_line( pos, col ); // Gradients int size = item_list.size(); for ( int i = 0 ; i < size-1 ; i++ ) { guint8 col1[4], col2[4]; memcpy( col1, item_list[i]->get_color(), sizeof(guint8)*4 ); memcpy( col2, item_list[i+1]->get_color(), sizeof(guint8)*4 ); next_pos = (int)( item_list[i+1]->value * (float)(lines) ) - 1; float progre[4]; float offset = next_pos - pos; for ( int y = 0 ; y < 4 ; y++ ) progre[y] = (float)( col2[y] - col1[y] ) / offset ; float diff; for ( diff = 0 ; pos < next_pos ; pos++ ) { col2[0] = (guint)(col1[0] + diff * progre[0]); col2[1] = (guint)(col1[1] + diff * progre[1]); col2[2] = (guint)(col1[2] + diff * progre[2]); col2[3] = (guint)(col1[3] + diff++ * progre[3]); draw_gradient_line( pos, col2 ); } } // Derniere couleur col = item_list[size-1]->get_color(); for ( pos = pos ; pos < lines ; pos++ ) draw_gradient_line( pos, col ); // Copie dans le buffer gdk_draw_rgb_image( drawing_pix, drawing_area->style->fg_gc[drawing_area->state], grad_x+2, grad_y+2, grad_w-3, grad_h-3, GDK_RGB_DITHER_NORMAL, grad_image, (grad_w-3)*3 ); } // Force redraw void TvWidget_map_editor::invalidate_drawing_area() { GdkRectangle rect; rect.x = grad_x; rect.y = grad_y-5; rect.width = width-grad_x; rect.height = grad_h+10; gtk_widget_draw( drawing_area, &rect ); } //**************************************** // Configure & REALIZE //*************************************** void TvWidget_map_editor::realize() { // Creation du cursor if ( cursor != NULL ) { gdk_pixmap_unref( cursor ); gdk_pixmap_unref( cursor_mask ); } char *pixmap = tv_get_pixmap( "mapedit_cursor.xpm" ); cursor = gdk_pixmap_create_from_xpm( drawing_area->window, &cursor_mask, drawing_area->style->bg, pixmap ); delete pixmap; // Pointeur if ( pointer != NULL ) gdk_cursor_destroy( pointer ); pointer = gdk_cursor_new( GDK_HAND2 ); } void TvWidget_map_editor::configure() { //cout << "\nConfigure !"; cout.flush(); width = drawing_area->allocation.width; height = drawing_area->allocation.height; grad_h = height - 8; if ( grad_h < 0 ) return; linebreak1 = width - (width - grad_x - grad_w) / 2; // Gradient if ( grad_image != NULL ) delete grad_image; grad_image = new guchar[ (grad_w-3) * (grad_h-3) * 3 ]; // PB // Recoit deux signaux 'configure' dont un avec des valeurs ( taille de fenetre ) // négatives qui font crasher l'attribution de mémoire. Le test n'est pas // définitif mais semble marcher pour le moment. //cout << "\nAttribution de : " << grad_w-3 << " x " << grad_h-3 << " x 3 octets"; //cout.flush(); // Drawing pixmap if ( drawing_pix != NULL ) gdk_pixmap_unref( drawing_pix ); drawing_pix = gdk_pixmap_new( drawing_area->window, width, height, -1 ); //invalidate_drawing_area(); } //**************************************** // MOUSE //*************************************** // get mouse position ( over a cursor ? ) int TvWidget_map_editor::test_mouse_pos( int xpos, int ypos, int sens, bool ignore_current, int current ) { bool is_inside = false; int size = item_list.size(); int min_x = grad_x + grad_w; int max_x = min_x + 11; register int i; // Without control-key try to keep already selected item // Usefull for overlapped cursors if ( ! ignore_current ) { if ( xpos > min_x && xpos < max_x && ypos > item_list[current]->cursor_pos && ypos < item_list[current]->cursor_pos + 11 ) return current; } // Otherwise do classic selection // From top to bottom with left click // and from bottom to top with right click /*int start = ( sens == 1 ) ? 0 : size; int stop = ( sens == 1 ) ? size : 0; int inc = ( sens == 1 ) ? 1 : -1;*/ if ( sens == 1 ) { for ( i = 0 ; i < size ; i ++ ) { if ( xpos < min_x ) continue; if ( xpos > max_x ) continue; if ( ypos < item_list[i]->cursor_pos ) continue; if ( ypos > item_list[i]->cursor_pos + 11 ) continue; is_inside = true; break; } } else { for ( i = size-1 ; i > -1 ; i-- ) { if ( xpos < min_x ) continue; if ( xpos > max_x ) continue; if ( ypos < item_list[i]->cursor_pos ) continue; if ( ypos > item_list[i]->cursor_pos + 11 ) continue; is_inside = true; break; } } if ( !is_inside ) return -1; if ( i == 0 && item_list[0]->value == 0 && (item_list[1]->cursor_pos - item_list[0]->cursor_pos) < 12 ) return 1; else return i; } // Mouse click void TvWidget_map_editor::mouse_click( GdkEventButton *ev ) { GdkModifierType state; int drag_x; gdk_window_get_pointer( ev->window, &drag_x, &drag_y, &state ); int sens = ( ev->button == 1 ) ? 1 : 0 ; int drag_item = test_mouse_pos( drag_x, drag_y, sens, ( state & GDK_CONTROL_MASK ), selected ); if ( drag_item == -1 ) return; if ( selected != drag_item ) { in_change = true; item_list[selected]->untoggle(); selected = drag_item; item_list[selected]->toggle(); set_item_editor(); in_change = false; } if ( selected== 0 ) drag_min = 0; else drag_min = item_list[selected-1]->value + diff; if ( selected== (int)item_list.size() - 1 ) drag_max = 1; else drag_max = item_list[selected+1]->value - diff; in_drag = true; } void TvWidget_map_editor::mouse_moved( GdkEventMotion *ev ) { int xpos, ypos; GdkModifierType state; if ( ev->is_hint ) gdk_window_get_pointer( ev->window, &xpos, &ypos, &state ); else { xpos = (int)ev->x; ypos = (int)ev->y; state = (GdkModifierType)ev->state; } if ( (state & GDK_BUTTON1_MASK) || (state & GDK_BUTTON3_MASK) ) { if ( in_drag == false ) return; if ( selected == -1 ) return; float offset = ( 1.0 / (float)grad_h ) * (float)( drag_y - ypos ); item_list[selected]->value -= offset; if ( item_list[selected]->value < drag_min ) item_list[selected]->value = drag_min; if ( item_list[selected]->value > drag_max ) item_list[selected]->value = drag_max; drag_y = ypos; invalidate_drawing_area(); //char text[30]; valentry_inchange = true; //sprintf( text, "%f", item_list[selected]->value ); //gtk_entry_set_text( GTK_ENTRY(value_entry), text ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(value_entry) , item_list[selected]->value ); valentry_inchange = false; return; } if ( test_mouse_pos( xpos, ypos, 1, true, selected ) != -1 ) gdk_window_set_cursor( drawing_area->window, pointer ); else gdk_window_set_cursor( drawing_area->window, NULL ); } //********************************************* // SELECT //********************************************* int TvWidget_map_editor::get_sender_item( GtkWidget *wid ) { int newsel = -1; for ( unsigned int i = 0; i < item_list.size() ; i++ ) if ( item_list[i]->button == wid ) { newsel = i; break; } return newsel; } void TvWidget_map_editor::select( GtkWidget *wid ) { if ( in_change ) return; int newsel = get_sender_item( wid ); if ( newsel == -1 ) return; in_change = true; item_list[selected]->untoggle(); selected = newsel; item_list[selected]->toggle(); set_item_editor(); in_change = false; invalidate_drawing_area(); } void TvWidget_map_editor::delete_item() { if ( item_list.size() == 2 ) return; in_change = true; item_list[selected]->destroy_widget(); if ( tree_store != NULL ) item_list[selected]->remove_from_tree(); delete item_list[selected]; vector::iterator it = item_list.begin() + selected; item_list.erase(it); if ( selected == (int)item_list.size() ) selected--; item_list[selected]->toggle(); set_item_editor(); in_change = false; invalidate_drawing_area(); } void TvWidget_map_editor::append_item() { int size = item_list.size(); if ( size > 254 ) return; if ( item_feeder == NULL ) return; MapItem *newone = (*item_feeder)(item_feeder_param); if ( selected == size - 1 ) { newone->value = ( 1.0 + item_list[selected]->value ) / 2.0; memcpy( newone->get_color(), item_list[selected]->get_color(), sizeof(guint8)*4 ); item_list.push_back( newone ); } else { newone->value = ( item_list[selected]->value + item_list[selected+1]->value ) / 2.0; for ( register int i = 0 ; i < 4 ; i++ ) newone->color[i] = ( item_list[selected]->color[i] + item_list[selected+1]->color[i] ) / 2; vector::iterator it = item_list.begin() + selected + 1; item_list.insert( it, newone ); } if ( tree_store != NULL ) newone->add_to_tree( tree_view, tree_store, tree_selection, node_iter ); selected++; item_list[selected]->update_editor(); invalidate_drawing_area(); rebuild_item_list(); } void TvWidget_map_editor::prepend_item() { int size = item_list.size(); if ( size > 254 ) return; if ( item_feeder == NULL ) return; MapItem *newone = (*item_feeder)(item_feeder_param); if ( selected == 0 ) { newone->value = item_list[selected]->value / 2.0; memcpy( newone->get_color(), item_list[selected]->get_color(), sizeof(guint8)*4 ); vector::iterator it = item_list.begin(); item_list.insert( it, newone ); } else { newone->value = ( item_list[selected]->value + item_list[selected-1]->value ) / 2.0; for ( register int i = 0 ; i < 4 ; i++ ) newone->color[i] = ( item_list[selected]->color[i] + item_list[selected-1]->color[i] ) / 2; vector::iterator it = item_list.begin() + selected; item_list.insert( it, newone ); } if ( tree_store != NULL ) newone->add_to_tree( tree_view, tree_store, tree_selection, node_iter ); item_list[selected]->update_editor(); invalidate_drawing_area(); rebuild_item_list(); } // Duplicate Item void TvWidget_map_editor::duplicate_item() { int size = item_list.size(); if ( size > 254 ) return; if ( item_feeder == NULL ) return; MapItem *newone = item_list[selected]->duplicate_yourself(); if ( newone->value < 0.999 ) newone->value += diff; if ( selected == size - 1 ) { vector::iterator it = item_list.begin() + selected; item_list.insert( it, newone ); } else { vector::iterator it = item_list.begin() + selected + 1; item_list.insert( it, newone ); } if ( tree_store != NULL ) newone->add_to_tree( tree_view, tree_store, tree_selection, node_iter ); selected++; //item_list[selected]->update_editor(); invalidate_drawing_area(); rebuild_item_list(); } //******************************** // VALUE ENTRY CHANGED //******************************** void TvWidget_map_editor::value_entry_changed() { if ( valentry_inchange == true ) return; float value = gtk_spin_button_get_value_as_float( GTK_SPIN_BUTTON(value_entry) );; //sscanf( gtk_entry_get_text( GTK_ENTRY(value_entry) ), "%f", &value ); if ( value < 0 || value > 1 ) return; float maxval, minval; if ( selected == 0 ) minval = 0; else minval = item_list[selected-1]->value + diff; if ( selected == (int)item_list.size() - 1 ) maxval = 1; else maxval = item_list[selected+1]->value - diff; if ( value > maxval ) value = maxval; if ( value < minval ) value = minval; item_list[selected]->value = value; invalidate_drawing_area(); } //******************************** // TREE //******************************** void TvWidget_map_editor::add_to_tree( GtkTreeView *view, GtkTreeStore *store, GtkTreeSelection *selection, GtkTreeIter *parent, GtkTreeIter *sibling ) { tree_store = store; tree_view = view; tree_selection = selection; node_iter = parent; int size = item_list.size(); for ( register int i = 0 ; i < size ; i ++ ) item_list[i]->add_to_tree( view, store, selection, parent ); } void TvWidget_map_editor::remove_from_tree() { tree_store = NULL; int size = item_list.size(); for ( register int i = 0 ; i < size ; i ++ ) item_list[i]->remove_from_tree(); } //******************************** // Output //******************************** void TvWidget_map_editor::output_to_povray( ofstream & file ) { int size = item_list.size(); for ( int i = 0 ; i < size ; i++ ) { file << "\n\t\t\t\t[ " << item_list[i]->value << " "; item_list[i]->output_to_povray( file ); file << " ]"; } } //******************************** // Sauvegarde //******************************** void TvWidget_map_editor::save( ofstream & file ) { int size = item_list.size(); TvWidget::save( file ); for ( int i = 0 ; i < size ; i++ ) item_list[i]->save( file ); file << " } "; } bool TvWidget_map_editor::load( ifstream & file, char * ltag ) { if ( strcmp( sname, ltag ) ) return false; char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( ! strcmp( "MAPITEM", tag ) ) { MapItem *newone = (*item_feeder)(item_feeder_param); newone->load( file, tag ); item_list.push_back( newone ); continue; } tvio_skip_section( file ); } while( tag != NULL ); return true; }