13
0
livetrax/libs/clearlooks/support.c

982 lines
20 KiB
C

#include "support.h"
/* #define ALWAYS_DITHER_GRADIENTS */
GtkTextDirection
get_direction (GtkWidget *widget)
{
GtkTextDirection dir;
if (widget)
dir = gtk_widget_get_direction (widget);
else
dir = GTK_TEXT_DIR_LTR;
return dir;
}
GdkPixbuf *
generate_bit (unsigned char alpha[], GdkColor *color, double mult)
{
guint r, g, b;
GdkPixbuf *pixbuf;
unsigned char *pixels;
int w, h, rs;
int x, y;
r = (color->red >> 8) * mult;
r = MIN(r, 255);
g = (color->green >> 8) * mult;
g = MIN(g, 255);
b = (color->blue >> 8) * mult;
b = MIN(b, 255);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, RADIO_SIZE, RADIO_SIZE);
w = gdk_pixbuf_get_width (pixbuf);
h = gdk_pixbuf_get_height (pixbuf);
rs = gdk_pixbuf_get_rowstride (pixbuf);
pixels = gdk_pixbuf_get_pixels (pixbuf);
for (y=0; y < h; y++)
{
for (x=0; x < w; x++)
{
pixels[y*rs + x*4 + 0] = r;
pixels[y*rs + x*4 + 1] = g;
pixels[y*rs + x*4 + 2] = b;
if (alpha)
pixels[y*rs + x*4 + 3] = alpha[y*w + x];
else
pixels[y*rs + x*4 + 3] = 255;
}
}
return pixbuf;
}
#define CLAMP_UCHAR(v) ((guchar) (CLAMP (((int)v), (int)0, (int)255)))
GdkPixbuf *
colorize_bit (unsigned char *bit,
unsigned char *alpha,
GdkColor *new_color)
{
GdkPixbuf *pixbuf;
double intensity;
int x, y;
const guchar *src, *asrc;
guchar *dest;
int dest_rowstride;
int width, height;
guchar *dest_pixels;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, RADIO_SIZE, RADIO_SIZE);
if (pixbuf == NULL)
return NULL;
dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
for (y = 0; y < RADIO_SIZE; y++)
{
src = bit + y * RADIO_SIZE;
asrc = alpha + y * RADIO_SIZE;
dest = dest_pixels + y * dest_rowstride;
for (x = 0; x < RADIO_SIZE; x++)
{
double dr, dg, db;
intensity = (src[x] + 0 )/ 255.0;
if (intensity <= 0.5)
{
/* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
dr = (new_color->red * intensity * 2.0) / 65535.0;
dg = (new_color->green * intensity * 2.0) / 65535.0;
db = (new_color->blue * intensity * 2.0) / 65535.0;
}
else
{
/* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
dr = (new_color->red + (65535 - new_color->red) * (intensity - 0.5) * 2.0) / 65535.0;
dg = (new_color->green + (65535 - new_color->green) * (intensity - 0.5) * 2.0) / 65535.0;
db = (new_color->blue + (65535 - new_color->blue) * (intensity - 0.5) * 2.0) / 65535.0;
}
dest[0] = CLAMP_UCHAR (255 * dr);
dest[1] = CLAMP_UCHAR (255 * dg);
dest[2] = CLAMP_UCHAR (255 * db);
dest[3] = asrc[x];
dest += 4;
}
}
return pixbuf;
}
GdkPixmap *
pixbuf_to_pixmap (GtkStyle *style,
GdkPixbuf *pixbuf,
GdkScreen *screen)
{
GdkGC *tmp_gc;
GdkPixmap *pixmap;
pixmap = gdk_pixmap_new (gdk_screen_get_root_window (screen),
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
style->depth);
gdk_drawable_set_colormap (pixmap, style->colormap);
tmp_gc = gdk_gc_new (pixmap);
gdk_pixbuf_render_to_drawable (pixbuf, pixmap, tmp_gc, 0, 0, 0, 0,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
GDK_RGB_DITHER_NORMAL, 0, 0);
gdk_gc_unref (tmp_gc);
return pixmap;
}
void
rgb_to_hls (gdouble *r,
gdouble *g,
gdouble *b)
{
gdouble min;
gdouble max;
gdouble red;
gdouble green;
gdouble blue;
gdouble h, l, s;
gdouble delta;
red = *r;
green = *g;
blue = *b;
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
min = blue;
}
else
{
if (green > blue)
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
l = (max + min) / 2;
s = 0;
h = 0;
if (max != min)
{
if (l <= 0.5)
s = (max - min) / (max + min);
else
s = (max - min) / (2 - max - min);
delta = max -min;
if (red == max)
h = (green - blue) / delta;
else if (green == max)
h = 2 + (blue - red) / delta;
else if (blue == max)
h = 4 + (red - green) / delta;
h *= 60;
if (h < 0.0)
h += 360;
}
*r = h;
*g = l;
*b = s;
}
void
hls_to_rgb (gdouble *h,
gdouble *l,
gdouble *s)
{
gdouble hue;
gdouble lightness;
gdouble saturation;
gdouble m1, m2;
gdouble r, g, b;
lightness = *l;
saturation = *s;
if (lightness <= 0.5)
m2 = lightness * (1 + saturation);
else
m2 = lightness + saturation - lightness * saturation;
m1 = 2 * lightness - m2;
if (saturation == 0)
{
*h = lightness;
*l = lightness;
*s = lightness;
}
else
{
hue = *h + 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
r = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
r = m2;
else if (hue < 240)
r = m1 + (m2 - m1) * (240 - hue) / 60;
else
r = m1;
hue = *h;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
g = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
g = m2;
else if (hue < 240)
g = m1 + (m2 - m1) * (240 - hue) / 60;
else
g = m1;
hue = *h - 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
b = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
b = m2;
else if (hue < 240)
b = m1 + (m2 - m1) * (240 - hue) / 60;
else
b = m1;
*h = r;
*l = g;
*s = b;
}
}
void
shade (GdkColor * a, GdkColor * b, float k)
{
gdouble red;
gdouble green;
gdouble blue;
red = (gdouble) a->red / 65535.0;
green = (gdouble) a->green / 65535.0;
blue = (gdouble) a->blue / 65535.0;
rgb_to_hls (&red, &green, &blue);
green *= k;
if (green > 1.0)
green = 1.0;
else if (green < 0.0)
green = 0.0;
blue *= k;
if (blue > 1.0)
blue = 1.0;
else if (blue < 0.0)
blue = 0.0;
hls_to_rgb (&red, &green, &blue);
b->red = red * 65535.0;
b->green = green * 65535.0;
b->blue = blue * 65535.0;
}
/**************************************************************************/
void
arrow_draw_hline (GdkWindow *window,
GdkGC *gc,
int x1,
int x2,
int y,
gboolean last)
{
if (x2 - x1 < 7 && !last) /* 7 to get garretts pixels, otherwise 6 */
{
gdk_draw_line (window, gc, x1, y, x2, y);
}
else if (last)
{
/* we don't draw "spikes" for very small arrows */
if (x2 - x1 <= 9)
{
/*gdk_draw_line (window, gc, x1+1, y, x1+1, y);
gdk_draw_line (window, gc, x2-1, y, x2-1, y);*/
}
else
{
gdk_draw_line (window, gc, x1+2, y, x1+2, y);
gdk_draw_line (window, gc, x2-2, y, x2-2, y);
}
}
else
{
gdk_draw_line (window, gc, x1, y, x1+2, y);
gdk_draw_line (window, gc, x2-2, y, x2, y);
}
}
void
arrow_draw_vline (GdkWindow *window,
GdkGC *gc,
int y1,
int y2,
int x,
gboolean last)
{
if (y2 - y1 < 7 && !last) /* 7 to get garretts pixels */
gdk_draw_line (window, gc, x, y1, x, y2);
else if (last)
{
/* we don't draw "spikes" for very small arrows */
if (y2 - y1 > 9) {
gdk_draw_line (window, gc, x, y1+2, x, y1+2);
gdk_draw_line (window, gc, x, y2-2, x, y2-2);
}
}
else
{
gdk_draw_line (window, gc, x, y1, x, y1+2);
gdk_draw_line (window, gc, x, y2-2, x, y2);
}
}
void
draw_arrow (GdkWindow *window,
GdkGC *gc,
GdkRectangle *area,
GtkArrowType arrow_type,
gint x,
gint y,
gint width,
gint height)
{
gint i, j;
if (area)
gdk_gc_set_clip_rectangle (gc, area);
if (arrow_type == GTK_ARROW_DOWN)
{
for (i = 0, j = -1; i < height; i++, j++)
arrow_draw_hline (window, gc, x + j, x + width - j - 1, y + i, i == 0);
}
else if (arrow_type == GTK_ARROW_UP)
{
for (i = height - 1, j = -1; i >= 0; i--, j++)
arrow_draw_hline (window, gc, x + j, x + width - j - 1, y + i, i == height - 1);
}
else if (arrow_type == GTK_ARROW_LEFT)
{
for (i = width - 1, j = -1; i >= 0; i--, j++)
arrow_draw_vline (window, gc, y + j, y + height - j - 1, x + i, i == width - 1);
}
else if (arrow_type == GTK_ARROW_RIGHT)
{
for (i = 0, j = -1; i < width; i++, j++)
arrow_draw_vline (window, gc, y + j, y + height - j - 1, x + i, i == 0);
}
if (area)
gdk_gc_set_clip_rectangle (gc, NULL);
}
void
calculate_arrow_geometry (GtkArrowType arrow_type,
gint *x,
gint *y,
gint *width,
gint *height)
{
gint w = *width;
gint h = *height;
switch (arrow_type)
{
case GTK_ARROW_UP:
case GTK_ARROW_DOWN:
w += (w % 2) - 1;
h = (w / 2 + 1) + 1;
if (h > *height)
{
h = *height;
w = 2 * (h - 1) - 1;
}
if (arrow_type == GTK_ARROW_DOWN)
{
if (*height % 2 == 1 || h % 2 == 0)
*height += 1;
}
else
{
if (*height % 2 == 0 || h % 2 == 0)
*height -= 1;
}
break;
case GTK_ARROW_RIGHT:
case GTK_ARROW_LEFT:
h += (h % 2) - 1;
w = (h / 2 + 1) + 1;
if (w > *width)
{
w = *width;
h = 2 * (w - 1) - 1;
}
if (arrow_type == GTK_ARROW_RIGHT)
{
if (*width % 2 == 1 || w % 2 == 0)
*width += 1;
}
else
{
if (*width % 2 == 0 || w % 2 == 0)
*width -= 1;
}
break;
default:
/* should not be reached */
break;
}
*x += (*width - w) / 2;
*y += (*height - h) / 2;
*height = h;
*width = w;
}
void gtk_treeview_get_header_index (GtkTreeView *tv, GtkWidget *header,
gint *column_index, gint *columns,
gboolean *resizable)
{
GList *list;
*column_index = *columns = 0;
list = gtk_tree_view_get_columns (tv);
do
{
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(list->data);
if ( column->button == header )
{
*column_index = *columns;
*resizable = column->resizable;
}
if ( column->visible )
(*columns)++;
} while ((list = g_list_next(list)));
}
void gtk_clist_get_header_index (GtkCList *clist, GtkWidget *button,
gint *column_index, gint *columns)
{
*columns = clist->columns;
int i;
for (i=0; i<*columns; i++)
{
if (clist->column[i].button == button)
{
*column_index = i;
break;
}
}
}
gboolean
sanitize_size (GdkWindow *window,
gint *width,
gint *height)
{
gboolean set_bg = FALSE;
if ((*width == -1) && (*height == -1))
{
set_bg = GDK_IS_WINDOW (window);
gdk_window_get_size (window, width, height);
}
else if (*width == -1)
gdk_window_get_size (window, width, NULL);
else if (*height == -1)
gdk_window_get_size (window, NULL, height);
return set_bg;
}
static GtkRequisition default_option_indicator_size = { 7, 13 };
static GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
void
option_menu_get_props (GtkWidget *widget,
GtkRequisition *indicator_size,
GtkBorder *indicator_spacing)
{
GtkRequisition *tmp_size = NULL;
GtkBorder *tmp_spacing = NULL;
if (widget)
gtk_widget_style_get (widget, "indicator_size", &tmp_size,
"indicator_spacing", &tmp_spacing, NULL);
if (tmp_size)
{
*indicator_size = *tmp_size;
g_free (tmp_size);
}
else
*indicator_size = default_option_indicator_size;
if (tmp_spacing)
{
*indicator_spacing = *tmp_spacing;
g_free (tmp_spacing);
}
else
*indicator_spacing = default_option_indicator_spacing;
}
GtkWidget *special_get_ancestor(GtkWidget * widget,
GType widget_type)
{
g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
while (widget && widget->parent
&& !g_type_is_a(GTK_WIDGET_TYPE(widget->parent),
widget_type))
widget = widget->parent;
if (!
(widget && widget->parent
&& g_type_is_a(GTK_WIDGET_TYPE(widget->parent), widget_type)))
return NULL;
return widget;
}
/* Dithered Gradient Buffers */
static void
internel_image_buffer_free_pixels (guchar *pixels, gpointer data)
{
g_free (pixels);
}
static GdkPixbuf*
internal_image_buffer_new (gint width, gint height)
{
guchar *buf;
int rowstride;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
rowstride = width * 3;
buf = g_try_malloc (height * rowstride);
if (!buf)
return NULL;
return gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB,
FALSE, 8,
width, height, rowstride,
internel_image_buffer_free_pixels, NULL);
}
static void
internal_color_get_as_uchars(GdkColor *color,
guchar *red,
guchar *green,
guchar *blue)
{
*red = (guchar) (color->red / 256.0);
*green = (guchar) (color->green / 256.0);
*blue = (guchar) (color->blue / 256.0);
}
static GdkPixbuf*
internal_create_horizontal_gradient_image_buffer (gint width, gint height,
GdkColor *from,
GdkColor *to)
{
int i;
long r, g, b, dr, dg, db;
GdkPixbuf* buffer;
guchar *ptr;
guchar *pixels;
guchar r0, g0, b0;
guchar rf, gf, bf;
int rowstride;
buffer = internal_image_buffer_new (width, height);
if (buffer == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (buffer);
ptr = pixels;
rowstride = gdk_pixbuf_get_rowstride (buffer);
internal_color_get_as_uchars(from, &r0, &g0, &b0);
internal_color_get_as_uchars(to, &rf, &gf, &bf);
r = r0 << 16;
g = g0 << 16;
b = b0 << 16;
dr = ((rf-r0)<<16)/width;
dg = ((gf-g0)<<16)/width;
db = ((bf-b0)<<16)/width;
/* render the first line */
for (i=0; i<width; i++)
{
*(ptr++) = (guchar)(r>>16);
*(ptr++) = (guchar)(g>>16);
*(ptr++) = (guchar)(b>>16);
r += dr;
g += dg;
b += db;
}
/* copy the first line to the other lines */
for (i=1; i<height; i++)
{
memcpy (&(pixels[i*rowstride]), pixels, rowstride);
}
return buffer;
}
static GdkPixbuf*
internal_create_vertical_gradient_image_buffer (gint width, gint height,
GdkColor *from,
GdkColor *to)
{
gint i, j, max_block, last_block;
long r, g, b, dr, dg, db;
GdkPixbuf *buffer;
guchar *ptr;
guchar point[4];
guchar r0, g0, b0;
guchar rf, gf, bf;
gint rowstride;
guchar *pixels;
buffer = internal_image_buffer_new (width, height);
if (buffer == NULL)
return NULL;
pixels = gdk_pixbuf_get_pixels (buffer);
rowstride = gdk_pixbuf_get_rowstride (buffer);
internal_color_get_as_uchars(from, &r0, &g0, &b0);
internal_color_get_as_uchars(to, &rf, &gf, &bf);
r = r0<<16;
g = g0<<16;
b = b0<<16;
dr = ((rf-r0)<<16)/height;
dg = ((gf-g0)<<16)/height;
db = ((bf-b0)<<16)/height;
max_block = width/2;
for (i=0; i < height; i++)
{
ptr = pixels + i * rowstride;
ptr[0] = r>>16;
ptr[1] = g>>16;
ptr[2] = b>>16;
if (width > 1)
{
last_block = 0;
for (j=1; j <= max_block; j *= 2)
{
memcpy (&(ptr[j*3]), ptr, j*3);
if ((j*2) >= max_block)
{
last_block = j*2;
}
}
if ((last_block < width) && (last_block > 0))
{
memcpy (&(ptr[last_block*3]), ptr, (width - last_block)*3);
}
}
r += dr;
g += dg;
b += db;
}
return buffer;
}
void
draw_vgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
int x, int y, int width, int height,
GdkColor *left_color, GdkColor *right_color)
{
#ifndef ALWAYS_DITHER_GRADIENTS
gboolean dither = ((style->depth > 0) && (style->depth <= 16));
#endif
if ((width <= 0) || (height <= 0))
return;
if ( left_color == NULL || right_color == NULL )
{
gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
return;
}
#ifndef ALWAYS_DITHER_GRADIENTS
if (dither)
#endif
{
GdkPixbuf *image_buffer = NULL;
image_buffer = internal_create_horizontal_gradient_image_buffer (width, height, left_color, right_color);
if (image_buffer)
{
gdk_draw_pixbuf(drawable, gc, image_buffer, 0, 0, x, y, width, height, GDK_RGB_DITHER_MAX, 0, 0);
g_object_unref(image_buffer);
}
}
#ifndef ALWAYS_DITHER_GRADIENTS
else
{
int i;
GdkColor col;
int dr, dg, db;
GdkGCValues old_values;
gdk_gc_get_values (gc, &old_values);
if (left_color == right_color )
{
col = *left_color;
gdk_rgb_find_color (style->colormap, &col);
gdk_gc_set_foreground (gc, &col);
gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
gdk_gc_set_foreground (gc, &old_values.foreground);
return;
}
col = *left_color;
dr = (right_color->red - left_color->red) / width;
dg = (right_color->green - left_color->green) / width;
db = (right_color->blue - left_color->blue) / width;
for (i = 0; i < width; i++)
{
gdk_rgb_find_color (style->colormap, &col);
gdk_gc_set_foreground (gc, &col);
gdk_draw_line (drawable, gc, x + i, y, x + i, y + height - 1);
col.red += dr;
col.green += dg;
col.blue += db;
}
gdk_gc_set_foreground (gc, &old_values.foreground);
}
#endif
}
void
draw_hgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
int x, int y, int width, int height,
GdkColor *top_color, GdkColor *bottom_color)
{
#ifndef ALWAYS_DITHER_GRADIENTS
gboolean dither = ((style->depth > 0) && (style->depth <= 16));
#endif
if ((width <= 0) || (height <= 0))
return;
#ifndef ALWAYS_DITHER_GRADIENTS
if (dither)
#endif
{
GdkPixbuf *image_buffer = NULL;
image_buffer = internal_create_vertical_gradient_image_buffer (width, height, top_color, bottom_color);
if (image_buffer)
{
gdk_draw_pixbuf(drawable, gc, image_buffer, 0, 0, x, y, width, height, GDK_RGB_DITHER_MAX, 0, 0);
g_object_unref(image_buffer);
}
}
#ifndef ALWAYS_DITHER_GRADIENTS
else
{
int i;
GdkColor col;
int dr, dg, db;
GdkGCValues old_values;
gdk_gc_get_values (gc, &old_values);
if (top_color == bottom_color )
{
col = *top_color;
gdk_rgb_find_color (style->colormap, &col);
gdk_gc_set_foreground (gc, &col);
gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
gdk_gc_set_foreground (gc, &old_values.foreground);
return;
}
col = *top_color;
dr = (bottom_color->red - top_color->red) / height;
dg = (bottom_color->green - top_color->green) / height;
db = (bottom_color->blue - top_color->blue) / height;
for (i = 0; i < height; i++)
{
gdk_rgb_find_color (style->colormap, &col);
gdk_gc_set_foreground (gc, &col);
gdk_draw_line (drawable, gc, x, y + i, x + width - 1, y + i);
col.red += dr;
col.green += dg;
col.blue += db;
}
gdk_gc_set_foreground (gc, &old_values.foreground);
}
#endif
}
void blend (GdkColormap *colormap,
GdkColor *a, GdkColor *b, GdkColor *c, int alpha)
{
int inAlpha = 100-alpha;
c->red = (a->red * alpha + b->red * inAlpha) / 100;
c->green = (a->green * alpha + b->green * inAlpha) / 100;
c->blue = (a->blue * alpha + b->blue * inAlpha) / 100;
gdk_rgb_find_color (colormap, c);
}
GtkWidget *get_parent_window (GtkWidget *widget)
{
GtkWidget *parent = widget->parent;
while (parent && GTK_WIDGET_NO_WINDOW (parent))
parent = parent->parent;
return parent;
}
GdkColor *get_parent_bgcolor (GtkWidget *widget)
{
GtkWidget *parent = get_parent_window (widget);
if (parent && parent->style)
return &parent->style->bg[GTK_STATE_NORMAL];
return NULL;
}
GtkWidget *
find_combo_box_widget (GtkWidget * widget)
{
GtkWidget *result = NULL;
if (widget && !GTK_IS_COMBO_BOX_ENTRY (widget))
{
if (GTK_IS_COMBO_BOX (widget))
result = widget;
else
result = find_combo_box_widget(widget->parent);
}
return result;
}
gboolean
is_combo_box (GtkWidget * widget)
{
return (find_combo_box_widget(widget) != NULL);
}