Index: widgets/gimppaletteeditor.c =================================================================== RCS file: /cvs/gnome/gimp/app/widgets/gimppaletteeditor.c,v retrieving revision 1.174 diff -u -r1.174 gimppaletteeditor.c --- widgets/gimppaletteeditor.c 8 Dec 2004 13:52:27 -0000 1.174 +++ widgets/gimppaletteeditor.c 21 Dec 2004 01:42:30 -0000 @@ -31,6 +31,7 @@ #include "libgimpbase/gimpbase.h" #include "libgimpwidgets/gimpwidgets.h" + #include "widgets-types.h" #include "core/gimp.h" @@ -38,6 +39,9 @@ #include "core/gimpcontext.h" #include "core/gimpdatafactory.h" #include "core/gimppalette.h" +#include "core/core-enums.h" + +#include "widgets/gimpenumcombobox.h" #include "gimpdnd.h" #include "gimpdocked.h" @@ -105,7 +109,8 @@ GimpPaletteEditor *editor); static void palette_editor_columns_changed (GtkAdjustment *adj, GimpPaletteEditor *editor); - +static void palette_editor_sort_type_changed (GtkWidget *widget, + GimpPaletteEditor *editor); static void palette_editor_drag_color (GtkWidget *widget, GimpRGB *color, gpointer data); @@ -122,11 +127,12 @@ GimpPaletteEditor *editor); static void palette_editor_viewport_realize (GtkWidget *widget, GimpPaletteEditor *editor); - +static void palette_editor_reset_sort (GimpPaletteEditor *editor); static GimpDataEditorClass *parent_class = NULL; static GimpDockedInterface *parent_docked_iface = NULL; +static GimpSortPaletteType default_sort_type = GIMP_SORT_ORIG; GType gimp_palette_editor_get_type (void) @@ -191,6 +197,7 @@ GtkWidget *eventbox; GtkWidget *alignment; GtkWidget *hbox; + GtkWidget *hbox2; GtkWidget *label; GtkWidget *spinbutton; @@ -248,7 +255,7 @@ palette_editor_drop_palette, editor); - hbox = gtk_hbox_new (FALSE, 2); + hbox = gtk_hbox_new (FALSE, 3); gtk_box_pack_start (GTK_BOX (editor), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); @@ -267,6 +274,23 @@ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); + hbox2 = gtk_hbox_new (FALSE, 2); + gtk_box_pack_start (GTK_BOX (editor), hbox2, FALSE, FALSE, 0); + gtk_widget_show (hbox2); + + editor->sort_combo = gimp_enum_combo_box_new (GIMP_TYPE_SORT_PALETTE_TYPE); + gtk_box_pack_start (GTK_BOX (hbox2), editor->sort_combo, TRUE, TRUE, 0); + gtk_widget_show (editor->sort_combo); + + gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (editor->sort_combo), + default_sort_type, + G_CALLBACK (gimp_int_combo_box_get_active), + &editor->sort_type); + + g_signal_connect (editor->sort_combo, "changed", + G_CALLBACK (palette_editor_sort_type_changed), + editor); + spinbutton = gimp_spin_button_new ((GtkObject **) &editor->columns_data, 0, 0, 64, 1, 4, 4, 1, 0); gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0); @@ -449,6 +473,8 @@ palette_editor_invalidate_preview (GIMP_PALETTE (editor->data), palette_editor); + + palette_editor_reset_sort (palette_editor); } g_signal_handlers_unblock_by_func (palette_editor->columns_data, @@ -568,6 +594,21 @@ /* the color area event callbacks ******************************************/ + +static void +palette_editor_reset_sort (GimpPaletteEditor *editor) +{ + GimpPalette *palette; + GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor); + + if (! editor) + return; + + palette = GIMP_PALETTE (data_editor->data); + gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (editor->sort_combo), + palette->sort_type); +} + static gboolean palette_editor_eventbox_button_press (GtkWidget *widget, GdkEventButton *bevent, @@ -973,6 +1014,8 @@ palette_editor_draw_entries (editor, editor->color->position / editor->columns, editor->color->position % editor->columns); + + } static void @@ -1010,6 +1053,20 @@ } } + +static void +palette_editor_sort_type_changed (GtkWidget *widget, + GimpPaletteEditor *editor) +{ + if (GIMP_DATA_EDITOR (editor)->data) + { + GimpPalette *palette; + + palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data); + gimp_palette_sort (palette, editor->sort_type); + + } +} /* the color name entry callback *******************************************/ Index: widgets/gimppaletteeditor.h =================================================================== RCS file: /cvs/gnome/gimp/app/widgets/gimppaletteeditor.h,v retrieving revision 1.34 diff -u -r1.34 gimppaletteeditor.h --- widgets/gimppaletteeditor.h 24 Oct 2004 20:38:35 -0000 1.34 +++ widgets/gimppaletteeditor.h 21 Dec 2004 01:42:30 -0000 @@ -51,6 +51,8 @@ GtkWidget *zoom_all_button; GtkWidget *color_dialog; + + GtkWidget *sort_combo; GimpPaletteEntry *color; GimpPaletteEntry *dnd_color; @@ -60,6 +62,8 @@ gint last_width; gint columns; gboolean columns_valid; + gint sort_type; + }; struct _GimpPaletteEditorClass Index: core/gimppalette.c =================================================================== RCS file: /cvs/gnome/gimp/app/core/gimppalette.c,v retrieving revision 1.50 diff -u -r1.50 gimppalette.c --- core/gimppalette.c 28 Sep 2004 14:59:55 -0000 1.50 +++ core/gimppalette.c 21 Dec 2004 01:42:30 -0000 @@ -30,12 +30,14 @@ #include "libgimpbase/gimpbase.h" #include "libgimpcolor/gimpcolor.h" +#include "libgimpcolor/gimpcolorspace.h" #include "core-types.h" #include "base/temp-buf.h" #include "gimppalette.h" +#include "cpercep.h" #include "gimp-intl.h" @@ -75,6 +77,31 @@ static void gimp_palette_entry_free (GimpPaletteEntry *entry); +static gint gimp_palette_sort_red_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_green_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_blue_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_hue_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_value_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_saturation_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_distance_cpercep_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_brightness_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_distance_hsl_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_distance_hsv_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_distance_rgb_compare (gconstpointer a, + gconstpointer b); +static gint gimp_palette_sort_lightness_compare (gconstpointer a, + gconstpointer b); + /* private variables */ @@ -137,9 +164,10 @@ static void gimp_palette_init (GimpPalette *palette) { - palette->colors = NULL; - palette->n_colors = 0; - palette->n_columns = 0; + palette->colors = NULL; + palette->orig_colors = NULL; + palette->n_colors = 0; + palette->n_columns = 0; } static void @@ -153,6 +181,12 @@ g_list_free (palette->colors); palette->colors = NULL; } + if (palette->orig_colors) + { + g_list_foreach (palette->orig_colors, (GFunc) gimp_palette_entry_free, NULL); + g_list_free (palette->orig_colors); + palette->colors = NULL; + } G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -175,6 +209,8 @@ memsize += strlen (entry->name) + 1; } + /* FIXME: sizeof orig_colors as well */ + return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } @@ -183,7 +219,7 @@ gimp_palette_get_preview_size (GimpViewable *viewable, gint size, gboolean popup, - gboolean dot_for_dot, + gboolean dot_for_dot, gint *width, gint *height) { @@ -193,7 +229,7 @@ static gboolean gimp_palette_get_popup_size (GimpViewable *viewable, - gint width, + gint width, gint height, gboolean dot_for_dot, gint *popup_width, @@ -547,6 +583,11 @@ fclose (file); palette->colors = g_list_reverse (palette->colors); + /* shallow copy since we just need to preserve the order, + so sharing the content is fine*/ + palette->orig_colors = g_list_copy(palette->colors); + palette->sort_type = GIMP_SORT_ORIG; + return g_list_prepend (NULL, palette); } @@ -676,6 +717,50 @@ } } + +void +gimp_palette_sort (GimpPalette *palette, gint sort_type) +{ + + g_return_if_fail (GIMP_IS_PALETTE (palette)); + + if (sort_type == GIMP_SORT_ORIG) + palette->colors = g_list_copy(palette->orig_colors); + if (sort_type == GIMP_SORT_RED) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_red_compare); + if (sort_type == GIMP_SORT_GREEN) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_green_compare); + if (sort_type == GIMP_SORT_BLUE) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_blue_compare); + if (sort_type == GIMP_SORT_HUE) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_hue_compare); + if (sort_type == GIMP_SORT_VALUE) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_value_compare); + if (sort_type == GIMP_SORT_SATURATION) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_saturation_compare); + if (sort_type == GIMP_SORT_LIGHTNESS) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_lightness_compare); + if (sort_type == GIMP_SORT_BRIGHTNESS) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_brightness_compare); + if (sort_type == GIMP_SORT_RGB) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_distance_rgb_compare); + if (sort_type == GIMP_SORT_HSV) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_distance_hsv_compare); + if (sort_type == GIMP_SORT_HSL) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_distance_hsl_compare); + if (sort_type == GIMP_SORT_CPERCEP) + palette->colors = g_list_sort(palette->colors, gimp_palette_sort_distance_cpercep_compare); + if (sort_type == GIMP_SORT_REVERSE) + palette->colors = g_list_reverse(palette->colors); + + palette->sort_type = sort_type; + /* will make the palette dirty too */ + gimp_object_name_changed (GIMP_OBJECT (palette)); + +} + + + void gimp_palette_set_n_columns (GimpPalette *palette, gint n_columns) @@ -711,3 +796,386 @@ g_free (entry->name); g_free (entry); } + +static gint +gimp_palette_sort_red_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + if (id_a->color.r > id_b->color.r ) + return 1; + else if (id_a->color.r < id_b->color.r ) + return -1; + return 0; + +} +static gint +gimp_palette_sort_green_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + if (id_a->color.g > id_b->color.g ) + return 1; + else if (id_a->color.g < id_b->color.g ) + return -1; + return 0; + +} + +static gint +gimp_palette_sort_blue_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + if (id_a->color.b > id_b->color.b ) + return 1; + else if (id_a->color.b < id_b->color.b ) + return -1; + return 0; + +} + +static gint +gimp_palette_sort_hue_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + GimpHSV a_hsv; + GimpHSV b_hsv; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + gimp_rgb_to_hsv(&id_a->color, &a_hsv); + gimp_rgb_to_hsv(&id_b->color, &b_hsv); + + if (a_hsv.h > b_hsv.h ) + return 1; + else if (a_hsv.h < b_hsv.h ) + return -1; + return 0; + +} + +static gint +gimp_palette_sort_value_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + GimpHSV a_hsv; + GimpHSV b_hsv; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + gimp_rgb_to_hsv(&id_a->color, &a_hsv); + gimp_rgb_to_hsv(&id_b->color, &b_hsv); + + if (a_hsv.v > b_hsv.v ) + return 1; + else if (a_hsv.v < b_hsv.v ) + return -1; + return 0; + +} + +static gint +gimp_palette_sort_saturation_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + GimpHSV a_hsv; + GimpHSV b_hsv; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + gimp_rgb_to_hsv(&id_a->color, &a_hsv); + gimp_rgb_to_hsv(&id_b->color, &b_hsv); + + if (a_hsv.s > b_hsv.s ) + return 1; + else if (a_hsv.s < b_hsv.s ) + return -1; + return 0; + +} + +static gint +gimp_palette_sort_lightness_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + GimpHSL a_hsl; + GimpHSL b_hsl; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + gimp_rgb_to_hsl(&id_a->color, &a_hsl); + gimp_rgb_to_hsl(&id_b->color, &b_hsl); + + if (a_hsl.l > b_hsl.l ) + return 1; + else if (a_hsl.l < b_hsl.l ) + return -1; + return 0; + +} + + +static gint +gimp_palette_sort_distance_rgb_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + + gdouble ad; + gdouble bd; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + ad = sqrt((id_a->color.r * id_a->color.r) + (id_a->color.g * id_a->color.g) + (id_a->color.b * id_a->color.b)); + bd = sqrt((id_b->color.r * id_b->color.r) + (id_b->color.g * id_b->color.g) + (id_b->color.b * id_b->color.b)); + + if (ad > bd ) + return 1; + else if (ad < bd ) + return -1; + return 0; + + +} + + +static gint +gimp_palette_sort_distance_hsv_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + gdouble ad; + gdouble bd; + + GimpHSV a_hsv; + GimpHSV b_hsv; + + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + gimp_rgb_to_hsv(&id_a->color, &a_hsv); + gimp_rgb_to_hsv(&id_b->color, &b_hsv); + + + ad = sqrt((a_hsv.h * a_hsv.h) + (a_hsv.s * a_hsv.s) + (a_hsv.v * a_hsv.v)); + bd = sqrt((b_hsv.h * b_hsv.h) + (b_hsv.s * b_hsv.s) + (b_hsv.v * b_hsv.v)); + + if (ad > bd ) + return 1; + else if (ad < bd ) + return -1; + return 0; + +} + +static gint +gimp_palette_sort_distance_hsl_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + gdouble ad; + gdouble bd; + + GimpHSL a_hsl; + GimpHSL b_hsl; + + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + gimp_rgb_to_hsl(&id_a->color, &a_hsl); + gimp_rgb_to_hsl(&id_b->color, &b_hsl); + + + ad = sqrt((a_hsl.h * a_hsl.h) + (a_hsl.s * a_hsl.s) + (a_hsl.l * a_hsl.l)); + bd = sqrt((b_hsl.h * b_hsl.h) + (b_hsl.s * b_hsl.s) + (b_hsl.l * b_hsl.l)); + + if (ad > bd ) + return 1; + else if (ad < bd ) + return -1; + return 0; + +} + + +static gint +gimp_palette_sort_brightness_compare (gconstpointer a, + gconstpointer b) +{ + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + gdouble a_bright; + gdouble b_bright; + + g_assert (a != NULL); + g_assert (b != NULL); + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + + /* from http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9 */ + a_bright = (0.2126 * id_a->color.r) + (0.7152 * id_a->color.g) + (0.722 * id_a->color.r); + b_bright = (0.2126 * id_b->color.r) + (0.7152 * id_b->color.g) + (0.722 * id_b->color.r); + + if (a_bright > b_bright ) + return 1; + else if (a_bright < b_bright ) + return -1; + return 0; + +} + + + + +/* a better approach might be to walk over each palette entry + and compare against all other entries, looking for it's + neareat neighbor, then do a tsort with the the partial + order of color b -> color a (where, say, a is close to 0,0,0) + or something other measure. The idea being to group stuff + thats closest together near each other. That might provide + more "smoothness" in the ordering. -akl +*/ +static gint +gimp_palette_sort_distance_cpercep_compare (gconstpointer a, + gconstpointer b) +{ + + GimpPaletteEntry *id_a; + GimpPaletteEntry *id_b; + + g_assert (a != NULL); + g_assert (b != NULL); + + double a_sL = 0.0; + double a_sa = 0.0; + double a_sB = 0.0; + + double a_ir; + double a_ig; + double a_ib; + + double b_ir; + double b_ig; + double b_ib; + + double b_sL = 0.0; + double b_sa = 0.0; + double b_sB = 0.0; + + double a_dist; + double b_dist; + + id_a = (GimpPaletteEntry *) a; + id_b = (GimpPaletteEntry *) b; + cpercep_init_conversions(); + + //printf("gh 1 id_a->color.r: %f %f\n", id_a->color.r, (double) id_a->color.r); + + a_ir = ((double)(id_a->color.r)) * 255.0F; + a_ig = ((double)(id_a->color.g)) * 255.0F; + a_ib = ((double)(id_a->color.b)) * 255.0F; + + b_ir = ((double)(id_b->color.r)) * 255.0F; + b_ig = ((double)(id_b->color.g)) * 255.0F; + b_ib = ((double)(id_b->color.b)) * 255.0F; + + cpercep_rgb_to_space(a_ir, + a_ig, + a_ib, + &a_sL, &a_sa, &a_sB); + + cpercep_rgb_to_space(b_ir, + b_ig, + b_ib, + &b_sL, &b_sa, &b_sB); + + //printf("a_sl %.5f a_sa %.5f a_sB %.5f\n", a_sL, a_sa, a_sB); + //printf("b_sl %.5f b_sa %.5f b_sB %.5f\n", b_sL, b_sa, b_sB); + a_dist = cpercep_distance_space(0.0, 0.0, 0.0, + a_sL, a_sa, a_sB); + + b_dist = cpercep_distance_space(0.0, 0.0, 0.0, + b_sL, b_sa, b_sB); + + //printf("a_dist %.5f b_dist %.5f\n", a_dist, b_dist); + if (a_dist > b_dist ) + return 1; + else if (a_dist < b_dist ) + return -1; + return 0; + +} + Index: core/gimppalette.h =================================================================== RCS file: /cvs/gnome/gimp/app/core/gimppalette.h,v retrieving revision 1.19 diff -u -r1.19 gimppalette.h --- core/gimppalette.h 26 Jul 2004 19:00:22 -0000 1.19 +++ core/gimppalette.h 21 Dec 2004 01:42:30 -0000 @@ -19,10 +19,8 @@ #ifndef __GIMP_PALETTE_H__ #define __GIMP_PALETTE_H__ - #include "gimpdata.h" - #define GIMP_PALETTE_FILE_EXTENSION ".gpl" @@ -51,6 +49,9 @@ GimpData parent_instance; GList *colors; + /* so we can restore the original sort order */ + GList *orig_colors; + gint sort_type; gint n_colors; gint n_columns; @@ -76,6 +77,11 @@ const GimpRGB *color); void gimp_palette_delete_entry (GimpPalette *palette, GimpPaletteEntry *entry); + +void gimp_palette_sort (GimpPalette *palette, + gint sort_type); + +void gimp_palette_sort_reverse (GimpPalette *palette); void gimp_palette_set_n_columns (GimpPalette *palette, gint n_columns); Index: core/cpercep.c =================================================================== RCS file: /cvs/gnome/gimp/app/core/cpercep.c,v retrieving revision 1.6 diff -u -r1.6 cpercep.c --- core/cpercep.c 16 Sep 2003 13:12:39 -0000 1.6 +++ core/cpercep.c 21 Dec 2004 01:42:30 -0000 @@ -81,8 +81,8 @@ the phosphor colours and the white point definition. */ -/* #define SANITY */ -#define APPROX +//#define SANITY +//#define APPROX #define SRGB @@ -508,6 +508,7 @@ rgb_to_xyz(&inr, &ing, &inb); + #ifdef SANITY if (inr < 0.0F || ing < 0.0F || inb < 0.0F) { @@ -517,7 +518,9 @@ #endif /* SANITY */ xyz_to_lab(&inr, &ing, &inb); + + *outr = inr; *outg = ing; *outb = inb; Index: core/cpercep.h =================================================================== RCS file: /cvs/gnome/gimp/app/core/cpercep.h,v retrieving revision 1.3 diff -u -r1.3 cpercep.h --- core/cpercep.h 24 May 2002 10:48:07 -0000 1.3 +++ core/cpercep.h 21 Dec 2004 01:42:30 -0000 @@ -44,7 +44,7 @@ cpercep_space_to_rgb (double inr, double ing, double inb, double* outr, double* outg, double* outb); -#if 0 +#if 1 /* This is in the header so that it can potentially be inlined. */ static const double cpercep_distance_space (const double L1, const double a1, const double b1,