#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>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>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); }