/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikapalettemru.c * Copyright (C) 2014 Michael Natterer * * 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 3 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, see . */ #include "config.h" #include #include #include #include "libpikacolor/pikacolor.h" #include "libpikaconfig/pikaconfig.h" #include "core-types.h" #include "pikapalettemru.h" #include "pika-intl.h" #define MAX_N_COLORS 256 #define RGBA_EPSILON 1e-4 enum { COLOR_HISTORY = 1 }; G_DEFINE_TYPE (PikaPaletteMru, pika_palette_mru, PIKA_TYPE_PALETTE) #define parent_class pika_palette_mru_parent_class static void pika_palette_mru_class_init (PikaPaletteMruClass *klass) { } static void pika_palette_mru_init (PikaPaletteMru *palette) { } /* public functions */ PikaData * pika_palette_mru_new (const gchar *name) { PikaPaletteMru *palette; g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (*name != '\0', NULL); palette = g_object_new (PIKA_TYPE_PALETTE_MRU, "name", name, "mime-type", "application/x-pika-palette", NULL); return PIKA_DATA (palette); } void pika_palette_mru_load (PikaPaletteMru *mru, GFile *file) { PikaPalette *palette; GScanner *scanner; GTokenType token; g_return_if_fail (PIKA_IS_PALETTE_MRU (mru)); g_return_if_fail (G_IS_FILE (file)); palette = PIKA_PALETTE (mru); scanner = pika_scanner_new_file (file, NULL); if (! scanner) return; g_scanner_scope_add_symbol (scanner, 0, "color-history", GINT_TO_POINTER (COLOR_HISTORY)); token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: if (scanner->value.v_symbol == GINT_TO_POINTER (COLOR_HISTORY)) { while (g_scanner_peek_next_token (scanner) == G_TOKEN_LEFT_PAREN) { PikaRGB color; if (! pika_scanner_parse_color (scanner, &color)) goto end; pika_palette_add_entry (palette, -1, _("History Color"), &color); if (pika_palette_get_n_colors (palette) == MAX_N_COLORS) goto end; } } token = G_TOKEN_RIGHT_PAREN; break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: /* do nothing */ break; } } end: pika_scanner_unref (scanner); } void pika_palette_mru_save (PikaPaletteMru *mru, GFile *file) { PikaPalette *palette; PikaConfigWriter *writer; GList *list; g_return_if_fail (PIKA_IS_PALETTE_MRU (mru)); g_return_if_fail (G_IS_FILE (file)); writer = pika_config_writer_new_from_file (file, TRUE, "PIKA colorrc\n\n" "This file holds a list of " "recently used colors.", NULL); if (! writer) return; palette = PIKA_PALETTE (mru); pika_config_writer_open (writer, "color-history"); for (list = palette->colors; list; list = g_list_next (list)) { PikaPaletteEntry *entry = list->data; gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE]; g_ascii_dtostr (buf[0], G_ASCII_DTOSTR_BUF_SIZE, entry->color.r); g_ascii_dtostr (buf[1], G_ASCII_DTOSTR_BUF_SIZE, entry->color.g); g_ascii_dtostr (buf[2], G_ASCII_DTOSTR_BUF_SIZE, entry->color.b); g_ascii_dtostr (buf[3], G_ASCII_DTOSTR_BUF_SIZE, entry->color.a); pika_config_writer_open (writer, "color-rgba"); pika_config_writer_printf (writer, "%s %s %s %s", buf[0], buf[1], buf[2], buf[3]); pika_config_writer_close (writer); } pika_config_writer_close (writer); pika_config_writer_finish (writer, "end of colorrc", NULL); } void pika_palette_mru_add (PikaPaletteMru *mru, const PikaRGB *color) { PikaPalette *palette; GList *list; g_return_if_fail (PIKA_IS_PALETTE_MRU (mru)); g_return_if_fail (color != NULL); palette = PIKA_PALETTE (mru); /* is the added color already there? */ for (list = pika_palette_get_colors (palette); list; list = g_list_next (list)) { PikaPaletteEntry *entry = list->data; if (pika_rgba_distance (&entry->color, color) < RGBA_EPSILON) { pika_palette_move_entry (palette, entry, 0); /* Even though they are nearly the same color, let's make them * exactly equal. */ pika_palette_set_entry_color (palette, 0, color, FALSE); return; } } if (pika_palette_get_n_colors (palette) == MAX_N_COLORS) { pika_palette_delete_entry (palette, pika_palette_get_entry (palette, MAX_N_COLORS - 1)); } pika_palette_add_entry (palette, 0, _("History Color"), color); }