gimp/app/widgets/gimppaletteeditor.c

1330 lines
40 KiB
C

/* 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 <string.h>
#ifdef __GNUC__
#warning GTK_DISABLE_DEPRECATED
#endif
#undef GTK_DISABLE_DEPRECATED
#include <gtk/gtk.h>
#include "libgimpcolor/gimpcolor.h"
#include "libgimpbase/gimpbase.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets-types.h"
#include "core/gimp.h"
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpdatafactory.h"
#include "core/gimppalette.h"
#include "gimpdialogfactory.h"
#include "gimpdnd.h"
#include "gimpdocked.h"
#include "gimphelp-ids.h"
#include "gimppaletteeditor.h"
#include "gimppreview.h"
#include "gimpsessioninfo.h"
#include "gimpuimanager.h"
#include "gimpwidgets-utils.h"
#include "gui/color-notebook.h"
#include "gimp-intl.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)
/* local function prototypes */
static void gimp_palette_editor_class_init (GimpPaletteEditorClass *klass);
static void gimp_palette_editor_init (GimpPaletteEditor *editor);
static void gimp_palette_editor_docked_iface_init (GimpDockedInterface *docked_iface);
static void gimp_palette_editor_set_aux_info (GimpDocked *docked,
GList *aux_info);
static GList *gimp_palette_editor_get_aux_info (GimpDocked *docked);
static void gimp_palette_editor_destroy (GtkObject *object);
static void gimp_palette_editor_unmap (GtkWidget *widget);
static void gimp_palette_editor_set_data (GimpDataEditor *editor,
GimpData *data);
static gint palette_editor_eventbox_button_press (GtkWidget *widget,
GdkEventButton *bevent,
GimpPaletteEditor *editor);
static gint palette_editor_color_area_button_press (GtkWidget *widget,
GdkEventButton *bevent,
GimpPaletteEditor *editor);
static void palette_editor_draw_entries (GimpPaletteEditor *editor,
gint row_start,
gint column_highlight);
static void palette_editor_redraw (GimpPaletteEditor *editor,
gint width,
gdouble zoom_factor);
static void palette_editor_scroll_top_left (GimpPaletteEditor *editor);
static void palette_editor_select_entry (GimpPaletteEditor *editor,
GimpPaletteEntry *entry);
static void palette_editor_color_name_changed (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_columns_changed (GtkAdjustment *adj,
GimpPaletteEditor *editor);
static void palette_editor_new_clicked (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_new_ext_clicked (GtkWidget *widget,
GdkModifierType state,
GimpPaletteEditor *editor);
static void palette_editor_edit_clicked (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_delete_clicked (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_zoom_out_clicked (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_zoom_in_clicked (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_zoom_all_clicked (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_redraw_zoom (GimpPaletteEditor *editor,
gdouble zoom_factor);
static void palette_editor_drag_color (GtkWidget *widget,
GimpRGB *color,
gpointer data);
static void palette_editor_drop_color (GtkWidget *widget,
const GimpRGB *color,
gpointer data);
static void palette_editor_drop_palette (GtkWidget *widget,
GimpViewable *viewable,
gpointer data);
static void palette_editor_invalidate_preview (GimpPalette *palette,
GimpPaletteEditor *editor);
static void palette_editor_viewport_resized (GtkWidget *widget,
GtkAllocation *allocation,
GimpPaletteEditor *editor);
static void palette_editor_viewport_realize (GtkWidget *widget,
GimpPaletteEditor *editor);
static void palette_editor_color_notebook_callback (ColorNotebook *color_notebook,
const GimpRGB *color,
ColorNotebookState state,
gpointer data);
static GimpDataEditorClass *parent_class = NULL;
static GimpDockedInterface *parent_docked_iface = NULL;
GType
gimp_palette_editor_get_type (void)
{
static GType type = 0;
if (! type)
{
static const GTypeInfo info =
{
sizeof (GimpPaletteEditorClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) gimp_palette_editor_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpPaletteEditor),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_palette_editor_init,
};
static const GInterfaceInfo docked_iface_info =
{
(GInterfaceInitFunc) gimp_palette_editor_docked_iface_init,
NULL, /* iface_finalize */
NULL /* iface_data */
};
type = g_type_register_static (GIMP_TYPE_DATA_EDITOR,
"GimpPaletteEditor",
&info, 0);
g_type_add_interface_static (type, GIMP_TYPE_DOCKED,
&docked_iface_info);
}
return type;
}
static void
gimp_palette_editor_class_init (GimpPaletteEditorClass *klass)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GimpDataEditorClass *editor_class;
object_class = GTK_OBJECT_CLASS (klass);
widget_class = GTK_WIDGET_CLASS (klass);
editor_class = GIMP_DATA_EDITOR_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->destroy = gimp_palette_editor_destroy;
widget_class->unmap = gimp_palette_editor_unmap;
editor_class->set_data = gimp_palette_editor_set_data;
}
static void
gimp_palette_editor_init (GimpPaletteEditor *editor)
{
GtkWidget *scrolledwindow;
GtkWidget *eventbox;
GtkWidget *alignment;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *spinbutton;
gchar *str;
editor->zoom_factor = 1.0;
editor->col_width = 0;
editor->last_width = 0;
editor->columns = COLUMNS;
editor->columns_valid = TRUE;
editor->scrolled_window = scrolledwindow =
gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_size_request (scrolledwindow, -1, PREVIEW_HEIGHT);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (editor), scrolledwindow, TRUE, TRUE, 0);
gtk_widget_show (scrolledwindow);
eventbox = gtk_event_box_new ();
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolledwindow),
eventbox);
gtk_widget_show (eventbox);
g_signal_connect (eventbox, "button_press_event",
G_CALLBACK (palette_editor_eventbox_button_press),
editor);
g_signal_connect (eventbox->parent, "size_allocate",
G_CALLBACK (palette_editor_viewport_resized),
editor);
g_signal_connect (eventbox->parent, "realize",
G_CALLBACK (palette_editor_viewport_realize),
editor);
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (eventbox), alignment);
gtk_widget_show (alignment);
editor->color_area = gtk_preview_new (GTK_PREVIEW_COLOR);
gtk_preview_set_dither (GTK_PREVIEW (editor->color_area), GDK_RGB_DITHER_MAX);
gtk_preview_size (GTK_PREVIEW (editor->color_area),
PREVIEW_WIDTH, PREVIEW_HEIGHT);
gtk_widget_set_events (editor->color_area, PALETTE_EVENT_MASK);
gtk_container_add (GTK_CONTAINER (alignment), editor->color_area);
gtk_widget_show (editor->color_area);
g_signal_connect (editor->color_area, "button_press_event",
G_CALLBACK (palette_editor_color_area_button_press),
editor);
gimp_dnd_color_source_add (editor->color_area,
palette_editor_drag_color,
editor);
gimp_dnd_color_dest_add (eventbox, palette_editor_drop_color, editor);
gimp_dnd_viewable_dest_add (eventbox, GIMP_TYPE_PALETTE,
palette_editor_drop_palette,
editor);
hbox = gtk_hbox_new (FALSE, 2);
gtk_box_pack_start (GTK_BOX (editor), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* The color name entry */
editor->color_name = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), editor->color_name, TRUE, TRUE, 0);
gtk_entry_set_text (GTK_ENTRY (editor->color_name), _("Undefined"));
gtk_widget_set_sensitive (editor->color_name, FALSE);
gtk_widget_show (editor->color_name);
g_signal_connect (editor->color_name, "changed",
G_CALLBACK (palette_editor_color_name_changed),
editor);
label = gtk_label_new (_("Columns:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
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);
gtk_widget_show (spinbutton);
g_signal_connect (editor->columns_data, "value_changed",
G_CALLBACK (palette_editor_columns_changed),
editor);
editor->edit_button =
gimp_editor_add_button (GIMP_EDITOR (editor),
GIMP_STOCK_EDIT, _("Edit Color"),
GIMP_HELP_PALETTE_EDITOR_EDIT,
G_CALLBACK (palette_editor_edit_clicked),
NULL,
editor);
str = g_strdup_printf (_("New Color from FG\n%s from BG"),
gimp_get_mod_name_control ());
editor->new_button =
gimp_editor_add_button (GIMP_EDITOR (editor),
GTK_STOCK_NEW, str,
GIMP_HELP_PALETTE_EDITOR_NEW,
G_CALLBACK (palette_editor_new_clicked),
G_CALLBACK (palette_editor_new_ext_clicked),
editor);
g_free (str);
editor->delete_button =
gimp_editor_add_button (GIMP_EDITOR (editor),
GTK_STOCK_DELETE, _("Delete Color"),
GIMP_HELP_PALETTE_EDITOR_DELETE,
G_CALLBACK (palette_editor_delete_clicked),
NULL,
editor);
editor->zoom_out_button =
gimp_editor_add_button (GIMP_EDITOR (editor),
GTK_STOCK_ZOOM_OUT, _("Zoom Out"),
GIMP_HELP_PALETTE_EDITOR_ZOOM_OUT,
G_CALLBACK (palette_editor_zoom_out_clicked),
NULL,
editor);
editor->zoom_in_button =
gimp_editor_add_button (GIMP_EDITOR (editor),
GTK_STOCK_ZOOM_IN, _("Zoom In"),
GIMP_HELP_PALETTE_EDITOR_ZOOM_IN,
G_CALLBACK (palette_editor_zoom_in_clicked),
NULL,
editor);
editor->zoom_all_button =
gimp_editor_add_button (GIMP_EDITOR (editor),
GTK_STOCK_ZOOM_FIT, _("Zoom All"),
GIMP_HELP_PALETTE_EDITOR_ZOOM_ALL,
G_CALLBACK (palette_editor_zoom_all_clicked),
NULL,
editor);
}
static void
gimp_palette_editor_docked_iface_init (GimpDockedInterface *docked_iface)
{
parent_docked_iface = g_type_interface_peek_parent (docked_iface);
docked_iface->set_aux_info = gimp_palette_editor_set_aux_info;
docked_iface->get_aux_info = gimp_palette_editor_get_aux_info;
}
#define AUX_INFO_ZOOM_FACTOR "zoom-factor"
static void
gimp_palette_editor_set_aux_info (GimpDocked *docked,
GList *aux_info)
{
GimpPaletteEditor *editor = GIMP_PALETTE_EDITOR (docked);
GList *list;
if (parent_docked_iface->set_aux_info)
parent_docked_iface->set_aux_info (docked, aux_info);
for (list = aux_info; list; list = g_list_next (list))
{
GimpSessionInfoAux *aux = list->data;
if (! strcmp (aux->name, AUX_INFO_ZOOM_FACTOR))
{
gdouble zoom_factor;
zoom_factor = g_ascii_strtod (aux->value, NULL);
editor->zoom_factor = CLAMP (zoom_factor, 0.1, 4.0);
}
}
}
static GList *
gimp_palette_editor_get_aux_info (GimpDocked *docked)
{
GimpPaletteEditor *editor = GIMP_PALETTE_EDITOR (docked);
GList *aux_info = NULL;
if (parent_docked_iface->get_aux_info)
aux_info = parent_docked_iface->get_aux_info (docked);
if (editor->zoom_factor != 1.0)
{
GimpSessionInfoAux *aux;
gchar value[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_formatd (value, sizeof (value), "%.2f", editor->zoom_factor);
aux = gimp_session_info_aux_new (AUX_INFO_ZOOM_FACTOR, value);
aux_info = g_list_append (aux_info, aux);
}
return aux_info;
}
static void
gimp_palette_editor_destroy (GtkObject *object)
{
GimpPaletteEditor *editor;
editor = GIMP_PALETTE_EDITOR (object);
if (editor->color_notebook)
{
color_notebook_free (editor->color_notebook);
editor->color_notebook = NULL;
}
GTK_OBJECT_CLASS (parent_class)->destroy (object);
}
static void
gimp_palette_editor_unmap (GtkWidget *widget)
{
GimpPaletteEditor *editor;
editor = GIMP_PALETTE_EDITOR (widget);
if (editor->color_notebook)
color_notebook_hide (editor->color_notebook);
GTK_WIDGET_CLASS (parent_class)->unmap (widget);
}
static void
gimp_palette_editor_set_data (GimpDataEditor *editor,
GimpData *data)
{
GimpPaletteEditor *palette_editor;
palette_editor = GIMP_PALETTE_EDITOR (editor);
g_signal_handlers_block_by_func (palette_editor->columns_data,
palette_editor_columns_changed,
editor);
if (editor->data)
{
if (palette_editor->color_notebook)
{
color_notebook_free (palette_editor->color_notebook);
palette_editor->color_notebook = NULL;
}
g_signal_handlers_disconnect_by_func (editor->data,
palette_editor_invalidate_preview,
editor);
palette_editor->columns_valid = FALSE;
palette_editor_select_entry (palette_editor, NULL);
gtk_adjustment_set_value (palette_editor->columns_data, 0);
}
GIMP_DATA_EDITOR_CLASS (parent_class)->set_data (editor, data);
if (editor->data)
{
GimpPalette *palette;
palette = GIMP_PALETTE (editor->data);
g_signal_connect (editor->data, "invalidate_preview",
G_CALLBACK (palette_editor_invalidate_preview),
editor);
gtk_adjustment_set_value (palette_editor->columns_data,
palette->n_columns);
palette_editor_scroll_top_left (palette_editor);
palette_editor_invalidate_preview (GIMP_PALETTE (editor->data),
palette_editor);
}
g_signal_handlers_unblock_by_func (palette_editor->columns_data,
palette_editor_columns_changed,
editor);
gtk_widget_set_sensitive (palette_editor->edit_button, FALSE);
gtk_widget_set_sensitive (palette_editor->new_button,
editor->data_editable);
gtk_widget_set_sensitive (palette_editor->delete_button, FALSE);
gtk_widget_set_sensitive (palette_editor->zoom_out_button,
editor->data != NULL);
gtk_widget_set_sensitive (palette_editor->zoom_in_button,
editor->data != NULL);
gtk_widget_set_sensitive (palette_editor->zoom_all_button,
editor->data != NULL);
}
/* public functions */
GimpDataEditor *
gimp_palette_editor_new (Gimp *gimp,
GimpMenuFactory *menu_factory)
{
GimpPaletteEditor *palette_editor;
palette_editor = g_object_new (GIMP_TYPE_PALETTE_EDITOR, NULL);
if (! gimp_data_editor_construct (GIMP_DATA_EDITOR (palette_editor),
gimp->palette_factory,
menu_factory, "<PaletteEditor>",
"/palette-editor-popup"))
{
g_object_unref (palette_editor);
return NULL;
}
return GIMP_DATA_EDITOR (palette_editor);
}
void
gimp_palette_editor_update_color (GimpContext *context,
const GimpRGB *color,
GimpUpdateColorState state)
{
#ifdef __GNUC__
#warning FIXME: palette_set_active_color()
#endif
#if 0
if (top_level_edit_palette)
{
GimpPalette *palette;
palette = gimp_context_get_palette (top_level_edit_palette->context);
if (palette)
{
switch (state)
{
case GIMP_UPDATE_COLOR_STATE_NEW:
top_level_edit_palette->color = gimp_palette_add_entry (palette,
NULL,
color);
break;
case GIMP_UPDATE_COLOR_STATE_UPDATE_NEW:
top_level_edit_palette->color->color = *color;
gimp_data_dirty (GIMP_DATA (palette));
break;
default:
break;
}
}
}
#endif
}
/* private functions */
/* the color area event callbacks ******************************************/
static gboolean
palette_editor_eventbox_button_press (GtkWidget *widget,
GdkEventButton *bevent,
GimpPaletteEditor *editor)
{
if (bevent->button == 3)
{
GimpEditor *gimp_editor = GIMP_EDITOR (editor);
gimp_ui_manager_update (gimp_editor->ui_manager,
gimp_editor->popup_data);
gimp_ui_manager_ui_popup (gimp_editor->ui_manager,
gimp_editor->ui_path,
gimp_editor->popup_data,
GTK_WIDGET (editor),
NULL, NULL, NULL);
}
return TRUE;
}
static gboolean
palette_editor_color_area_button_press (GtkWidget *widget,
GdkEventButton *bevent,
GimpPaletteEditor *editor)
{
GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor);
GimpPalette *palette;
GimpContext *user_context;
GList *list;
gint entry_width;
gint entry_height;
gint row, col;
gint pos;
palette = GIMP_PALETTE (data_editor->data);
user_context = gimp_get_user_context (data_editor->data_factory->gimp);
entry_width = editor->col_width + SPACING;
entry_height = (ENTRY_HEIGHT * editor->zoom_factor) + SPACING;
col = (bevent->x - 1) / entry_width;
row = (bevent->y - 1) / entry_height;
pos = row * editor->columns + col;
if (palette)
list = g_list_nth (palette->colors, pos);
else
list = NULL;
if (list)
editor->dnd_color = list->data;
else
editor->dnd_color = NULL;
if ((bevent->button == 1 || bevent->button == 3) && palette)
{
palette_editor_select_entry (editor, list ? list->data : NULL);
if (list)
{
if (bevent->state & GDK_CONTROL_MASK)
gimp_context_set_background (user_context,
&editor->color->color);
else
gimp_context_set_foreground (user_context,
&editor->color->color);
palette_editor_draw_entries (editor, row, col);
if (data_editor->data_editable &&
bevent->button == 1 &&
((GdkEventAny *) bevent)->type == GDK_2BUTTON_PRESS)
{
gtk_button_clicked (GTK_BUTTON (editor->edit_button));
}
}
}
return FALSE; /* continue with eventbox_button_press */
}
/* functions for drawing & updating the palette dialog color area **********/
static gint
palette_editor_draw_color_row (guchar *colors,
gint n_colors,
gint y,
gint column_highlight,
guchar *buffer,
GimpPaletteEditor *palette_editor)
{
guchar *p;
guchar bcolor;
gint width, height;
gint entry_width;
gint entry_height;
gint vsize;
gint vspacing;
gint i, j;
GtkWidget *preview;
preview = palette_editor->color_area;
bcolor = 0;
width = preview->requisition.width;
height = preview->requisition.height;
entry_width = palette_editor->col_width;
entry_height = (ENTRY_HEIGHT * palette_editor->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;
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 < n_colors; i++)
{
for (j = 0; j < SPACING; j++)
{
*p++ = bcolor;
*p++ = bcolor;
*p++ = bcolor;
}
for (j = 0; j < entry_width; j++)
{
*p++ = colors[i * 3];
*p++ = colors[i * 3 + 1];
*p++ = colors[i * 3 + 2];
}
}
for (i = 0; i < (palette_editor->columns - n_colors); i++)
{
for (j = 0; j < (SPACING + entry_width); j++)
{
*p++ = 0;
*p++ = 0;
*p++ = 0;
}
}
for (j = 0; j < SPACING; j++)
{
if (n_colors == 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;
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_editor_draw_entries (GimpPaletteEditor *editor,
gint row_start,
gint column_highlight)
{
GimpPalette *palette;
GimpPaletteEntry *entry;
guchar *buffer;
guchar *colors;
GList *list;
gint width, height;
gint entry_width;
gint entry_height;
gint index, y;
palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
if (! palette)
return;
width = editor->color_area->requisition.width;
height = editor->color_area->requisition.height;
entry_width = editor->col_width;
entry_height = (ENTRY_HEIGHT * editor->zoom_factor);
if (entry_width <= 0)
return;
colors = g_new (guchar, editor->columns * 3);
buffer = g_new (guchar, width * 3);
if (row_start < 0)
{
y = 0;
list = palette->colors;
column_highlight = -1;
}
else
{
y = (entry_height + SPACING) * row_start;
list = g_list_nth (palette->colors,
row_start * editor->columns);
}
index = 0;
for (; list; list = g_list_next (list))
{
entry = (GimpPaletteEntry *) list->data;
gimp_rgb_get_uchar (&entry->color,
&colors[index * 3],
&colors[index * 3 + 1],
&colors[index * 3 + 2]);
index++;
if (index == editor->columns)
{
index = 0;
y = palette_editor_draw_color_row (colors,
editor->columns, y,
column_highlight, buffer,
editor);
if (y >= height || row_start >= 0)
{
/* This row only */
gtk_widget_queue_draw (editor->color_area);
g_free (buffer);
g_free (colors);
return;
}
}
}
while (y < height)
{
y = palette_editor_draw_color_row (colors, index, y, column_highlight,
buffer, editor);
index = 0;
if (row_start >= 0)
break;
}
g_free (buffer);
g_free (colors);
gtk_widget_queue_draw (editor->color_area);
}
static void
palette_editor_scroll_top_left (GimpPaletteEditor *palette_editor)
{
GtkAdjustment *hadj;
GtkAdjustment *vadj;
if (! palette_editor->scrolled_window)
return;
hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (palette_editor->scrolled_window));
vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (palette_editor->scrolled_window));
if (hadj)
gtk_adjustment_set_value (hadj, 0.0);
if (vadj)
gtk_adjustment_set_value (vadj, 0.0);
}
static void
palette_editor_redraw (GimpPaletteEditor *editor,
gint width,
gdouble zoom_factor)
{
GimpPalette *palette;
gint vsize;
gint nrows;
gint n_entries;
gint preview_width;
palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
if (! palette)
return;
if (editor->columns_valid)
return;
editor->zoom_factor = zoom_factor;
editor->last_width = width;
editor->col_width = width / (editor->columns + 1) - SPACING;
if (editor->col_width < 0)
editor->col_width = 0;
editor->columns_valid = TRUE;
n_entries = palette->n_colors;
nrows = n_entries / editor->columns;
if (n_entries % editor->columns)
nrows += 1;
vsize = nrows * (SPACING + (gint) (ENTRY_HEIGHT * editor->zoom_factor)) + SPACING;
preview_width = (editor->col_width + SPACING) * editor->columns + SPACING;
gtk_preview_size (GTK_PREVIEW (editor->color_area), preview_width, vsize);
gtk_widget_queue_resize (editor->color_area);
palette_editor_draw_entries (editor, -1, -1);
if (editor->color)
palette_editor_draw_entries (editor,
editor->color->position / editor->columns,
editor->color->position % editor->columns);
}
static void
palette_editor_select_entry (GimpPaletteEditor *editor,
GimpPaletteEntry *entry)
{
GimpDataEditor *data_editor;
GimpPalette *palette;
data_editor = GIMP_DATA_EDITOR (editor);
palette = GIMP_PALETTE (data_editor->data);
if (editor->color != entry)
{
if (editor->color)
palette_editor_draw_entries (editor, -1, -1);
editor->color = entry;
g_signal_handlers_block_by_func (editor->color_name,
palette_editor_color_name_changed,
editor);
gtk_entry_set_text (GTK_ENTRY (editor->color_name),
entry ? entry->name : _("Undefined"));
g_signal_handlers_unblock_by_func (editor->color_name,
palette_editor_color_name_changed,
editor);
gtk_widget_set_sensitive (editor->color_name,
entry && data_editor->data_editable);
gtk_widget_set_sensitive (editor->edit_button,
entry && data_editor->data_editable);
gtk_widget_set_sensitive (editor->delete_button,
entry && data_editor->data_editable);
}
}
/* the color name entry callback *******************************************/
static void
palette_editor_color_name_changed (GtkWidget *widget,
GimpPaletteEditor *editor)
{
if (GIMP_DATA_EDITOR (editor)->data)
{
GimpPalette *palette;
palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
if (editor->color->name)
g_free (editor->color->name);
editor->color->name =
g_strdup (gtk_entry_get_text (GTK_ENTRY (editor->color_name)));
gimp_data_dirty (GIMP_DATA (palette));
}
}
/* the columns spinbutton callback *****************************************/
static void
palette_editor_columns_changed (GtkAdjustment *adj,
GimpPaletteEditor *editor)
{
if (GIMP_DATA_EDITOR (editor)->data)
{
GimpPalette *palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
gimp_palette_set_n_columns (palette, ROUND (adj->value));
}
}
/* palette zoom functions & callbacks **************************************/
static void
palette_editor_edit_clicked (GtkWidget *widget,
GimpPaletteEditor *editor)
{
GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor);
GimpPalette *palette;
if (! (data_editor->data && data_editor->data_editable && editor->color))
return;
palette = GIMP_PALETTE (data_editor->data);
if (! editor->color_notebook)
{
GimpDialogFactory *toplevel_factory;
toplevel_factory = gimp_dialog_factory_from_name ("toplevel");
editor->color_notebook =
color_notebook_new (GIMP_VIEWABLE (palette),
_("Edit Palette Color"),
GIMP_STOCK_PALETTE,
_("Edit Color Palette Entry"),
GTK_WIDGET (editor),
toplevel_factory,
"gimp-palette-editor-color-dialog",
(const GimpRGB *) &editor->color->color,
palette_editor_color_notebook_callback,
editor,
FALSE, FALSE);
}
else
{
color_notebook_set_viewable (editor->color_notebook,
GIMP_VIEWABLE (palette));
color_notebook_set_color (editor->color_notebook,
&editor->color->color);
color_notebook_show (editor->color_notebook);
}
}
static void
palette_editor_new_clicked (GtkWidget *widget,
GimpPaletteEditor *editor)
{
palette_editor_new_ext_clicked (widget, 0, editor);
}
static void
palette_editor_new_ext_clicked (GtkWidget *widget,
GdkModifierType state,
GimpPaletteEditor *editor)
{
GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor);
if (data_editor->data && data_editor->data_editable)
{
GimpPalette *palette = GIMP_PALETTE (data_editor->data);
GimpContext *user_context;
GimpRGB color;
user_context = gimp_get_user_context (data_editor->data_factory->gimp);
if (state & GDK_CONTROL_MASK)
gimp_context_get_background (user_context, &color);
else
gimp_context_get_foreground (user_context, &color);
editor->color = gimp_palette_add_entry (palette, NULL, &color);
}
}
static void
palette_editor_delete_clicked (GtkWidget *widget,
GimpPaletteEditor *editor)
{
GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor);
if (data_editor->data && data_editor->data_editable && editor->color)
{
GimpPalette *palette = GIMP_PALETTE (data_editor->data);
gimp_palette_delete_entry (palette, editor->color);
}
}
static void
palette_editor_zoom_out_clicked (GtkWidget *widget,
GimpPaletteEditor *editor)
{
palette_editor_redraw_zoom (editor, editor->zoom_factor - 0.1);
}
static void
palette_editor_zoom_in_clicked (GtkWidget *widget,
GimpPaletteEditor *editor)
{
palette_editor_redraw_zoom (editor, editor->zoom_factor + 0.1);
}
static void
palette_editor_zoom_all_clicked (GtkWidget *widget,
GimpPaletteEditor *editor)
{
if (GIMP_DATA_EDITOR (editor)->data)
{
GimpPalette *palette;
gint window_height;
gint rows;
gdouble zoom_factor;
palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
window_height =
editor->color_area->parent->parent->parent->allocation.height;
if (palette->n_columns)
rows = palette->n_colors / palette->n_columns;
else
rows = palette->n_colors / COLUMNS;
rows = MAX (1, rows);
zoom_factor =
(((gdouble) window_height - 2 * SPACING) / (gdouble) rows - SPACING) /
ENTRY_HEIGHT;
palette_editor_redraw_zoom (editor, zoom_factor);
}
}
static void
palette_editor_redraw_zoom (GimpPaletteEditor *editor,
gdouble zoom_factor)
{
zoom_factor = CLAMP (zoom_factor, 0.1, 4.0);
if (GIMP_DATA_EDITOR (editor)->data && editor->zoom_factor != zoom_factor)
{
GimpPalette *palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
if (palette->n_columns)
editor->columns = palette->n_columns;
else
editor->columns = COLUMNS;
editor->columns_valid = FALSE;
palette_editor_redraw (editor, editor->last_width, zoom_factor);
palette_editor_scroll_top_left (editor);
}
}
/* the palette dialog color dnd callbacks **********************************/
static void
palette_editor_drag_color (GtkWidget *widget,
GimpRGB *color,
gpointer data)
{
GimpPaletteEditor *editor = GIMP_PALETTE_EDITOR (data);
if (GIMP_DATA_EDITOR (editor)->data && editor->dnd_color)
{
*color = editor->dnd_color->color;
}
else
{
gimp_rgba_set (color, 0.0, 0.0, 0.0, 1.0);
}
}
static void
palette_editor_drop_color (GtkWidget *widget,
const GimpRGB *color,
gpointer data)
{
GimpPaletteEditor *editor = GIMP_PALETTE_EDITOR (data);
if (GIMP_DATA_EDITOR (editor)->data_editable)
{
editor->color =
gimp_palette_add_entry (GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data),
NULL,
(GimpRGB *) color);
}
}
static void
palette_editor_drop_palette (GtkWidget *widget,
GimpViewable *viewable,
gpointer data)
{
gimp_data_editor_set_data (GIMP_DATA_EDITOR (data), GIMP_DATA (viewable));
}
static void
palette_editor_invalidate_preview (GimpPalette *palette,
GimpPaletteEditor *editor)
{
if (editor->color && ! g_list_find (palette->colors, editor->color))
palette_editor_select_entry (editor, NULL);
if (editor->dnd_color && ! g_list_find (palette->colors, editor->dnd_color))
editor->dnd_color = NULL;
if (palette->n_columns)
editor->columns = palette->n_columns;
else
editor->columns = COLUMNS;
editor->columns_valid = FALSE;
palette_editor_redraw (editor, editor->last_width, editor->zoom_factor);
}
static void
palette_editor_viewport_resized (GtkWidget *widget,
GtkAllocation *allocation,
GimpPaletteEditor *editor)
{
if (widget->allocation.width != editor->last_width)
{
editor->columns_valid = FALSE;
palette_editor_redraw (editor, widget->allocation.width,
editor->zoom_factor);
}
}
static void
palette_editor_viewport_realize (GtkWidget *widget,
GimpPaletteEditor *editor)
{
editor->columns_valid = FALSE;
palette_editor_redraw (editor, widget->allocation.width, editor->zoom_factor);
}
static void
palette_editor_color_notebook_callback (ColorNotebook *color_notebook,
const GimpRGB *color,
ColorNotebookState state,
gpointer data)
{
GimpPaletteEditor *editor;
GimpPalette *palette;
GimpContext *user_context;
editor = GIMP_PALETTE_EDITOR (data);
palette = GIMP_PALETTE (GIMP_DATA_EDITOR (editor)->data);
user_context = gimp_get_user_context (GIMP_DATA_EDITOR (editor)->data_factory->gimp);
switch (state)
{
case COLOR_NOTEBOOK_UPDATE:
break;
case COLOR_NOTEBOOK_OK:
if (editor->color)
{
editor->color->color = *color;
gimp_data_dirty (GIMP_DATA (palette));
}
/* Fallthrough */
case COLOR_NOTEBOOK_CANCEL:
color_notebook_hide (editor->color_notebook);
}
}