mirror of https://github.com/Gnucash/gnucash
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
6.2 KiB
297 lines
6.2 KiB
/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
/*
|
|
* color.c: Color allocation on the Gnumeric spreadsheet
|
|
*
|
|
* Author:
|
|
* Miguel de Icaza (miguel@kernel.org)
|
|
*
|
|
*/
|
|
#include <config.h>
|
|
#include "gnumeric.h"
|
|
#include "style-color.h"
|
|
#include "style-border.h"
|
|
#include <gtk/gtk.h>
|
|
#include <stdio.h>
|
|
|
|
/* Public _unallocated_ colours, i.e., no valid .pixel. */
|
|
GdkColor gs_black = { 0, 0x0000, 0x0000, 0x0000 }; /* "Black" */
|
|
GdkColor gs_white = { 0, 0xffff, 0xffff, 0xffff }; /* "White" */
|
|
GdkColor gs_yellow = { 0, 0xffff, 0xffff, 0xe0e0 }; /* "LightYellow" */
|
|
GdkColor gs_lavender = { 0, 0xe6e6, 0xe6e6, 0xfafa }; /* "lavender" */
|
|
GdkColor gs_dark_gray = { 0, 0x3333, 0x3333, 0x3333 }; /* "gray20" */
|
|
GdkColor gs_light_gray = { 0, 0xc7c7, 0xc7c7, 0xc7c7 }; /* "gray78" */
|
|
|
|
static GHashTable *style_color_hash;
|
|
static GnmColor *sc_black;
|
|
static GnmColor *sc_white;
|
|
static GnmColor *sc_grid;
|
|
|
|
GnmColor *
|
|
style_color_new_name (char const *name)
|
|
{
|
|
GdkColor c;
|
|
|
|
gdk_color_parse (name, &c);
|
|
return style_color_new (c.red, c.green, c.blue);
|
|
}
|
|
|
|
static GnmColor *
|
|
style_color_new_uninterned (gushort red, gushort green, gushort blue,
|
|
gboolean is_auto)
|
|
{
|
|
GnmColor *sc = g_new (GnmColor, 1);
|
|
|
|
sc->color.red = red;
|
|
sc->color.green = green;
|
|
sc->color.blue = blue;
|
|
sc->color.pixel = gs_white.pixel;
|
|
sc->name = NULL;
|
|
sc->is_auto = is_auto;
|
|
|
|
/* Make a contrasting selection color with an alpha of .5 */
|
|
red += (gs_lavender.red - red)/2;
|
|
green += (gs_lavender.green - green)/2;
|
|
blue += (gs_lavender.blue - blue)/2;
|
|
sc->selected_color.red = red;
|
|
sc->selected_color.green = green;
|
|
sc->selected_color.blue = blue;
|
|
sc->selected_color.pixel = gs_white.pixel;
|
|
|
|
sc->ref_count = 1;
|
|
|
|
return sc;
|
|
}
|
|
|
|
GnmColor *
|
|
style_color_new (gushort red, gushort green, gushort blue)
|
|
{
|
|
GnmColor *sc;
|
|
GnmColor key;
|
|
|
|
key.color.red = red;
|
|
key.color.green = green;
|
|
key.color.blue = blue;
|
|
key.is_auto = FALSE;
|
|
|
|
sc = g_hash_table_lookup (style_color_hash, &key);
|
|
if (!sc) {
|
|
sc = style_color_new_uninterned (red, green, blue, FALSE);
|
|
g_hash_table_insert (style_color_hash, sc, sc);
|
|
} else
|
|
sc->ref_count++;
|
|
|
|
return sc;
|
|
}
|
|
|
|
GnmColor *
|
|
style_color_new_pango (PangoColor *c)
|
|
{
|
|
return style_color_new (c->red, c->green, c->blue);
|
|
}
|
|
|
|
/* scale 8 bit/color -> 16 bit/color by cloning */
|
|
GnmColor *
|
|
style_color_new_i8 (guint8 red, guint8 green, guint8 blue)
|
|
{
|
|
gushort red16, green16, blue16;
|
|
|
|
red16 = ((gushort) red) << 8 | red;
|
|
green16 = ((gushort) green) << 8 | green;
|
|
blue16 = ((gushort) blue) << 8 | blue;
|
|
|
|
return style_color_new (red16, green16, blue16);
|
|
}
|
|
GnmColor *
|
|
style_color_new_go (GOColor c)
|
|
{
|
|
return style_color_new_i8 (
|
|
UINT_RGBA_R (c), UINT_RGBA_G (c), UINT_RGBA_B (c));
|
|
}
|
|
|
|
GnmColor *
|
|
style_color_black (void)
|
|
{
|
|
if (!sc_black)
|
|
sc_black = style_color_new (0, 0, 0);
|
|
return style_color_ref (sc_black);
|
|
}
|
|
|
|
GnmColor *
|
|
style_color_white (void)
|
|
{
|
|
if (!sc_white)
|
|
sc_white = style_color_new (0xffff, 0xffff, 0xffff);
|
|
return style_color_ref (sc_white);
|
|
}
|
|
|
|
GnmColor *
|
|
style_color_grid (void)
|
|
{
|
|
if (!sc_grid)
|
|
sc_grid = style_color_new (0xc7c7, 0xc7c7, 0xc7c7);
|
|
return style_color_ref (sc_grid);
|
|
}
|
|
|
|
/**
|
|
* Support for Excel auto-colors.
|
|
*/
|
|
|
|
/**
|
|
* Always black, as far as we know.
|
|
*/
|
|
GnmColor *
|
|
style_color_auto_font (void)
|
|
{
|
|
static GnmColor *color = NULL;
|
|
|
|
if (!color)
|
|
color = style_color_new_uninterned (0, 0, 0, TRUE);
|
|
return style_color_ref (color);
|
|
}
|
|
|
|
/**
|
|
* Always white, as far as we know.
|
|
*/
|
|
GnmColor *
|
|
style_color_auto_back (void)
|
|
{
|
|
static GnmColor *color = NULL;
|
|
|
|
if (!color)
|
|
color = style_color_new_uninterned (0xffff, 0xffff, 0xffff,
|
|
TRUE);
|
|
return style_color_ref (color);
|
|
}
|
|
|
|
/**
|
|
* Normally black, but follows grid color if so told.
|
|
*/
|
|
GnmColor *
|
|
style_color_auto_pattern (void)
|
|
{
|
|
static GnmColor *color = NULL;
|
|
|
|
if (!color)
|
|
color = style_color_new_uninterned (0, 0, 0, TRUE);
|
|
return style_color_ref (color);
|
|
}
|
|
|
|
GnmColor *
|
|
style_color_ref (GnmColor *sc)
|
|
{
|
|
if (sc != NULL)
|
|
sc->ref_count++;
|
|
|
|
return sc;
|
|
}
|
|
|
|
void
|
|
style_color_unref (GnmColor *sc)
|
|
{
|
|
if (sc == NULL)
|
|
return;
|
|
|
|
g_return_if_fail (sc->ref_count > 0);
|
|
|
|
sc->ref_count--;
|
|
if (sc->ref_count != 0)
|
|
return;
|
|
|
|
/*
|
|
* There is no need to deallocate colors, as they come from
|
|
* the GDK Color Context
|
|
*/
|
|
g_hash_table_remove (style_color_hash, sc);
|
|
g_free (sc);
|
|
}
|
|
|
|
gint
|
|
style_color_equal (const GnmColor *k1, const GnmColor *k2)
|
|
{
|
|
if (k1->color.red == k2->color.red &&
|
|
k1->color.green == k2->color.green &&
|
|
k1->color.blue == k2->color.blue &&
|
|
k1->is_auto == k2->is_auto)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static guint
|
|
color_hash (gconstpointer v)
|
|
{
|
|
const GnmColor *k = (const GnmColor *)v;
|
|
|
|
return (k->color.red << 16) ^ (k->color.green << 8) ^ (k->color.blue << 0) ^
|
|
(k->is_auto);
|
|
}
|
|
|
|
void
|
|
gnumeric_color_init (void)
|
|
{
|
|
GdkColor error;
|
|
|
|
gdk_color_parse ("cyan", &error);
|
|
if (gdk_screen_get_default () != NULL) {
|
|
/*
|
|
* Make sure we can see bogus attempt at getting the pixel
|
|
* value. This is, by nature, not multi-head safe.
|
|
*/
|
|
gdk_rgb_find_color (
|
|
gdk_screen_get_default_colormap (
|
|
gdk_screen_get_default ()),
|
|
&error);
|
|
} else
|
|
error.pixel = 0;
|
|
|
|
gs_black.pixel = error.pixel;
|
|
gs_white.pixel = error.pixel;
|
|
gs_yellow.pixel = error.pixel;
|
|
gs_lavender.pixel = error.pixel;
|
|
gs_dark_gray.pixel = error.pixel;
|
|
gs_light_gray.pixel = error.pixel;
|
|
|
|
style_color_hash = g_hash_table_new (color_hash,
|
|
(GEqualFunc) style_color_equal);
|
|
}
|
|
|
|
static void
|
|
cb_color_leak (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
GnmColor *color = value;
|
|
|
|
fprintf (stderr, "Leaking style-color at %p [%04x:%04x:%04x].\n",
|
|
color, color->color.red, color->color.green, color->color.blue);
|
|
}
|
|
|
|
void
|
|
gnumeric_color_shutdown (void)
|
|
{
|
|
/*
|
|
* FIXME: this doesn't really belong here, but style-border.c isn't
|
|
* able to clean itself up yet.
|
|
*/
|
|
GnmBorder *none = style_border_none ();
|
|
style_color_unref (none->color);
|
|
none->color = NULL;
|
|
|
|
if (sc_black) {
|
|
style_color_unref (sc_black);
|
|
sc_black = NULL;
|
|
}
|
|
|
|
if (sc_white) {
|
|
style_color_unref (sc_white);
|
|
sc_white = NULL;
|
|
}
|
|
|
|
if (sc_grid) {
|
|
style_color_unref (sc_grid);
|
|
sc_grid = NULL;
|
|
}
|
|
|
|
g_hash_table_foreach (style_color_hash, cb_color_leak, NULL);
|
|
g_hash_table_destroy (style_color_hash);
|
|
style_color_hash = NULL;
|
|
}
|