/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_DIRENT_H #include #endif #include #include #include "appenv.h" #include "actionarea.h" #include "buildmenu.h" #include "colormaps.h" #include "color_area.h" #include "color_select.h" #include "datafiles.h" #include "devices.h" #include "errors.h" #include "general.h" #include "gimprc.h" #include "gradient_header.h" #include "gradient.h" #include "interface.h" #include "palette.h" #include "palette_entries.h" #include "session.h" #include "palette_select.h" #include "dialog_handler.h" #include "pixmaps/zoom_in.xpm" #include "pixmaps/zoom_out.xpm" #include "libgimp/gimpintl.h" #define ENTRY_WIDTH 12 #define ENTRY_HEIGHT 10 #define SPACING 1 #define COLUMNS 16 #define ROWS 11 #define PREVIEW_WIDTH ((ENTRY_WIDTH * COLUMNS) + (SPACING * (COLUMNS + 1))) #define PREVIEW_HEIGHT ((ENTRY_HEIGHT * ROWS) + (SPACING * (ROWS + 1))) #define PALETTE_EVENT_MASK GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK /* New palette code... */ #define IMPORT_PREVIEW_WIDTH 80 #define IMPORT_PREVIEW_HEIGHT 80 #define MAX_IMAGE_COLOURS (10000*2) typedef enum { GRAD_IMPORT = 0, IMAGE_IMPORT = 1, } ImportType; struct _ImportDialog { GtkWidget *dialog; GtkWidget *preview; GtkWidget *entry; GtkWidget *select_area; GtkWidget *select; GtkWidget *image_list; GtkWidget *image_menu_item_image; GtkWidget *image_menu_item_gradient; GtkWidget *optionmenu1_menu; GtkWidget *type_option; GtkWidget *threshold_scale; GtkWidget *threshold_text; GtkAdjustment *threshold; GtkAdjustment *sample; ImportType import_type; GimpImage *gimage; }; typedef struct _ImportDialog ImportDialog ,*ImportDialogP; typedef struct _Palette _Palette, *PaletteP; struct _Palette { GtkWidget *shell; GtkWidget *color_area; GtkWidget *scrolled_window; GtkWidget *color_name; GtkWidget *clist; GtkWidget *popup_menu; GtkWidget *popup_small_menu; ColorSelectP color_select; int color_select_active; PaletteEntriesP entries; PaletteEntryP color; GdkGC *gc; guint entry_sig_id; gfloat zoom_factor; /* range from 0.1 to 4.0 */ gint columns; gint freeze_update; }; static void palette_entries_free (PaletteEntriesP); static void palette_entries_load (char *); static void palette_entry_free (PaletteEntryP); static void palette_entries_save (PaletteEntriesP, char *); PaletteP create_palette_dialog (gint vert); static void palette_draw_entries (PaletteP palette,gint row_start, gint column_highlight); static void redraw_palette(PaletteP palette); static GSList * palette_entries_insert_list (GSList *list,PaletteEntriesP entries,gint pos); void palette_clist_init(GtkWidget *clist, GtkWidget *shell, GdkGC *gc); static void palette_draw_small_preview(GdkGC *gc, PaletteEntriesP p_entry); static void palette_scroll_clist_to_current(PaletteP palette); static void palette_update_small_preview(PaletteP palette); static void palette_scroll_top_left(PaletteP palette); static ImportDialogP palette_import_dialog(PaletteP palette); static void palette_import_dialog_callback (GtkWidget *w,gpointer client_data); static void import_palette_create_from_image (GImage *gimage,guchar *pname,PaletteP palette); static void palette_merge_dialog_callback (GtkWidget *w,gpointer client_data); GSList *palette_entries_list = NULL; static PaletteEntriesP default_palette_entries = NULL; static int num_palette_entries = 0; static unsigned char foreground[3] = { 0, 0, 0 }; static unsigned char background[3] = { 255, 255, 255 }; static ImportDialogP import_dialog = NULL; PaletteP top_level_edit_palette = NULL; PaletteP top_level_palette = NULL; static void palette_entries_free (PaletteEntriesP entries) { PaletteEntryP entry; GSList * list; list = entries->colors; while (list) { entry = (PaletteEntryP) list->data; palette_entry_free (entry); list = list->next; } g_free (entries->name); if (entries->filename) g_free (entries->filename); g_free (entries); } static void palette_entries_delete (char *filename) { if (filename) unlink (filename); } void palettes_init (int no_data) { palette_init_palettes (no_data); } void palette_free_palettes (void) { GSList *list; PaletteEntriesP entries; list = palette_entries_list; while (list) { entries = (PaletteEntriesP) list->data; /* If the palette has been changed, save it, if possible */ if (entries->changed) /* save the palette */ palette_entries_save (entries, entries->filename); palette_entries_free (entries); list = g_slist_next (list); } g_slist_free (palette_entries_list); num_palette_entries = 0; palette_entries_list = NULL; } void palettes_free () { palette_free_palettes (); } void palette_get_foreground (unsigned char *r, unsigned char *g, unsigned char *b) { *r = foreground[0]; *g = foreground[1]; *b = foreground[2]; } void palette_get_background (unsigned char *r, unsigned char *g, unsigned char *b) { *r = background[0]; *g = background[1]; *b = background[2]; } void palette_set_foreground (int r, int g, int b) { unsigned char rr, gg, bb; /* Foreground */ foreground[0] = r; foreground[1] = g; foreground[2] = b; palette_get_foreground (&rr, &gg, &bb); if (no_interface == FALSE) { store_color (&foreground_pixel, rr, gg, bb); color_area_update (); device_status_update (current_device); } } void palette_set_background (int r, int g, int b) { unsigned char rr, gg, bb; /* Background */ background[0] = r; background[1] = g; background[2] = b; palette_get_background (&rr, &gg, &bb); if (no_interface == FALSE) { store_color (&background_pixel, rr, gg, bb); color_area_update (); } } void palette_set_default_colors (void) { palette_set_foreground (0, 0, 0); palette_set_background (255, 255, 255); } void palette_swap_colors (void) { unsigned char fg_r, fg_g, fg_b; unsigned char bg_r, bg_g, bg_b; palette_get_foreground (&fg_r, &fg_g, &fg_b); palette_get_background (&bg_r, &bg_g, &bg_b); palette_set_foreground (bg_r, bg_g, bg_b); palette_set_background (fg_r, fg_g, fg_b); } void palette_init_palettes (int no_data) { if(!no_data) datafiles_read_directories (palette_path, palette_entries_load, 0); } static void palette_select2_set_text_all(PaletteEntriesP entries) { gint pos = 0; char *num_buf; GSList *plist; PaletteP pp; PaletteEntriesP p_entries = NULL; gchar * num_copy; plist = palette_entries_list; while (plist) { p_entries = (PaletteEntriesP) plist->data; plist = g_slist_next (plist); if (p_entries == entries) break; pos++; } if(p_entries == NULL) return; /* This is actually and error */ num_buf = g_strdup_printf("%d",p_entries->n_colors);; num_copy = g_strdup(num_buf); pp = top_level_palette; gtk_clist_set_text(GTK_CLIST(pp->clist),pos,1,num_copy); redraw_palette(pp); } static void palette_select2_refresh_all() { PaletteP pp; if(!top_level_palette) return; pp = top_level_palette; gtk_clist_freeze(GTK_CLIST(pp->clist)); gtk_clist_clear(GTK_CLIST(pp->clist)); palette_clist_init(pp->clist,pp->shell,pp->gc); gtk_clist_thaw(GTK_CLIST(pp->clist)); pp->entries = palette_entries_list->data; redraw_palette(pp); palette_scroll_clist_to_current(pp); } static void palette_select2_clist_insert_all(PaletteEntriesP p_entries) { PaletteEntriesP chk_entries; PaletteP pp; GSList *plist; gint pos = 0; plist = palette_entries_list; while (plist) { chk_entries = (PaletteEntriesP) plist->data; plist = g_slist_next (plist); /* to make sure we get something! */ if (chk_entries == NULL) { return; } if (strcmp(p_entries->name, chk_entries->name) == 0) break; pos++; } pp = top_level_palette; gtk_clist_freeze(GTK_CLIST(pp->clist)); palette_insert_clist(pp->clist,pp->shell,pp->gc,p_entries,pos); gtk_clist_thaw(GTK_CLIST(pp->clist)); /* if(gradient_select_dialog) */ /* { */ /* gtk_clist_set_text(GTK_CLIST(gradient_select_dialog->clist),n,1,grad->name); */ /* } */ } static void palette_save_palettes() { GSList *list; PaletteEntriesP entries; list = palette_entries_list; while (list) { entries = (PaletteEntriesP) list->data; /* If the palette has been changed, save it, if possible */ if (entries->changed) /* save the palette */ palette_entries_save (entries, entries->filename); list = g_slist_next (list); } } static void palette_save_palettes_callback(GtkWidget *w, gpointer client_data) { palette_save_palettes(); } static void palette_entry_free (PaletteEntryP entry) { if (entry->name) g_free (entry->name); g_free (entry); } void palette_free () { if (top_level_edit_palette) { if(import_dialog) { gtk_widget_destroy(import_dialog->dialog); g_free(import_dialog); import_dialog = NULL; } gdk_gc_destroy (top_level_edit_palette->gc); if (top_level_edit_palette->color_select) color_select_free (top_level_edit_palette->color_select); g_free (top_level_edit_palette); top_level_edit_palette = NULL; } if(top_level_palette) { gdk_gc_destroy (top_level_palette->gc); session_get_window_info (top_level_palette->shell, &palette_session_info); top_level_palette = NULL; } } static void palette_entries_save (PaletteEntriesP palette, char *filename) { FILE * fp; GSList * list; PaletteEntryP entry; if (! filename) return; /* Open the requested file */ if (! (fp = fopen (filename, "wb"))) { g_message (_("can't save palette \"%s\"\n"), filename); return; } fprintf (fp, "GIMP Palette\n"); fprintf (fp, "# %s -- GIMP Palette file\n", palette->name); list = palette->colors; while (list) { entry = (PaletteEntryP) list->data; fprintf (fp, "%d %d %d\t%s\n", entry->color[0], entry->color[1], entry->color[2], entry->name); list = g_slist_next (list); } /* Clean up */ fclose (fp); } static PaletteEntryP palette_add_entry (PaletteEntriesP entries, char *name, int r, int g, int b) { PaletteEntryP entry; if (entries) { entry = g_malloc (sizeof (_PaletteEntry)); entry->color[0] = r; entry->color[1] = g; entry->color[2] = b; if (name) entry->name = g_strdup (name); else entry->name = g_strdup (_("Untitled")); entry->position = entries->n_colors; entries->colors = g_slist_append (entries->colors, entry); entries->n_colors += 1; entries->changed = 1; return entry; } return NULL; } static void palette_change_color (int r, int g, int b, int state) { if (top_level_edit_palette && top_level_edit_palette->entries) { switch (state) { case COLOR_NEW: top_level_edit_palette->color = palette_add_entry (top_level_edit_palette->entries, _("Untitled"), r, g, b); palette_update_small_preview(top_level_edit_palette); redraw_palette(top_level_edit_palette); break; case COLOR_UPDATE_NEW: top_level_edit_palette->color->color[0] = r; top_level_edit_palette->color->color[1] = g; top_level_edit_palette->color->color[2] = b; palette_update_small_preview(top_level_edit_palette); redraw_palette(top_level_edit_palette); break; default: break; } } if (active_color == FOREGROUND) palette_set_foreground (r, g, b); else if (active_color == BACKGROUND) palette_set_background (r, g, b); } void palette_set_active_color (int r, int g, int b, int state) { palette_change_color (r, g, b, state); } static void palette_entries_load (char *filename) { PaletteEntriesP entries; char str[512]; char *tok; FILE *fp; int r, g, b; GSList *list; gint pos = 0; PaletteEntriesP p_entries = NULL; r = g = b = 0; entries = (PaletteEntriesP) g_malloc (sizeof (_PaletteEntries)); entries->filename = g_strdup (filename); entries->name = g_strdup (g_basename (filename)); entries->colors = NULL; entries->n_colors = 0; entries->pixmap = NULL; /* Open the requested file */ if (!(fp = fopen (filename, "rb"))) { palette_entries_free (entries); return; } fread (str, 13, 1, fp); str[13] = '\0'; if (strcmp (str, "GIMP Palette\n")) { fclose (fp); return; } while (!feof (fp)) { if (!fgets (str, 512, fp)) continue; if (str[0] != '#') { tok = strtok (str, " \t"); if (tok) r = atoi (tok); tok = strtok (NULL, " \t"); if (tok) g = atoi (tok); tok = strtok (NULL, " \t"); if (tok) b = atoi (tok); tok = strtok (NULL, "\n"); palette_add_entry (entries, tok, r, g, b); } /* if */ } /* while */ /* Clean up */ fclose (fp); entries->changed = 0; list = palette_entries_list; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); /* to make sure we get something! */ if (p_entries == NULL) { p_entries = default_palette_entries; } if (strcmp(p_entries->name, entries->name) > 0) break; pos++; } palette_entries_list = palette_entries_insert_list (palette_entries_list, entries,pos); /* Check if the current palette is the default one */ if (strcmp(default_palette, g_basename(filename)) == 0) default_palette_entries = entries; } static PaletteP new_top_palette(gint vert) { PaletteP p; p = create_palette_dialog(vert); palette_clist_init(p->clist,p->shell,p->gc); return(p); } void palette_select_palette_init(void) { /* Load them if they are not already loaded */ if(top_level_edit_palette == NULL) { top_level_edit_palette = new_top_palette(FALSE); } } void palette_create(void) { if(top_level_palette == NULL) { top_level_palette = new_top_palette(TRUE); /* top_level_palette = palette_new_selection(_("Palette"),NULL); */ session_set_window_geometry (top_level_palette->shell, &palette_session_info, TRUE); /* register this one only */ dialog_register(top_level_palette->shell); gtk_widget_show(top_level_palette->shell); palette_scroll_clist_to_current(top_level_palette); } else { if (!GTK_WIDGET_VISIBLE (top_level_palette->shell)) { gtk_widget_show (top_level_palette->shell); } else { gdk_window_raise(top_level_palette->shell->window); } } } void palette_create_edit(PaletteEntriesP entries) { PaletteP p; if(top_level_edit_palette == NULL) { p = new_top_palette(FALSE); gtk_widget_show(p->shell); palette_draw_entries(p,-1,-1); top_level_edit_palette = p; } else { if (!GTK_WIDGET_VISIBLE (top_level_edit_palette->shell)) { gtk_widget_show (top_level_edit_palette->shell); palette_draw_entries(top_level_edit_palette,-1,-1); } else { gdk_window_raise(top_level_edit_palette->shell->window); } } if(entries != NULL) { top_level_edit_palette->entries = entries; gtk_clist_unselect_all(GTK_CLIST(top_level_edit_palette->clist)); palette_scroll_clist_to_current(top_level_edit_palette); } } static GSList * palette_entries_insert_list (GSList * list, PaletteEntriesP entries, gint pos) { GSList *ret_list; /* add it to the list */ num_palette_entries++; ret_list = g_slist_insert(list, (void *) entries,pos); return ret_list; } static void palette_update_small_preview(PaletteP palette) { GSList *list; gint pos = 0; PaletteEntriesP p_entries = NULL; char *num_buf; list = palette_entries_list; pos = 0; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); /* to make sure we get something! */ if (p_entries == NULL) { p_entries = default_palette_entries; } if (p_entries == palette->entries) break; pos++; } num_buf = g_strdup_printf("%d",p_entries->n_colors); palette_draw_small_preview(palette->gc,p_entries); gtk_clist_set_text(GTK_CLIST(palette->clist),pos,1,num_buf); } static void palette_delete_entry (GtkWidget *w, gpointer client_data) { PaletteEntryP entry; GSList *tmp_link; PaletteP palette; gint pos = 0; palette = client_data; if (palette && palette->entries && palette->color) { entry = palette->color; palette->entries->colors = g_slist_remove (palette->entries->colors, entry); palette->entries->n_colors--; palette->entries->changed = 1; pos = entry->position; palette_entry_free (entry); tmp_link = g_slist_nth (palette->entries->colors, pos); if (tmp_link) { palette->color = tmp_link->data; while (tmp_link) { entry = tmp_link->data; tmp_link = tmp_link->next; entry->position = pos++; } } else { tmp_link = g_slist_nth (palette->entries->colors, pos - 1); if (tmp_link) palette->color = tmp_link->data; } if (palette->entries->n_colors == 0) palette->color = palette_add_entry (palette->entries, _("Black"), 0, 0, 0); palette_update_small_preview(palette); palette_select_set_text_all(palette->entries); palette_select2_set_text_all(palette->entries); redraw_palette(palette); } } static void palette_new_callback (GtkWidget *w, gpointer client_data) { PaletteP palette; char *num_buf; GSList *list; gint pos = 0; PaletteEntriesP p_entries = NULL; palette = client_data; if (palette && palette->entries) { if (active_color == FOREGROUND) palette->color = palette_add_entry (palette->entries, _("Untitled"), foreground[0], foreground[1], foreground[2]); else if (active_color == BACKGROUND) palette->color = palette_add_entry (palette->entries, _("Untitled"), background[0], background[1], background[2]); redraw_palette(palette); list = palette_entries_list; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); /* to make sure we get something! */ if (p_entries == NULL) { p_entries = default_palette_entries; } if (p_entries == palette->entries) break; pos++; } num_buf = g_strdup_printf("%d",p_entries->n_colors);; palette_draw_small_preview(palette->gc,p_entries); gtk_clist_set_text(GTK_CLIST(palette->clist),pos,1,num_buf); palette_select_set_text_all(palette->entries); palette_select2_set_text_all(palette->entries); } } static PaletteEntriesP palette_create_entries(gpointer client_data, gpointer call_data) { char *home; char *palette_name; char *local_path; char *first_token; char *token; char *path; PaletteEntriesP entries = NULL; PaletteP palette; GSList *list; gint pos = 0; PaletteEntriesP p_entries = NULL; palette = client_data; palette_name = (char *) call_data; if (palette && palette_name) { entries = g_malloc (sizeof (_PaletteEntries)); if (palette_path) { /* Get the first path specified in the palette path list */ home = g_get_home_dir (); local_path = g_strdup (palette_path); first_token = local_path; token = xstrsep(&first_token, G_SEARCHPATH_SEPARATOR_S); if (token) { if (*token == '~') { if (home) path = g_strdup_printf("%s%s", home, token + 1); else /* Just ignore the ~ if no HOME ??? */ path = g_strdup(token + 1); } else { path = g_strdup(token); } entries->filename = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", path, palette_name); g_free (path); } g_free (local_path); } else entries->filename = NULL; entries->name = palette_name; /* don't need to copy because this memory is ours */ entries->colors = NULL; entries->n_colors = 0; entries->changed = 1; entries->pixmap = NULL; /* Add into the clist */ list = palette_entries_list; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); /* to make sure we get something! */ if (p_entries == NULL) { p_entries = default_palette_entries; } if (strcmp(p_entries->name, entries->name) > 0) break; pos++; } palette_entries_list = palette_entries_insert_list (palette_entries_list, entries,pos); palette_insert_clist(palette->clist,palette->shell,palette->gc,entries,pos); palette->entries = entries; palette_save_palettes(); } return entries; } static void palette_add_entries_callback (GtkWidget *w, gpointer client_data, gpointer call_data) { PaletteEntriesP entries; entries = palette_create_entries(client_data,call_data); /* Update other selectors on screen */ palette_select_clist_insert_all(entries); palette_select2_clist_insert_all(entries); palette_scroll_clist_to_current((PaletteP)client_data); } static void palette_new_entries_callback (GtkWidget *w, gpointer client_data) { query_string_box (_("New Palette"), _("Enter a name for new palette"), NULL, NULL, NULL, palette_add_entries_callback, client_data); } static void redraw_zoom(PaletteP palette) { if(palette->zoom_factor > 4.0) { palette->zoom_factor = 4.0; } else if(palette->zoom_factor < 0.1) { palette->zoom_factor = 0.1; } palette->columns = COLUMNS; redraw_palette(palette); palette_scroll_top_left(palette); } static void palette_zoomin(GtkWidget *w, gpointer client_data) { PaletteP palette = client_data; palette->zoom_factor += 0.1; redraw_zoom(palette); } static void palette_zoomout (GtkWidget *w, gpointer client_data) { PaletteP palette = client_data; palette->zoom_factor -= 0.1; redraw_zoom(palette); } static void palette_refresh(PaletteP palette) { if(palette) { if (default_palette_entries == palette->entries) default_palette_entries = NULL; palette->entries = NULL; /* If a color selection dialog is up, hide it */ if (palette->color_select_active) { palette->color_select_active = 0; color_select_hide (palette->color_select); } palette_free_palettes (); /* free palettes, don't save any modified versions */ palette_init_palettes (FALSE); /* reload palettes */ gtk_clist_freeze(GTK_CLIST(palette->clist)); gtk_clist_clear(GTK_CLIST(palette->clist)); palette_clist_init(palette->clist,palette->shell,palette->gc); gtk_clist_thaw(GTK_CLIST(palette->clist)); if(palette->entries == NULL) palette->entries = default_palette_entries; if(palette->entries == NULL && palette_entries_list) palette->entries = palette_entries_list->data; redraw_palette(palette); palette_scroll_clist_to_current(palette); palette_select_refresh_all(); palette_select2_refresh_all(); } else { palette_free_palettes (); palette_init_palettes(FALSE); } } static void palette_refresh_callback (GtkWidget *w, gpointer client_data) { palette_refresh(client_data); } /*****/ static void palette_draw_small_preview(GdkGC *gc, PaletteEntriesP p_entry) { guchar rgb_buf[SM_PREVIEW_WIDTH*SM_PREVIEW_HEIGHT*3]; GSList *tmp_link; gint index; PaletteEntryP entry; /*fill_clist_prev(p_entry,rgb_buf,48,16,0.0,1.0);*/ memset(rgb_buf,0x0,SM_PREVIEW_WIDTH*SM_PREVIEW_HEIGHT*3); gdk_draw_rgb_image (p_entry->pixmap, gc, 0, 0, SM_PREVIEW_WIDTH, SM_PREVIEW_HEIGHT, GDK_RGB_DITHER_NORMAL, rgb_buf, SM_PREVIEW_WIDTH*3); tmp_link = p_entry->colors; index = 0; while (tmp_link) { guchar cell[3*3*3]; int loop; entry = tmp_link->data; tmp_link = tmp_link->next; for(loop = 0; loop < 27 ; loop+=3) { cell[0+loop] = entry->color[0]; cell[1+loop] = entry->color[1]; cell[2+loop] = entry->color[2]; } gdk_draw_rgb_image (p_entry->pixmap, gc, 1+(index%((SM_PREVIEW_WIDTH-2)/3))*3, 1+(index/((SM_PREVIEW_WIDTH-2)/3))*3, 3, 3, GDK_RGB_DITHER_NORMAL, cell, 3); index++; if(index >= (((SM_PREVIEW_WIDTH-2)*(SM_PREVIEW_HEIGHT-2))/9)) break; } } static void palette_select_callback (int r, int g, int b, ColorSelectState state, void *client_data) { PaletteP palette; unsigned char * color; GSList *list; gint pos = 0; PaletteEntriesP p_entries = NULL; palette = client_data; if (palette && palette->entries) { switch (state) { case COLOR_SELECT_UPDATE: break; case COLOR_SELECT_OK: if (palette->color) { color = palette->color->color; color[0] = r; color[1] = g; color[2] = b; /* Update either foreground or background colors */ if (active_color == FOREGROUND) palette_set_foreground (r, g, b); else if (active_color == BACKGROUND) palette_set_background (r, g, b); palette_draw_entries (palette, palette->color->position/(palette->columns), palette->color->position%(palette->columns)); palette_draw_small_preview(palette->gc,palette->entries); /* Add into the clist */ list = palette_entries_list; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); /* to make sure we get something! */ if (p_entries == NULL) { p_entries = default_palette_entries; } if (p_entries == palette->entries) break; pos++; } gtk_clist_set_text(GTK_CLIST(palette->clist),pos,2,p_entries->name); palette_select_set_text_all(palette->entries); palette_select2_set_text_all(palette->entries); } /* Fallthrough */ case COLOR_SELECT_CANCEL: color_select_hide (palette->color_select); palette->color_select_active = 0; } } } static void palette_scroll_clist_to_current(PaletteP palette) { GSList *list; gint pos = 0; PaletteEntriesP p_entries; if(palette && palette->entries) { list = palette_entries_list; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); if (p_entries == palette->entries) break; pos++; } gtk_clist_unselect_all(GTK_CLIST(palette->clist)); gtk_clist_select_row(GTK_CLIST(palette->clist),pos,-1); gtk_clist_moveto(GTK_CLIST(palette->clist),pos,0,0.0,0.0); } } static void palette_delete_entries_callback (GtkWidget *w, gpointer client_data) { PaletteP palette; PaletteEntriesP entries; palette = client_data; if (palette && palette->entries) { entries = palette->entries; if (entries && entries->filename) palette_entries_delete (entries->filename); palette_entries_list = g_slist_remove(palette_entries_list,entries); palette_refresh(palette); } } static void palette_close_callback (GtkWidget *w, gpointer client_data) { PaletteP palette; palette = client_data; if (palette) { if (palette->color_select_active) { palette->color_select_active = 0; color_select_hide (palette->color_select); } if(import_dialog) { gtk_widget_destroy(import_dialog->dialog); g_free(import_dialog); import_dialog = NULL; } if (GTK_WIDGET_VISIBLE (palette->shell)) gtk_widget_hide (palette->shell); } } static gint palette_dialog_delete_callback (GtkWidget *w, GdkEvent *e, gpointer client_data) { palette_close_callback (w, client_data); return TRUE; } static void color_name_entry_changed (GtkWidget *widget, gpointer pdata) { PaletteP palette; palette = pdata; if(palette->color->name) g_free(palette->color->name); palette->entries->changed = 1; palette->color->name = g_strdup(gtk_entry_get_text(GTK_ENTRY (palette->color_name))); } static void palette_edit_callback (GtkWidget * widget, gpointer client_data) { PaletteP palette; unsigned char *color; palette = client_data; if (palette && palette->entries && palette->color) { color = palette->color->color; if (!palette->color_select) { palette->color_select = color_select_new (color[0], color[1], color[2], palette_select_callback, palette, FALSE); palette->color_select_active = 1; } else { if (!palette->color_select_active) { color_select_show (palette->color_select); palette->color_select_active = 1; } color_select_set_color (palette->color_select, color[0], color[1], color[2], 1); } } } static void palette_popup_menu(PaletteP palette) { GtkWidget *menu; GtkWidget *menu_items; menu = gtk_menu_new(); menu_items = gtk_menu_item_new_with_label(_("Edit")); gtk_menu_append(GTK_MENU (menu), menu_items); gtk_signal_connect(GTK_OBJECT(menu_items), "activate", GTK_SIGNAL_FUNC(palette_edit_callback), (gpointer)palette); gtk_widget_show(menu_items); menu_items = gtk_menu_item_new_with_label(_("New")); gtk_menu_append(GTK_MENU (menu), menu_items); gtk_signal_connect(GTK_OBJECT(menu_items), "activate", GTK_SIGNAL_FUNC(palette_new_callback), (gpointer)palette); gtk_widget_show(menu_items); menu_items = gtk_menu_item_new_with_label(_("Delete")); gtk_signal_connect(GTK_OBJECT(menu_items), "activate", GTK_SIGNAL_FUNC(palette_delete_entry), (gpointer)palette); gtk_menu_append(GTK_MENU (menu), menu_items); gtk_widget_show(menu_items); /* Do something interesting when the menuitem is selected */ /* gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate", */ /* GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf)); */ palette->popup_menu = menu; palette->popup_small_menu = menu = gtk_menu_new(); menu_items = gtk_menu_item_new_with_label(_("New")); gtk_menu_append(GTK_MENU (menu), menu_items); gtk_signal_connect(GTK_OBJECT(menu_items), "activate", GTK_SIGNAL_FUNC(palette_new_callback), (gpointer)palette); gtk_widget_show(menu_items); } static gint palette_color_area_events (GtkWidget *widget, GdkEvent *event, PaletteP palette) { GdkEventButton *bevent; GSList *tmp_link; int r, g, b; int width, height; int entry_width; int entry_height; int row, col; int pos; switch (event->type) { case GDK_BUTTON_PRESS: bevent = (GdkEventButton *) event; width = palette->color_area->requisition.width; height = palette->color_area->requisition.height; entry_width = (ENTRY_WIDTH*palette->zoom_factor)+SPACING; entry_height = (ENTRY_HEIGHT*palette->zoom_factor)+SPACING; col = (bevent->x - 1) / entry_width; row = (bevent->y - 1) / entry_height; pos = row * palette->columns + col; if ((bevent->button == 1 || bevent->button == 3) && palette->entries) { tmp_link = g_slist_nth (palette->entries->colors, pos); if (tmp_link) { if(palette->color) { palette->freeze_update = TRUE; palette_draw_entries(palette,-1,-1); palette->freeze_update = FALSE; } palette->color = tmp_link->data; /* Update either foreground or background colors */ r = palette->color->color[0]; g = palette->color->color[1]; b = palette->color->color[2]; if (active_color == FOREGROUND) palette_set_foreground (r, g, b); else if (active_color == BACKGROUND) palette_set_background (r, g, b); palette_draw_entries(palette,row,col); /* Update the active color name */ gtk_entry_set_text (GTK_ENTRY (palette->color_name), palette->color->name); gtk_widget_set_sensitive (palette->color_name, TRUE); /* palette_update_current_entry (palette); */ if(bevent->button == 3) { /* Popup the edit menu */ gtk_menu_popup (GTK_MENU (palette->popup_menu), NULL, NULL, NULL, NULL, 3, ((GdkEventButton *)event)->time); } } else { if(bevent->button == 3) { /* Popup the small new menu */ gtk_menu_popup (GTK_MENU (palette->popup_small_menu), NULL, NULL, NULL, NULL, 3, ((GdkEventButton *)event)->time); } } } break; default: break; } return FALSE; } void palette_insert_clist(GtkWidget *clist, GtkWidget *shell, GdkGC *gc, PaletteEntriesP p_entries, gint pos) { gchar *string[3]; string[0] = NULL; string[1] = g_strdup_printf("%d",p_entries->n_colors); string[2] = p_entries->name; gtk_clist_insert(GTK_CLIST(clist),pos,string); g_free((void *)string[1]); if(p_entries->pixmap == NULL) p_entries->pixmap = gdk_pixmap_new(shell->window, SM_PREVIEW_WIDTH, SM_PREVIEW_HEIGHT, gtk_widget_get_visual(shell)->depth); palette_draw_small_preview(gc,p_entries); gtk_clist_set_pixmap(GTK_CLIST(clist), pos, 0, p_entries->pixmap, NULL); gtk_clist_set_row_data(GTK_CLIST(clist),pos,(gpointer)p_entries); } void palette_clist_init(GtkWidget *clist, GtkWidget *shell, GdkGC *gc) { GSList *list; PaletteEntriesP p_entries = NULL; gint pos = 0; list = palette_entries_list; while (list) { p_entries = (PaletteEntriesP) list->data; list = g_slist_next (list); /* to make sure we get something! */ if (p_entries == NULL) { p_entries = default_palette_entries; } palette_insert_clist(clist,shell,gc,p_entries,pos); pos++; } } static int palette_draw_color_row (unsigned char **colors, gint ncolors, gint y, gint column_highlight, unsigned char *buffer, PaletteP palette) { unsigned char *p; unsigned char bcolor; int width, height; int entry_width; int entry_height; int vsize; int vspacing; int i, j; GtkWidget *preview; if(!palette) return -1; preview = palette->color_area; bcolor = 0; width = preview->requisition.width; height = preview->requisition.height; entry_width = (ENTRY_WIDTH*palette->zoom_factor); entry_height = (ENTRY_HEIGHT*palette->zoom_factor); if ((y >= 0) && ((y + SPACING) < height)) vspacing = SPACING; else if (y < 0) vspacing = SPACING + y; else vspacing = height - y; if (vspacing > 0) { if (y < 0) y += SPACING - vspacing; for (i = SPACING - vspacing; i < SPACING; i++, y++) { p = buffer; for (j = 0; j < width; j++) { *p++ = bcolor; *p++ = bcolor; *p++ = bcolor; } if(column_highlight >= 0) { guchar *ph = &buffer[3*column_highlight*(entry_width+SPACING)]; for(j = 0 ; j <= entry_width + SPACING; j++) { *ph++ = ~bcolor; *ph++ = ~bcolor; *ph++ = ~bcolor; } gtk_preview_draw_row (GTK_PREVIEW (preview), buffer, 0, y+entry_height+1, width); } gtk_preview_draw_row (GTK_PREVIEW (preview), buffer, 0, y, width); } if (y > SPACING) y += SPACING - vspacing; } else y += SPACING; vsize = (y >= 0) ? (entry_height) : (entry_height + y); if ((y >= 0) && ((y + entry_height) < height)) vsize = entry_height; else if (y < 0) vsize = entry_height + y; else vsize = height - y; if (vsize > 0) { p = buffer; for (i = 0; i < ncolors; i++) { for (j = 0; j < SPACING; j++) { *p++ = bcolor; *p++ = bcolor; *p++ = bcolor; } for (j = 0; j < entry_width; j++) { *p++ = colors[i][0]; *p++ = colors[i][1]; *p++ = colors[i][2]; } } for (i = 0; i < (palette->columns - ncolors); i++) { for (j = 0; j < (SPACING + entry_width); j++) { *p++ = 0; *p++ = 0; *p++ = 0; } } for (j = 0; j < SPACING; j++) { if(ncolors == column_highlight) { *p++ = ~bcolor; *p++ = ~bcolor; *p++ = ~bcolor; } else { *p++ = bcolor; *p++ = bcolor; *p++ = bcolor; } } if (y < 0) y += entry_height - vsize; for (i = 0; i < vsize; i++, y++) { if(column_highlight >= 0) { guchar *ph = &buffer[3*column_highlight*(entry_width+SPACING)]; *ph++ = ~bcolor; *ph++ = ~bcolor; *ph++ = ~bcolor; ph += 3*(entry_width); *ph++ = ~bcolor; *ph++ = ~bcolor; *ph++ = ~bcolor; } gtk_preview_draw_row (GTK_PREVIEW (preview), buffer, 0, y, width); } if (y > entry_height) y += entry_height - vsize; } else y += entry_height; return y; } static void palette_draw_entries (PaletteP palette,gint row_start, gint column_highlight) { PaletteEntryP entry; unsigned char *buffer; unsigned char **colors; GSList *tmp_link; int width, height; int entry_width; int entry_height; int index, y; if (palette && palette->entries) { width = palette->color_area->requisition.width; height = palette->color_area->requisition.height; entry_width = (ENTRY_WIDTH*palette->zoom_factor); entry_height = (ENTRY_HEIGHT*palette->zoom_factor); colors = g_malloc (sizeof(unsigned char *) * palette->columns * 3); buffer = g_malloc (width * 3); if(row_start < 0) { y = 0; tmp_link = palette->entries->colors; column_highlight = -1; } else { y = (entry_height+SPACING)*row_start; tmp_link = g_slist_nth (palette->entries->colors, row_start*palette->columns); } index = 0; while (tmp_link) { entry = tmp_link->data; tmp_link = tmp_link->next; colors[index] = entry->color; index++; if (index == palette->columns) { index = 0; y = palette_draw_color_row (colors, palette->columns, y, column_highlight, buffer, palette); if (y >= height || row_start >= 0) { /* This row only */ gtk_widget_draw (palette->color_area, NULL); g_free (buffer); g_free (colors); return; } } } while (y < height) { y = palette_draw_color_row (colors, index, y, column_highlight, buffer, palette); index = 0; if(row_start >= 0) break; } g_free (buffer); g_free (colors); if(palette->freeze_update == FALSE) gtk_widget_draw (palette->color_area, NULL); } } static void palette_scroll_top_left(PaletteP palette) { GtkAdjustment *hadj; GtkAdjustment *vadj; /* scroll viewport to top left */ if(palette && palette->scrolled_window) { hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(palette->scrolled_window)); vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(palette->scrolled_window)); if(hadj) gtk_adjustment_set_value(hadj,0.0); if(vadj) gtk_adjustment_set_value(vadj,0.0); } } static void redraw_palette(PaletteP palette) { gint vsize; gint nrows; gint n_entries; GtkWidget *parent; gint new_pre_width; n_entries = palette->entries->n_colors; nrows = n_entries / palette->columns; if (n_entries % palette->columns) nrows += 1; vsize = nrows*(SPACING + (gint)(ENTRY_HEIGHT*palette->zoom_factor))+SPACING; parent = palette->color_area->parent; gtk_widget_ref(palette->color_area); gtk_container_remove(GTK_CONTAINER(parent),palette->color_area); new_pre_width = (gint)(ENTRY_WIDTH*palette->zoom_factor); new_pre_width = (new_pre_width+SPACING)*palette->columns+SPACING; gtk_preview_size(GTK_PREVIEW(palette->color_area), new_pre_width, /*PREVIEW_WIDTH,*/ vsize); gtk_container_add(GTK_CONTAINER(parent),palette->color_area); gtk_widget_unref(palette->color_area); palette_draw_entries(palette,-1,-1); } static void palette_list_item_update(GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data) { PaletteP palette; PaletteEntriesP p_entries; palette = (PaletteP)data; if (palette->color_select_active) { palette->color_select_active = 0; color_select_hide (palette->color_select); } if(palette->color_select) color_select_free(palette->color_select); palette->color_select = NULL; p_entries = (PaletteEntriesP)gtk_clist_get_row_data(GTK_CLIST(palette->clist),row); palette->entries = p_entries; redraw_palette(palette); palette_scroll_top_left(palette); /* Stop errors in case no colours are selected */ gtk_signal_handler_block(GTK_OBJECT (palette->color_name),palette->entry_sig_id); gtk_entry_set_text (GTK_ENTRY (palette->color_name), _("Undefined")); gtk_widget_set_sensitive (palette->color_name, FALSE); gtk_signal_handler_unblock(GTK_OBJECT (palette->color_name),palette->entry_sig_id); } static void palette_edit_palette_callback (GtkWidget *w, gpointer client_data) { PaletteEntriesP p_entries = NULL; PaletteP palette = (PaletteP)client_data; GList *sel_list; sel_list = GTK_CLIST(palette->clist)->selection; if(sel_list) { while (sel_list) { gint row; row = GPOINTER_TO_INT (sel_list->data); p_entries = (PaletteEntriesP)gtk_clist_get_row_data(GTK_CLIST(palette->clist),row); palette_create_edit(p_entries); /* One only */ return; } } } PaletteP create_palette_dialog (gint vert) { GtkWidget *palette_dialog; GtkWidget *dialog_vbox3; GtkWidget *hbox3; GtkWidget *hbox4; GtkWidget *hbox5; GtkWidget *vbox4; GtkWidget *palette_scrolledwindow; GtkWidget *palette_region; GtkWidget *color_name; GtkWidget *alignment1; GtkWidget *palette_list; GtkWidget *frame1; GtkWidget *vbuttonbox2; GtkWidget *new_palette; GtkWidget *delete_palette; GtkWidget *save_palettes; GtkWidget *import_palette; GtkWidget *merge_palette; GtkWidget *dialog_action_area3; GtkWidget *alignment2; GtkWidget *hbuttonbox3; GtkWidget *close_button; GtkWidget *refresh_button; GtkWidget *clist_scrolledwindow; PaletteP palette; GdkColormap *colormap; GtkWidget* button_plus; GtkWidget* button_minus; GtkWidget* pixmapwid; GdkPixmap* pixmap; GdkBitmap* mask; GtkStyle* style; palette = g_malloc (sizeof (_Palette)); palette->entries = default_palette_entries; palette->color = NULL; palette->color_select = NULL; palette->color_select_active = 0; palette->zoom_factor = 1.0; palette->columns = COLUMNS; palette->freeze_update = FALSE; palette->shell = palette_dialog = gtk_dialog_new (); gtk_window_set_wmclass (GTK_WINDOW (palette->shell), "color_palette", "Gimp"); if(!vert) { gtk_widget_set_usize (palette_dialog, 615, 200); } else { gtk_widget_set_usize (palette_dialog, 230, 300); } if(!vert) { gtk_window_set_title (GTK_WINDOW (palette_dialog), _("Color Palette Edit")); } else { gtk_window_set_title (GTK_WINDOW (palette_dialog), _("Color Palette")); } gtk_window_set_policy (GTK_WINDOW (palette_dialog), TRUE, TRUE, FALSE); dialog_vbox3 = GTK_DIALOG (palette_dialog)->vbox; gtk_object_set_data (GTK_OBJECT (palette_dialog), "dialog_vbox3", dialog_vbox3); gtk_widget_show (dialog_vbox3); if(vert) { hbox3 = gtk_notebook_new(); gtk_widget_show (hbox3); gtk_box_pack_start (GTK_BOX (dialog_vbox3), hbox3, TRUE, TRUE, 0); } else { hbox3 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox3); gtk_box_pack_start (GTK_BOX (dialog_vbox3), hbox3, TRUE, TRUE, 0); } vbox4 = gtk_vbox_new (FALSE, 0); gtk_object_set_data (GTK_OBJECT (palette_dialog), "vbox4", vbox4); gtk_widget_show (vbox4); if(!vert) { gtk_box_pack_start (GTK_BOX (hbox3), vbox4, TRUE, TRUE, 0); } alignment1 = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_object_set_data (GTK_OBJECT (palette_dialog), "alignment1", alignment1); gtk_widget_show (alignment1); palette->scrolled_window = palette_scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (palette_scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_object_set_data (GTK_OBJECT (palette_dialog), "palette_scrolledwindow", palette_scrolledwindow); gtk_widget_show (palette_scrolledwindow); gtk_box_pack_start (GTK_BOX (vbox4), palette_scrolledwindow, TRUE, TRUE, 0); palette->color_area = palette_region = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_set_dither (GTK_PREVIEW (palette->color_area), GDK_RGB_DITHER_MAX); gtk_preview_size (GTK_PREVIEW (palette_region), PREVIEW_WIDTH, PREVIEW_HEIGHT); gtk_widget_set_events (palette_region, PALETTE_EVENT_MASK); gtk_signal_connect (GTK_OBJECT (palette->color_area), "event", (GtkSignalFunc) palette_color_area_events, palette); gtk_widget_show (palette_region); gtk_container_add (GTK_CONTAINER (alignment1), palette_region); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (palette_scrolledwindow), alignment1); hbox4 = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox4), hbox4, FALSE, FALSE, 0); gtk_widget_show(hbox4); palette->color_name = color_name = gtk_entry_new (); gtk_widget_show (color_name); gtk_box_pack_start (GTK_BOX (hbox4), color_name, TRUE, TRUE, 0); gtk_entry_set_text (GTK_ENTRY (color_name), _("Undefined")); palette->entry_sig_id = gtk_signal_connect (GTK_OBJECT (color_name), "changed", GTK_SIGNAL_FUNC (color_name_entry_changed), palette); /* + and - buttons */ style = gtk_widget_get_style(palette_dialog); gtk_widget_realize(palette_dialog); button_plus = gtk_button_new (); GTK_WIDGET_UNSET_FLAGS (button_plus, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (button_plus), "clicked", GTK_SIGNAL_FUNC (palette_zoomin), (gpointer) palette); gtk_box_pack_start (GTK_BOX (hbox4), button_plus, FALSE, FALSE, 0); button_minus = gtk_button_new (); GTK_WIDGET_UNSET_FLAGS (button_minus, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (button_minus), "clicked", GTK_SIGNAL_FUNC (palette_zoomout), (gpointer) palette); gtk_box_pack_start (GTK_BOX (hbox4), button_minus, FALSE, FALSE, 0); pixmap = gdk_pixmap_create_from_xpm_d(palette_dialog->window, &mask, &style->bg[GTK_STATE_NORMAL], zoom_in_xpm); pixmapwid = gtk_pixmap_new(pixmap, mask); gtk_container_add (GTK_CONTAINER (button_plus), pixmapwid); gtk_widget_show (pixmapwid); pixmap = gdk_pixmap_create_from_xpm_d(palette_dialog->window, &mask, &style->bg[GTK_STATE_NORMAL], zoom_out_xpm); pixmapwid = gtk_pixmap_new(pixmap, mask); gtk_container_add (GTK_CONTAINER (button_minus), pixmapwid); gtk_widget_show (pixmapwid); gtk_widget_show (button_plus); gtk_widget_show (button_minus); /* clist preview of palettes */ clist_scrolledwindow = gtk_scrolled_window_new (NULL, NULL); palette->clist = palette_list = gtk_clist_new (3); gtk_object_set_data (GTK_OBJECT (palette_dialog), "palette_list", palette_list); gtk_clist_set_row_height(GTK_CLIST(palette_list),SM_PREVIEW_HEIGHT+2); gtk_signal_connect(GTK_OBJECT(palette->clist), "select_row", GTK_SIGNAL_FUNC(palette_list_item_update), (gpointer) palette); if(vert) { gtk_widget_set_usize (palette_list, 203, 90); gtk_notebook_append_page(GTK_NOTEBOOK(hbox3), vbox4, gtk_label_new("Palette")); gtk_notebook_append_page(GTK_NOTEBOOK(hbox3), clist_scrolledwindow, gtk_label_new("Select")); gtk_widget_show (palette_list); } else { gtk_container_add (GTK_CONTAINER (hbox3), clist_scrolledwindow); gtk_widget_set_usize (palette_list, 203, -1); gtk_widget_show (palette_list); } gtk_clist_set_column_title(GTK_CLIST(palette_list), 0, _("Palette")); gtk_clist_set_column_title(GTK_CLIST(palette_list), 1, _("Ncols")); gtk_clist_set_column_title(GTK_CLIST(palette_list), 2, _("Name")); gtk_clist_column_titles_show(GTK_CLIST(palette_list)); gtk_container_add (GTK_CONTAINER (clist_scrolledwindow), GTK_WIDGET(palette->clist)); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (clist_scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); if(!vert) { gtk_clist_set_selection_mode(GTK_CLIST(palette_list),GTK_SELECTION_EXTENDED); } gtk_widget_show(clist_scrolledwindow); gtk_container_border_width (GTK_CONTAINER (palette_list), 4); gtk_clist_set_column_width (GTK_CLIST (palette_list), 0, SM_PREVIEW_WIDTH+2); gtk_clist_column_titles_show (GTK_CLIST (palette_list)); if(!vert) { frame1 = gtk_frame_new (_("Palette Ops")); gtk_object_set_data (GTK_OBJECT (palette_dialog), "frame1", frame1); gtk_widget_show (frame1); gtk_box_pack_end (GTK_BOX (hbox3), frame1, FALSE, FALSE, 7); vbuttonbox2 = gtk_vbutton_box_new (); gtk_object_set_data (GTK_OBJECT (palette_dialog), "vbuttonbox2", vbuttonbox2); gtk_widget_show (vbuttonbox2); gtk_container_add (GTK_CONTAINER (frame1), vbuttonbox2); gtk_container_border_width (GTK_CONTAINER (vbuttonbox2), 6); gtk_button_box_set_layout (GTK_BUTTON_BOX (vbuttonbox2), GTK_BUTTONBOX_SPREAD); gtk_button_box_set_spacing (GTK_BUTTON_BOX (vbuttonbox2), 0); gtk_button_box_set_child_size (GTK_BUTTON_BOX (vbuttonbox2), 44, 22); gtk_button_box_set_child_ipadding (GTK_BUTTON_BOX (vbuttonbox2), 17, 0); new_palette = gtk_button_new_with_label (_("New")); GTK_WIDGET_UNSET_FLAGS (new_palette, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (new_palette), "clicked", (GtkSignalFunc) palette_new_entries_callback, (gpointer) palette); gtk_object_set_data (GTK_OBJECT (palette_dialog), "new_palette", new_palette); gtk_widget_show (new_palette); gtk_container_add (GTK_CONTAINER (vbuttonbox2), new_palette); delete_palette = gtk_button_new_with_label (_("Delete")); GTK_WIDGET_UNSET_FLAGS (delete_palette, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (delete_palette), "clicked", (GtkSignalFunc) palette_delete_entries_callback, (gpointer) palette); gtk_widget_show (delete_palette); gtk_container_add (GTK_CONTAINER (vbuttonbox2), delete_palette); save_palettes = gtk_button_new_with_label (_("Save")); GTK_WIDGET_UNSET_FLAGS (save_palettes, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (save_palettes), "clicked", (GtkSignalFunc) palette_save_palettes_callback, (gpointer) NULL); gtk_widget_show (save_palettes); gtk_container_add (GTK_CONTAINER (vbuttonbox2), save_palettes); import_palette = gtk_button_new_with_label (_("Import")); GTK_WIDGET_UNSET_FLAGS (import_palette, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (import_palette), "clicked", (GtkSignalFunc) palette_import_dialog_callback, (gpointer) palette); gtk_widget_show (import_palette); gtk_container_add (GTK_CONTAINER (vbuttonbox2), import_palette); merge_palette = gtk_button_new_with_label (_("Merge")); GTK_WIDGET_UNSET_FLAGS (merge_palette, GTK_RECEIVES_DEFAULT); gtk_signal_connect (GTK_OBJECT (merge_palette), "clicked", (GtkSignalFunc) palette_merge_dialog_callback, (gpointer) palette); gtk_widget_show (merge_palette); gtk_container_add (GTK_CONTAINER (vbuttonbox2), merge_palette); } dialog_action_area3 = GTK_DIALOG (palette_dialog)->action_area; gtk_object_set_data (GTK_OBJECT (palette_dialog), "dialog_action_area3", dialog_action_area3); gtk_widget_show (dialog_action_area3); gtk_container_border_width (GTK_CONTAINER (dialog_action_area3), 2); alignment2 = gtk_alignment_new (0.5, 0.5, 1, 1); gtk_object_set_data (GTK_OBJECT (palette_dialog), "alignment2", alignment2); gtk_widget_show (alignment2); gtk_box_pack_start (GTK_BOX (dialog_action_area3), alignment2, TRUE, TRUE, 0); hbox5 = gtk_hbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (alignment2), hbox5); gtk_widget_show (hbox5); hbuttonbox3 = gtk_hbutton_box_new (); gtk_object_set_data (GTK_OBJECT (palette_dialog), "hbuttonbox3", hbuttonbox3); gtk_widget_show (hbuttonbox3); gtk_box_pack_end (GTK_BOX(hbox5), hbuttonbox3, FALSE, FALSE, 0); gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox3), 4); gtk_signal_connect (GTK_OBJECT (palette->shell), "delete_event", GTK_SIGNAL_FUNC (palette_dialog_delete_callback), palette); close_button = gtk_button_new_with_label (_("Close")); GTK_WIDGET_SET_FLAGS (close_button, GTK_CAN_DEFAULT); gtk_window_set_default (GTK_WINDOW (palette->shell), close_button); gtk_signal_connect(GTK_OBJECT(close_button), "clicked", GTK_SIGNAL_FUNC(palette_close_callback), (gpointer)palette); if(!vert) { refresh_button = gtk_button_new_with_label (_("Refresh")); gtk_signal_connect(GTK_OBJECT(refresh_button), "clicked", GTK_SIGNAL_FUNC(palette_refresh_callback), (gpointer)palette); } else { refresh_button = gtk_button_new_with_label (_("Edit")); gtk_signal_connect(GTK_OBJECT(refresh_button), "clicked", GTK_SIGNAL_FUNC(palette_edit_palette_callback), (gpointer)palette); } GTK_WIDGET_SET_FLAGS (refresh_button, GTK_CAN_DEFAULT); gtk_container_add (GTK_CONTAINER (hbuttonbox3), refresh_button); gtk_widget_show (refresh_button); gtk_container_add (GTK_CONTAINER (hbuttonbox3), close_button); gtk_widget_show (close_button); gtk_widget_realize(palette->shell); palette->gc = gdk_gc_new(palette->shell->window); colormap = gtk_widget_get_colormap(palette->clist); palette_popup_menu(palette); return palette; } static void import_dialog_select_grad_callback (GtkWidget *w, gpointer client_data) { /* Popup grad edit box .... */ grad_create_gradient_editor(); } static void import_dialog_close_callback (GtkWidget *w, gpointer client_data) { gtk_widget_destroy(import_dialog->dialog); g_free(import_dialog); import_dialog = NULL; } static void import_palette_create_from_grad(gchar *name,PaletteP palette) { PaletteEntriesP entries; if(curr_gradient) { /* Add names to entry */ double dx, cur_x; double r, g, b, a; extern void grad_get_color_at(double, double *, double *, double *, double *); gint sample_sz; gint loop; entries = palette_create_entries(palette,name); sample_sz = (gint)import_dialog->sample->value; dx = 1.0/ (sample_sz - 1); cur_x = 0; for (loop = 0 ; loop < sample_sz; loop++) { grad_get_color_at(cur_x, &r, &g, &b, &a); r = r * 255.0; g = g * 255.0; b = b * 255.0; cur_x += dx; palette_add_entry (palette->entries, _("Untitled"), (gint)r, (gint)g, (gint)b); } palette_update_small_preview(palette); redraw_palette(palette); /* Update other selectors on screen */ palette_select_clist_insert_all(entries); palette_select2_clist_insert_all(entries); palette_scroll_clist_to_current(palette); } } static void import_dialog_import_callback (GtkWidget *w, gpointer client_data) { PaletteP palette; palette = client_data; if(import_dialog) { guchar *pname; pname = gtk_entry_get_text(GTK_ENTRY(import_dialog->entry)); if(!pname || strlen(pname) == 0) pname = g_strdup("tmp"); else pname = g_strdup(pname); switch(import_dialog->import_type) { case GRAD_IMPORT: import_palette_create_from_grad(pname,palette); break; case IMAGE_IMPORT: import_palette_create_from_image(import_dialog->gimage,pname,palette); break; default: break; } import_dialog_close_callback(NULL,NULL); } } static gint import_dialog_delete_callback (GtkWidget *w, GdkEvent *e, gpointer client_data) { import_dialog_close_callback(w,client_data); return TRUE; } static void palette_merge_entries_callback (GtkWidget *w, gpointer client_data, gpointer call_data) { PaletteP palette; PaletteEntriesP p_entries; PaletteEntriesP new_entries; GList *sel_list; new_entries = palette_create_entries(client_data,call_data); palette = (PaletteP)client_data; sel_list = GTK_CLIST(palette->clist)->selection; if(sel_list) { while (sel_list) { gint row; GSList *cols; row = GPOINTER_TO_INT (sel_list->data); p_entries = (PaletteEntriesP)gtk_clist_get_row_data(GTK_CLIST(palette->clist),row); /* Go through each palette and merge the colours */ cols = p_entries->colors; while(cols) { PaletteEntryP entry = cols->data; palette_add_entry (new_entries, g_strdup(entry->name), entry->color[0], entry->color[1], entry->color[2]); cols = cols->next; } sel_list = sel_list->next; } } palette_update_small_preview(palette); redraw_palette(palette); gtk_clist_unselect_all(GTK_CLIST(palette->clist)); /* Update other selectors on screen */ palette_select_clist_insert_all(new_entries); palette_select2_clist_insert_all(new_entries); palette_scroll_clist_to_current(palette); } static void palette_merge_dialog_callback (GtkWidget *w, gpointer client_data) { query_string_box (_("Merge Palette"), _("Enter a name for merged palette"), NULL, NULL, NULL, palette_merge_entries_callback, client_data); } static void palette_import_dialog_callback (GtkWidget *w, gpointer client_data) { if(!import_dialog) { import_dialog = palette_import_dialog((PaletteP)client_data); gtk_widget_show(import_dialog->dialog); } else { gdk_window_raise(import_dialog->dialog->window); } } static void palette_import_fill_grad_preview(GtkWidget *preview, gradient_t *gradient) { guchar buffer[3*IMPORT_PREVIEW_WIDTH]; gint loop; guchar *p = buffer; double dx, cur_x; double r, g, b, a; extern void grad_get_color_at(double, double *, double *, double *, double *); gradient_t *last_grad; dx = 1.0/ (IMPORT_PREVIEW_WIDTH - 1); cur_x = 0; last_grad = curr_gradient; curr_gradient = gradient; for (loop = 0 ; loop < IMPORT_PREVIEW_WIDTH; loop++) { grad_get_color_at(cur_x, &r, &g, &b, &a); *p++ = r * 255.0; *p++ = g * 255.0; *p++ = b * 255.0; cur_x += dx; } curr_gradient = last_grad; for (loop = 0 ; loop < IMPORT_PREVIEW_HEIGHT; loop++) { gtk_preview_draw_row (GTK_PREVIEW (preview), buffer, 0, loop, IMPORT_PREVIEW_WIDTH); } gtk_widget_draw (preview, NULL); } void import_palette_grad_update(gradient_t *grad) { if(import_dialog && import_dialog->import_type == GRAD_IMPORT) { /* redraw gradient */ palette_import_fill_grad_preview(import_dialog->preview,grad); gtk_entry_set_text (GTK_ENTRY (import_dialog->entry), grad->name); } } static void import_grad_callback(GtkWidget *widget, gpointer data) { if(import_dialog) { import_dialog->import_type = GRAD_IMPORT; if(import_dialog->image_list) { gtk_widget_hide(import_dialog->image_list); gtk_widget_destroy(import_dialog->image_list); import_dialog->image_list = NULL; } gtk_widget_show(import_dialog->select); palette_import_fill_grad_preview(import_dialog->preview,curr_gradient); gtk_entry_set_text (GTK_ENTRY (import_dialog->entry), curr_gradient->name); gtk_widget_set_sensitive(import_dialog->threshold_scale,FALSE); gtk_widget_set_sensitive(import_dialog->threshold_text,FALSE); } } static void gimlist_cb(gpointer im, gpointer data){ GSList** l=(GSList**)data; *l=g_slist_prepend(*l, im); } static void import_image_update_image_preview(GimpImage *gimage) { TempBuf * preview_buf; gchar *src, *buf; gint x,y,has_alpha; gint sel_width, sel_height; gint pwidth, pheight; import_dialog->gimage = gimage; /* Calculate preview size */ sel_width = gimage->width; sel_height = gimage->height; if (sel_width > sel_height) { pwidth = MIN(sel_width, IMPORT_PREVIEW_WIDTH); pheight = sel_height * pwidth / sel_width; } else { pheight = MIN(sel_height, IMPORT_PREVIEW_HEIGHT); pwidth = sel_width * pheight / sel_height; } /* Min size is 2 */ preview_buf = gimp_image_construct_composite_preview(gimage, MAX(pwidth, 2), MAX(pheight, 2)); gtk_preview_size(GTK_PREVIEW(import_dialog->preview), preview_buf->width, preview_buf->height); buf = g_new (gchar, IMPORT_PREVIEW_WIDTH * 3); src = (gchar *)temp_buf_data (preview_buf); has_alpha = (preview_buf->bytes == 2 || preview_buf->bytes == 4); for (y = 0; y height ; y++) { if (preview_buf->bytes == (1+has_alpha)) for (x = 0; x < preview_buf->width; x++) { buf[x*3+0] = src[x]; buf[x*3+1] = src[x]; buf[x*3+2] = src[x]; } else for (x = 0; x < preview_buf->width; x++) { gint stride = 3 + has_alpha; buf[x*3+0] = src[x*stride+0]; buf[x*3+1] = src[x*stride+1]; buf[x*3+2] = src[x*stride+2]; } gtk_preview_draw_row (GTK_PREVIEW (import_dialog->preview), (guchar *)buf, 0, y, preview_buf->width); src += preview_buf->width * preview_buf->bytes; } g_free(buf); temp_buf_free(preview_buf); gtk_widget_hide(import_dialog->preview); gtk_widget_draw(import_dialog->preview, NULL); gtk_widget_show(import_dialog->preview); } static void import_image_sel_callback(GtkWidget *widget, gpointer data) { GimpImage *gimage; gchar *lab; gimage = GIMP_IMAGE(data); import_image_update_image_preview(gimage); lab = g_strdup_printf("%s-%d", g_basename(gimage_filename(import_dialog->gimage)), pdb_image_to_id (import_dialog->gimage)); gtk_entry_set_text (GTK_ENTRY (import_dialog->entry),lab); } static void import_image_menu_add(GimpImage *gimage) { GtkWidget *menuitem; gchar *lab = g_strdup_printf("%s-%d", g_basename(gimage_filename(gimage)), pdb_image_to_id (gimage)); menuitem = gtk_menu_item_new_with_label(lab); gtk_widget_show (menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc) import_image_sel_callback, gimage); gtk_menu_append (GTK_MENU (import_dialog->optionmenu1_menu), menuitem); } /* Last Param gives us control over what goes in the menu on a delete oper */ static void import_image_menu_activate(gint redo,GimpImage * del_image) { GSList *list=NULL; gint num_images; GimpImage *last_img = NULL; GimpImage *first_img = NULL; gint act_num = -1; gint count = 0; gchar *lab; if(import_dialog) { if(import_dialog->import_type == IMAGE_IMPORT) { if(!redo) return; else { if(import_dialog->image_list) { last_img = import_dialog->gimage; gtk_widget_hide(import_dialog->image_list); gtk_widget_destroy(import_dialog->image_list); import_dialog->image_list = NULL; } } } import_dialog->import_type = IMAGE_IMPORT; /* Get list of images */ gimage_foreach(gimlist_cb, &list); num_images = g_slist_length (list); if (num_images) { int i; GtkWidget *optionmenu1; GtkWidget *optionmenu1_menu; import_dialog->image_list = optionmenu1 = gtk_option_menu_new (); gtk_widget_set_usize (optionmenu1,IMPORT_PREVIEW_WIDTH,-1); import_dialog->optionmenu1_menu = optionmenu1_menu = gtk_menu_new (); for (i = 0; i < num_images; i++, list = g_slist_next (list)) { if(GIMP_IMAGE(list->data) != del_image) { if(first_img == NULL) first_img = GIMP_IMAGE(list->data); import_image_menu_add(GIMP_IMAGE(list->data)); if(last_img == GIMP_IMAGE(list->data)) act_num = count; else count++; } } gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu1), optionmenu1_menu); gtk_widget_hide(import_dialog->select); gtk_container_add(GTK_CONTAINER(import_dialog->select_area),optionmenu1); if(last_img != NULL && last_img != del_image) import_image_update_image_preview(last_img); else if(first_img != NULL) import_image_update_image_preview(first_img); gtk_widget_show (optionmenu1); /* reset to last one */ if(redo && act_num >= 0) { gchar *lab = g_strdup_printf("%s-%d", g_basename(gimage_filename(import_dialog->gimage)), pdb_image_to_id (import_dialog->gimage)); gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu1),act_num); gtk_entry_set_text (GTK_ENTRY (import_dialog->entry),lab); } } g_slist_free(list); lab = g_strdup_printf("%s-%d", g_basename(gimage_filename(import_dialog->gimage)), pdb_image_to_id (import_dialog->gimage)); gtk_entry_set_text (GTK_ENTRY (import_dialog->entry),lab); } } static void import_image_callback(GtkWidget *widget, gpointer data) { import_image_menu_activate(FALSE,NULL); gtk_widget_set_sensitive(import_dialog->threshold_scale,TRUE); gtk_widget_set_sensitive(import_dialog->threshold_text,TRUE); } static gint image_count() { GSList *list=NULL; gint num_images = 0; gimage_foreach(gimlist_cb, &list); num_images = g_slist_length (list); g_slist_free(list); return (num_images); } static ImportDialogP palette_import_dialog(PaletteP palette) { GtkWidget *dialog1; GtkWidget *dialog_vbox1; GtkWidget *hbox2; GtkWidget *import_frame; GtkWidget *vbox2; GtkWidget *table1; GtkWidget *steps; GtkWidget *import_name; GtkWidget *import_type; GtkWidget *spinbutton2; GtkWidget *entry1; GtkWidget *optionmenu1; GtkWidget *optionmenu1_menu; GtkWidget *menuitem; GtkWidget *preview_frame; GtkWidget *vbox1; GtkWidget *image1; GtkWidget *select; GtkWidget *dialog_action_area1; GtkWidget *hbox1; GtkWidget *hscale1; GtkWidget *import; GtkWidget *close; import_dialog = g_malloc(sizeof(struct _ImportDialog)); import_dialog->image_list = NULL; import_dialog->gimage = NULL; import_dialog->dialog = dialog1 = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (dialog1), _("Import Palette")); gtk_window_set_policy (GTK_WINDOW (dialog1), TRUE, TRUE, FALSE); dialog_vbox1 = GTK_DIALOG (dialog1)->vbox; gtk_widget_show (dialog_vbox1); hbox2 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox2); gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox2, FALSE, FALSE, 0); import_frame = gtk_frame_new (_("Import")); gtk_widget_show (import_frame); gtk_box_pack_start (GTK_BOX (hbox2), import_frame, TRUE, TRUE, 0); vbox2 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox2); gtk_container_add (GTK_CONTAINER (import_frame), vbox2); table1 = gtk_table_new (4, 2, FALSE); gtk_widget_show (table1); gtk_box_pack_start (GTK_BOX (vbox2), table1, TRUE, TRUE, 0); steps = gtk_label_new (_("Sample Size:")); gtk_widget_show (steps); gtk_table_attach (GTK_TABLE (table1), steps, 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0); gtk_label_set_justify (GTK_LABEL (steps), GTK_JUSTIFY_LEFT); import_dialog->threshold_text = steps = gtk_label_new (_("Interval:")); gtk_widget_show (steps); gtk_table_attach (GTK_TABLE (table1), steps, 0, 1, 3, 4, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0); gtk_label_set_justify (GTK_LABEL (steps), GTK_JUSTIFY_LEFT); gtk_widget_set_sensitive(steps,FALSE); import_name = gtk_label_new (_("Name:")); gtk_widget_show (import_name); gtk_table_attach (GTK_TABLE (table1), import_name, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0); gtk_label_set_justify (GTK_LABEL (import_name), GTK_JUSTIFY_LEFT); import_type = gtk_label_new (_("Source:")); gtk_widget_show (import_type); gtk_table_attach (GTK_TABLE (table1), import_type, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0); gtk_label_set_justify (GTK_LABEL (import_type), GTK_JUSTIFY_LEFT); import_dialog->sample = GTK_ADJUSTMENT(gtk_adjustment_new (256, 2, 10000, 1, 10, 10)); spinbutton2 = gtk_spin_button_new (import_dialog->sample, 1, 0); gtk_widget_show (spinbutton2); gtk_table_attach (GTK_TABLE (table1), spinbutton2, 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0); import_dialog->threshold_scale = hscale1 = gtk_hscale_new (import_dialog->threshold = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 128, 1, 1, 1))); gtk_scale_set_value_pos (GTK_SCALE (hscale1), GTK_POS_TOP); gtk_scale_set_digits (GTK_SCALE (hscale1), 0); gtk_widget_show (hscale1); gtk_table_attach (GTK_TABLE (table1), hscale1, 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0); gtk_widget_set_sensitive(hscale1,FALSE); import_dialog->entry = entry1 = gtk_entry_new (); gtk_widget_show (entry1); gtk_table_attach (GTK_TABLE (table1), entry1, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); /* gtk_widget_set_usize (entry1, 100, -1); */ gtk_entry_set_text (GTK_ENTRY (entry1), (curr_gradient)?curr_gradient->name:_("new_import")); import_dialog->type_option = optionmenu1 = gtk_option_menu_new (); gtk_widget_show (optionmenu1); gtk_table_attach (GTK_TABLE (table1), optionmenu1, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); optionmenu1_menu = gtk_menu_new (); import_dialog->image_menu_item_gradient = menuitem = gtk_menu_item_new_with_label (_("Gradient")); gtk_widget_show (menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc) import_grad_callback, NULL); gtk_menu_append (GTK_MENU (optionmenu1_menu), menuitem); import_dialog->image_menu_item_image = menuitem = gtk_menu_item_new_with_label ("Image"); gtk_widget_show (menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc) import_image_callback, (gpointer)import_dialog); gtk_menu_append (GTK_MENU (optionmenu1_menu), menuitem); gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu1), optionmenu1_menu); gtk_widget_set_sensitive(menuitem,image_count() > 0); preview_frame = gtk_frame_new (_("Preview")); gtk_widget_show (preview_frame); gtk_box_pack_start (GTK_BOX (hbox2), preview_frame, TRUE, TRUE, 0); import_dialog->select_area = vbox1 = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox1); gtk_container_add (GTK_CONTAINER (preview_frame), vbox1); import_dialog->preview = image1 = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_set_dither (GTK_PREVIEW (image1), GDK_RGB_DITHER_MAX); gtk_preview_size (GTK_PREVIEW (image1), IMPORT_PREVIEW_WIDTH, IMPORT_PREVIEW_HEIGHT); gtk_widget_show (image1); gtk_widget_set_usize (image1,IMPORT_PREVIEW_WIDTH, IMPORT_PREVIEW_HEIGHT); gtk_box_pack_start (GTK_BOX (vbox1), image1, FALSE, FALSE, 0); import_dialog->select = select = gtk_button_new_with_label (_("select")); gtk_signal_connect(GTK_OBJECT(select), "clicked", GTK_SIGNAL_FUNC(import_dialog_select_grad_callback),(gpointer)image1); gtk_widget_show (select); gtk_box_pack_start (GTK_BOX (vbox1), select, FALSE, FALSE, 0); dialog_action_area1 = GTK_DIALOG (dialog1)->action_area; gtk_container_border_width (GTK_CONTAINER (dialog_action_area1), 2); gtk_widget_show (dialog_action_area1); hbox1 = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox1); gtk_box_pack_start (GTK_BOX (dialog_action_area1), hbox1, TRUE, TRUE, 0); import = gtk_button_new_with_label (_("import")); gtk_widget_show (import); gtk_signal_connect(GTK_OBJECT(import), "clicked", GTK_SIGNAL_FUNC(import_dialog_import_callback),(gpointer)palette); gtk_container_border_width (GTK_CONTAINER (import), 4); gtk_box_pack_end (GTK_BOX (hbox1), import, FALSE, FALSE, 0); close = gtk_button_new_with_label (_("close")); gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(import_dialog_close_callback),(gpointer)NULL); gtk_widget_show (close); gtk_box_pack_start (GTK_BOX (hbox1), close, FALSE, FALSE, 0); GTK_WIDGET_SET_FLAGS (close, GTK_CAN_DEFAULT); gtk_widget_grab_default (close); gtk_signal_connect (GTK_OBJECT (dialog1), "delete_event", GTK_SIGNAL_FUNC (import_dialog_delete_callback), (gpointer)palette); /* Fill with the selected gradient */ palette_import_fill_grad_preview(image1,curr_gradient); import_dialog->import_type = GRAD_IMPORT; return import_dialog; } /* Stuff to keep dialog uptodate */ void palette_import_image_new(GimpImage * gimage) { if(!import_dialog) return; if(!GTK_WIDGET_IS_SENSITIVE(import_dialog->image_menu_item_image)) { gtk_widget_set_sensitive(import_dialog->image_menu_item_image,TRUE); return; } /* Now fill in the names if image menu shown */ if(import_dialog->import_type == IMAGE_IMPORT) { import_image_menu_activate(TRUE,NULL); } } void palette_import_image_destroyed(GimpImage* gimage) { /* Now fill in the names if image menu shown */ if(!import_dialog) return; if(image_count() <= 1) { /* Back to gradient type */ gtk_option_menu_set_history(GTK_OPTION_MENU(import_dialog->type_option),0); import_grad_callback(NULL,NULL); if(import_dialog->image_menu_item_image) gtk_widget_set_sensitive(import_dialog->image_menu_item_image,FALSE); return; } if(import_dialog->import_type == IMAGE_IMPORT) { import_image_menu_activate(TRUE,gimage); } } void palette_import_image_renamed(GimpImage* gimage) { /* Now fill in the names if image menu shown */ if(import_dialog && import_dialog->import_type == IMAGE_IMPORT) { import_image_menu_activate(TRUE,NULL); } } struct _img_colours { guint count; guint r_adj; guint g_adj; guint b_adj; guchar r; guchar g; guchar b; }; typedef struct _img_colours ImgColours, *ImgColoursP; static int count_colour_entries = 0; static void create_storted_list(gpointer key,gpointer value,gpointer user_data) { GSList **sorted_list = (GSList**)user_data; ImgColoursP colour_tab = (ImgColoursP)value; *sorted_list = g_slist_prepend(*sorted_list,colour_tab); } static void create_image_palette(gpointer data,gpointer user_data) { PaletteP palette = (PaletteP)user_data; ImgColoursP colour_tab = (ImgColoursP)data; gint sample_sz; gchar *lab; sample_sz = (gint)import_dialog->sample->value; if(palette->entries->n_colors >= sample_sz) return; lab = g_strdup_printf("%s (occurs %u)",_("Untitled"),colour_tab->count); /* Adjust the colours to the mean of the the sample */ palette_add_entry (palette->entries, lab, (gint)colour_tab->r + (colour_tab->r_adj/colour_tab->count), (gint)colour_tab->g + (colour_tab->g_adj/colour_tab->count), (gint)colour_tab->b + (colour_tab->b_adj/colour_tab->count)); } static gboolean colour_print_remove(gpointer key,gpointer value,gpointer user_data) { g_free(value); return TRUE; } static gint sort_colours (gconstpointer a,gconstpointer b) { ImgColoursP s1 = (ImgColoursP) a; ImgColoursP s2 = (ImgColoursP) b; if(s1->count > s2->count) return -1; if(s1->count < s2->count) return 1; return 0; } static void import_image_make_palette(GHashTable *h_array,guchar *name, PaletteP palette) { GSList * sorted_list = NULL; PaletteEntriesP entries; g_hash_table_foreach(h_array,create_storted_list,&sorted_list); sorted_list = g_slist_sort(sorted_list,sort_colours); entries = palette_create_entries(palette,name); g_slist_foreach(sorted_list,create_image_palette,palette); /* Free up used memory */ /* Note the same structure is on both the hash list and the sorted * list. So only delete it once. */ g_hash_table_freeze(h_array); g_hash_table_foreach_remove(h_array,colour_print_remove,NULL); g_hash_table_thaw(h_array); g_hash_table_destroy(h_array); g_slist_free(sorted_list); /* Redraw with new palette */ palette_update_small_preview(palette); redraw_palette(palette); /* Update other selectors on screen */ palette_select_clist_insert_all(entries); palette_select2_clist_insert_all(entries); palette_scroll_clist_to_current(palette); } static GHashTable * store_colours(GHashTable *h_array, guchar * colours, guchar * colours_real, gint sample_sz) { gpointer found_colour = NULL; ImgColoursP new_colour; guint key_colours = colours[0]*256*256+colours[1]*256+colours[2]; if(h_array == NULL) { h_array = g_hash_table_new(g_direct_hash,g_direct_equal); count_colour_entries = 0; } else { found_colour = g_hash_table_lookup(h_array,(gpointer)key_colours); } if(found_colour == NULL) { if(count_colour_entries > MAX_IMAGE_COLOURS) { /* Don't add any more new ones */ return h_array; } count_colour_entries++; new_colour = g_new(ImgColours,1); new_colour->count = 1; new_colour->r_adj = 0; new_colour->g_adj = 0; new_colour->b_adj = 0; new_colour->r = colours[0]; new_colour->g = colours[1]; new_colour->b = colours[2]; g_hash_table_insert(h_array,(gpointer)key_colours,new_colour); } else { new_colour = (ImgColoursP)found_colour; if(new_colour->count < (G_MAXINT - 1)) new_colour->count++; /* Now do the adjustments ...*/ new_colour->r_adj += (colours_real[0] - colours[0]); new_colour->g_adj += (colours_real[1] - colours[1]); new_colour->b_adj += (colours_real[2] - colours[2]); /* Boundary conditions */ if(new_colour->r_adj > (G_MAXINT - 255)) new_colour->r_adj /= new_colour->count; if(new_colour->g_adj > (G_MAXINT - 255)) new_colour->g_adj /= new_colour->count; if(new_colour->b_adj > (G_MAXINT - 255)) new_colour->b_adj /= new_colour->count; } return h_array; } static void import_palette_create_from_image (GImage *gimage,guchar *pname,PaletteP palette) { PixelRegion imagePR; unsigned char *image_data; unsigned char *idata; guchar rgb[MAX_CHANNELS]; guchar rgb_real[MAX_CHANNELS]; int has_alpha, indexed; int width, height; int bytes, alpha; int i, j; void * pr; int d_type; GHashTable *store_array = NULL; gint sample_sz; gint threshold = 1; sample_sz = (gint)import_dialog->sample->value; if(gimage == NULL) return; /* Get the image information */ bytes = gimage_composite_bytes (gimage); d_type = gimage_composite_type (gimage); has_alpha = (d_type == RGBA_GIMAGE || d_type == GRAYA_GIMAGE || d_type == INDEXEDA_GIMAGE); indexed = d_type == INDEXEDA_GIMAGE || d_type == INDEXED_GIMAGE; width = gimage->width; height = gimage->height; pixel_region_init (&imagePR, gimage_composite (gimage), 0, 0, width, height, FALSE); alpha = bytes - 1; threshold = (gint)import_dialog->threshold->value; if(threshold < 1) threshold = 1; /* iterate over the entire image */ for (pr = pixel_regions_register (1, &imagePR); pr != NULL; pr = pixel_regions_process (pr)) { image_data = imagePR.data; for (i = 0; i < imagePR.h; i++) { idata = image_data; for (j = 0; j < imagePR.w; j++) { /* Get the rgb values for the color */ gimage_get_color (gimage, d_type, rgb, idata); memcpy(rgb_real,rgb,MAX_CHANNELS); /* Structure copy */ rgb[0] = (rgb[0]/threshold)*threshold; rgb[1] = (rgb[1]/threshold)*threshold; rgb[2] = (rgb[2]/threshold)*threshold; store_array = store_colours(store_array,rgb,rgb_real,sample_sz); idata += bytes; } image_data += imagePR.rowstride; } } /* Make palette from the store_array */ import_image_make_palette(store_array,pname,palette); }