/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2010 Free Software Foundation, Inc. * * 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, see . */ #include #include #include #include #include "contact-sheet-enum-types.h" #include "gth-contact-sheet-theme.h" #define DEFAULT_FONT "Sans 12" #define FRAME_BORDER 5 #define HEADER_TEXT _("Header") #define FOOTER_TEXT _("Footer") #define CAPTION_TEXT _("Caption") static void _g_key_file_get_rgba (GKeyFile *key_file, char *group_name, char *key, GdkRGBA *color, GError **error) { char *spec; spec = g_key_file_get_string (key_file, group_name, key, error); if (spec != NULL) gdk_rgba_parse (color, spec); g_free (spec); } static void _g_key_file_set_rgba (GKeyFile *key_file, char *group_name, char *key, GdkRGBA *color) { char *color_value; color_value = gdk_rgba_to_string (color); g_key_file_set_string (key_file, group_name, key, color_value); g_free (color_value); } GthContactSheetTheme * gth_contact_sheet_theme_new (void) { GthContactSheetTheme *theme; theme = g_new0 (GthContactSheetTheme, 1); theme->ref = 1; theme->frame_hpadding = 8; theme->frame_vpadding = 8; theme->caption_spacing = 3; theme->row_spacing = 15; theme->col_spacing = 15; theme->frame_border = 0; theme->editable = TRUE; return theme; } GthContactSheetTheme * gth_contact_sheet_theme_new_from_key_file (GKeyFile *key_file) { GthContactSheetTheme *theme; char *nick; theme = gth_contact_sheet_theme_new (); theme->display_name = g_key_file_get_string (key_file, "Theme", "Name", NULL); nick = g_key_file_get_string (key_file, "Background", "Type", NULL); theme->background_type = _g_enum_type_get_value_by_nick (GTH_TYPE_CONTACT_SHEET_BACKGROUND_TYPE, nick)->value; g_free (nick); _g_key_file_get_rgba (key_file, "Background", "Color1", &theme->background_color1, NULL); _g_key_file_get_rgba (key_file, "Background", "Color2", &theme->background_color2, NULL); _g_key_file_get_rgba (key_file, "Background", "Color3", &theme->background_color3, NULL); _g_key_file_get_rgba (key_file, "Background", "Color4", &theme->background_color4, NULL); nick = g_key_file_get_string (key_file, "Frame", "Style", NULL); theme->frame_style = _g_enum_type_get_value_by_nick (GTH_TYPE_CONTACT_SHEET_FRAME_STYLE, nick)->value; g_free (nick); _g_key_file_get_rgba (key_file, "Frame", "Color", &theme->frame_color, NULL); theme->header_font_name = g_key_file_get_string (key_file, "Header", "Font", NULL); _g_key_file_get_rgba (key_file, "Header", "Color", &theme->header_color, NULL); theme->footer_font_name = g_key_file_get_string (key_file, "Footer", "Font", NULL); _g_key_file_get_rgba (key_file, "Footer", "Color", &theme->footer_color, NULL); theme->caption_font_name = g_key_file_get_string (key_file, "Caption", "Font", NULL); _g_key_file_get_rgba (key_file, "Caption", "Color", &theme->caption_color, NULL); return theme; } GthContactSheetTheme * gth_contact_sheet_theme_dup (GthContactSheetTheme *theme) { GthContactSheetTheme *new_theme = NULL; void *data; gsize length; GKeyFile *key_file; gth_contact_sheet_theme_to_data (theme, &data, &length, NULL); key_file = g_key_file_new (); if (g_key_file_load_from_data (key_file, data, length, G_KEY_FILE_NONE, NULL)) new_theme = gth_contact_sheet_theme_new_from_key_file (key_file); g_key_file_free (key_file); if (new_theme != NULL) { _g_object_unref (new_theme->file); new_theme->file = _g_object_ref (theme->file); } return new_theme; } gboolean gth_contact_sheet_theme_to_data (GthContactSheetTheme *theme, void **buffer, gsize *count, GError **error) { GKeyFile *key_file; key_file = g_key_file_new (); g_key_file_set_string (key_file, "Theme", "Name", theme->display_name); g_key_file_set_string (key_file, "Background", "Type", _g_enum_type_get_value (GTH_TYPE_CONTACT_SHEET_BACKGROUND_TYPE, theme->background_type)->value_nick); _g_key_file_set_rgba (key_file, "Background", "Color1", &theme->background_color1); if (theme->background_type != GTH_CONTACT_SHEET_BACKGROUND_TYPE_SOLID) { _g_key_file_set_rgba (key_file, "Background", "Color2", &theme->background_color2); if (theme->background_type == GTH_CONTACT_SHEET_BACKGROUND_TYPE_FULL) { _g_key_file_set_rgba (key_file, "Background", "Color3", &theme->background_color3); _g_key_file_set_rgba (key_file, "Background", "Color4", &theme->background_color4); } } g_key_file_set_string (key_file, "Frame", "Style", _g_enum_type_get_value (GTH_TYPE_CONTACT_SHEET_FRAME_STYLE, theme->frame_style)->value_nick); _g_key_file_set_rgba (key_file, "Frame", "Color", &theme->frame_color); g_key_file_set_string (key_file, "Header", "Font", theme->header_font_name); _g_key_file_set_rgba (key_file, "Header", "Color", &theme->header_color); g_key_file_set_string (key_file, "Footer", "Font", theme->footer_font_name); _g_key_file_set_rgba (key_file, "Footer", "Color", &theme->footer_color); g_key_file_set_string (key_file, "Caption", "Font", theme->caption_font_name); _g_key_file_set_rgba (key_file, "Caption", "Color", &theme->caption_color); *buffer = g_key_file_to_data (key_file, count, error); g_key_file_free (key_file); return *buffer != NULL; } GthContactSheetTheme * gth_contact_sheet_theme_ref (GthContactSheetTheme *theme) { theme->ref++; return theme; } void gth_contact_sheet_theme_unref (GthContactSheetTheme *theme) { if (theme == NULL) return; theme->ref--; if (theme->ref > 0) return; _g_object_unref (theme->file); g_free (theme->display_name); g_free (theme->header_font_name); g_free (theme->footer_font_name); g_free (theme->caption_font_name); g_free (theme); } void gth_contact_sheet_theme_paint_background (GthContactSheetTheme *theme, cairo_t *cr, int width, int height) { cairo_surface_t *surface; cairo_pattern_t *pattern; switch (theme->background_type) { case GTH_CONTACT_SHEET_BACKGROUND_TYPE_SOLID: gdk_cairo_set_source_rgba (cr, &theme->background_color1); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); break; case GTH_CONTACT_SHEET_BACKGROUND_TYPE_VERTICAL: pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, height); cairo_pattern_add_color_stop_rgba (pattern, 0.0, theme->background_color1.red, theme->background_color1.green, theme->background_color1.blue, theme->background_color1.alpha); cairo_pattern_add_color_stop_rgba (pattern, height, theme->background_color2.red, theme->background_color2.green, theme->background_color2.blue, theme->background_color2.alpha); cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST); cairo_set_source (cr, pattern); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); cairo_pattern_destroy (pattern); break; case GTH_CONTACT_SHEET_BACKGROUND_TYPE_HORIZONTAL: pattern = cairo_pattern_create_linear (0.0, 0.0, width, 0.0); cairo_pattern_add_color_stop_rgba (pattern, 0.0, theme->background_color1.red, theme->background_color1.green, theme->background_color1.blue, theme->background_color1.alpha); cairo_pattern_add_color_stop_rgba (pattern, width, theme->background_color2.red, theme->background_color2.green, theme->background_color2.blue, theme->background_color2.alpha); cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST); cairo_set_source (cr, pattern); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); cairo_pattern_destroy (pattern); break; case GTH_CONTACT_SHEET_BACKGROUND_TYPE_FULL: surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy (surface); break; } _cairo_paint_full_gradient (surface, &theme->background_color1, &theme->background_color2, &theme->background_color3, &theme->background_color4); cairo_set_source_surface (cr, surface, 0, 0); cairo_rectangle (cr, 0, 0, width, height); cairo_fill (cr); cairo_surface_destroy (surface); break; } } void gth_contact_sheet_theme_paint_frame (GthContactSheetTheme *theme, cairo_t *cr, cairo_rectangle_int_t *frame_rect, cairo_rectangle_int_t *image_rect) { int width; switch (theme->frame_style) { case GTH_CONTACT_SHEET_FRAME_STYLE_NONE: break; case GTH_CONTACT_SHEET_FRAME_STYLE_SHADOW: _cairo_draw_drop_shadow (cr, image_rect->x, image_rect->y, image_rect->width, image_rect->height, 3); break; case GTH_CONTACT_SHEET_FRAME_STYLE_SIMPLE: gdk_cairo_set_source_rgba (cr, &theme->frame_color); _cairo_draw_frame (cr, image_rect->x, image_rect->y, image_rect->width, image_rect->height, 3); break; case GTH_CONTACT_SHEET_FRAME_STYLE_SIMPLE_WITH_SHADOW: _cairo_draw_drop_shadow (cr, image_rect->x, image_rect->y, image_rect->width, image_rect->height, 5); gdk_cairo_set_source_rgba (cr, &theme->frame_color); _cairo_draw_frame (cr, image_rect->x, image_rect->y, image_rect->width, image_rect->height, 3); break; case GTH_CONTACT_SHEET_FRAME_STYLE_SLIDE: _cairo_draw_slide (cr, frame_rect->x, frame_rect->y, frame_rect->width, frame_rect->height, image_rect->width, image_rect->height, &theme->frame_color, TRUE); break; case GTH_CONTACT_SHEET_FRAME_STYLE_SHADOW_IN: width = 3; cairo_save (cr); cairo_set_line_width (cr, width); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5); cairo_move_to (cr, image_rect->x + image_rect->width + (width / 2), image_rect->y - (width / 2)); cairo_line_to (cr, image_rect->x - (width / 2), image_rect->y - (width / 2)); cairo_line_to (cr, image_rect->x - (width / 2), image_rect->y + image_rect->height + (width / 2)); cairo_stroke (cr); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5); cairo_move_to (cr, image_rect->x + image_rect->width + (width / 2), image_rect->y - (width / 2)); cairo_line_to (cr, image_rect->x + image_rect->width + (width / 2), image_rect->y + image_rect->height + (width / 2)); cairo_line_to (cr, image_rect->x - (width / 2), image_rect->y + image_rect->height + (width / 2)); cairo_stroke (cr); cairo_restore (cr); break; case GTH_CONTACT_SHEET_FRAME_STYLE_SHADOW_OUT: width = 3; cairo_save (cr); cairo_set_line_width (cr, width); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5); cairo_move_to (cr, image_rect->x + image_rect->width + (width / 2), image_rect->y - (width / 2)); cairo_line_to (cr, image_rect->x - (width / 2), image_rect->y - (width / 2)); cairo_line_to (cr, image_rect->x - (width / 2), image_rect->y + image_rect->height + (width / 2)); cairo_stroke (cr); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5); cairo_move_to (cr, image_rect->x + image_rect->width + (width / 2), image_rect->y - (width / 2)); cairo_line_to (cr, image_rect->x + image_rect->width + (width / 2), image_rect->y + image_rect->height + (width / 2)); cairo_line_to (cr, image_rect->x - (width / 2), image_rect->y + image_rect->height + (width / 2)); cairo_stroke (cr); cairo_restore (cr); break; } } static void get_text_bounds (GthContactSheetTheme *theme, const char *font_name, int width, double font_scale, const char *text, PangoRectangle *bounds) { PangoContext *pango_context; PangoLayout *pango_layout; PangoFontDescription *font_desc; pango_context = gdk_pango_context_get (); pango_context_set_language (pango_context, gtk_get_default_language ()); pango_layout = pango_layout_new (pango_context); pango_layout_set_alignment (pango_layout, PANGO_ALIGN_CENTER); if (font_name != NULL) font_desc = pango_font_description_from_string (font_name); else font_desc = pango_font_description_from_string (DEFAULT_FONT); if (font_scale != 1.0) { double size_in_points; cairo_font_options_t *options; size_in_points = (double) pango_font_description_get_size (font_desc) * font_scale; pango_font_description_set_absolute_size (font_desc, size_in_points); pango_layout_set_font_description (pango_layout, font_desc); options = cairo_font_options_create (); cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); pango_cairo_context_set_font_options (pango_context, options); cairo_font_options_destroy (options); } pango_layout_set_font_description (pango_layout, font_desc); pango_layout_set_width (pango_layout, width * PANGO_SCALE); pango_layout_set_wrap (pango_layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_text (pango_layout, text, -1); pango_layout_get_pixel_extents (pango_layout, NULL, bounds); } static void paint_text (GthContactSheetTheme *theme, cairo_t *cr, const char *font_name, GdkRGBA *color, int x, int y, int width, gboolean footer, double font_scale, const char *text) { PangoContext *pango_context; PangoLayout *pango_layout; PangoFontDescription *font_desc; PangoRectangle bounds; pango_context = gdk_pango_context_get (); pango_context_set_language (pango_context, gtk_get_default_language ()); pango_layout = pango_layout_new (pango_context); pango_layout_set_alignment (pango_layout, PANGO_ALIGN_CENTER); if (font_name != NULL) font_desc = pango_font_description_from_string (font_name); else font_desc = pango_font_description_from_string (DEFAULT_FONT); if (font_scale != 1.0) { double size_in_points; cairo_font_options_t *options; size_in_points = (double) pango_font_description_get_size (font_desc) * font_scale; pango_font_description_set_absolute_size (font_desc, size_in_points); pango_layout_set_font_description (pango_layout, font_desc); options = cairo_font_options_create (); cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); pango_cairo_context_set_font_options (pango_context, options); cairo_font_options_destroy (options); } pango_layout_set_font_description (pango_layout, font_desc); pango_layout_set_width (pango_layout, width * PANGO_SCALE); pango_layout_set_wrap (pango_layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_text (pango_layout, text, -1); pango_layout_get_pixel_extents (pango_layout, NULL, &bounds); cairo_save (cr); gdk_cairo_set_source_rgba (cr, color); pango_cairo_update_layout (cr, pango_layout); if (footer) cairo_move_to (cr, x, y - bounds.height - 2); else cairo_move_to (cr, x, y); pango_cairo_show_layout (cr, pango_layout); cairo_restore (cr); #if 0 cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); cairo_rectangle (cr, x, y, width, bounds.height); cairo_stroke (cr); #endif pango_font_description_free (font_desc); g_object_unref (pango_layout); g_object_unref (pango_context); } static void paint_thumbnail (GthContactSheetTheme *theme, cairo_t *cr, cairo_rectangle_int_t *image_rect, double font_scale) { cairo_rectangle_int_t frame_rect; /* frame */ frame_rect.x = image_rect->x - FRAME_BORDER; frame_rect.y = image_rect->y - FRAME_BORDER; frame_rect.width = image_rect->width + (FRAME_BORDER * 2); frame_rect.height = image_rect->height + (FRAME_BORDER * 2); gth_contact_sheet_theme_paint_frame (theme, cr, &frame_rect, image_rect); /* pseduo-image */ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_rectangle (cr, image_rect->x, image_rect->y, image_rect->width, image_rect->height); cairo_fill (cr); cairo_set_source_rgb (cr, 0.66, 0.66, 0.66); cairo_set_line_width (cr, 1.0); cairo_rectangle (cr, image_rect->x + 0.5, image_rect->y + 0.5, image_rect->width - 1, image_rect->height - 1); cairo_move_to (cr, image_rect->x + 0.5, image_rect->y + 0.5); cairo_line_to (cr, image_rect->x + image_rect->width - 1, image_rect->y + 0.5 + image_rect->height - 1); cairo_move_to (cr, image_rect->x + image_rect->width - 1, image_rect->y + 0.5); cairo_line_to (cr, image_rect->x + 0.5, image_rect->y + 0.5 + image_rect->height - 1); cairo_stroke (cr); /* caption */ paint_text (theme, cr, theme->caption_font_name, &theme->caption_color, frame_rect.x, frame_rect.y + frame_rect.height + 2, frame_rect.width, FALSE, font_scale, CAPTION_TEXT); } void gth_contact_sheet_theme_paint_preview (GthContactSheetTheme *theme, cairo_t *cr, int width, int height) { double font_scale; cairo_rectangle_int_t image_rect; if (height < 200) font_scale = height / 200.0; else font_scale = 1.0; gth_contact_sheet_theme_paint_background (theme, cr, width, height); /* thumbnail */ if (height < 200) { image_rect.width = width / 2; image_rect.height = image_rect.width; image_rect.x = (width - image_rect.width) / 2; image_rect.y = (height - image_rect.height) / 2 - 3; paint_thumbnail (theme, cr, &image_rect, font_scale); } else { PangoRectangle header_rect; PangoRectangle footer_rect; PangoRectangle caption_rect; int n_columns; int n_rows; int size; int x_offset; int y_offset; int c, r; size = 80; get_text_bounds (theme, theme->header_font_name, width, font_scale, HEADER_TEXT, &header_rect); get_text_bounds (theme, theme->footer_font_name, width, font_scale, FOOTER_TEXT, &footer_rect); get_text_bounds (theme, theme->caption_font_name, size, font_scale, CAPTION_TEXT, &caption_rect); n_columns = ((width- (theme->col_spacing * 2)) / (size + (FRAME_BORDER * 2) + theme->col_spacing)); n_rows = ((height - header_rect.height - (theme->row_spacing * 2) - footer_rect.height) / (size + theme->col_spacing + caption_rect.height)); x_offset = (width - (n_columns * (size + theme->col_spacing))) / 2; y_offset = header_rect.height + theme->row_spacing; for (r = 0; r < n_rows; r++) { int y; y = y_offset + r * (size + caption_rect.height + theme->row_spacing); for (c = 0; c < n_columns; c++) { image_rect.width = size; image_rect.height = size; image_rect.x = x_offset + c * (size + theme->col_spacing); image_rect.y = y; paint_thumbnail (theme, cr, &image_rect, font_scale); } } } /* header */ paint_text (theme, cr, theme->header_font_name, &theme->header_color, 0, 0, width, FALSE, font_scale, HEADER_TEXT); /* footer */ paint_text (theme, cr, theme->footer_font_name, &theme->footer_color, 0, height, width, TRUE, font_scale, FOOTER_TEXT); } GdkPixbuf * gth_contact_sheet_theme_create_preview (GthContactSheetTheme *theme, int preview_size) { cairo_surface_t *surface; cairo_t *cr; GdkPixbuf *pixbuf; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, preview_size, preview_size); cr = cairo_create (surface); cairo_surface_destroy (surface); gth_contact_sheet_theme_paint_preview (theme, cr, preview_size, preview_size); pixbuf = _gdk_pixbuf_new_from_cairo_context (cr); cairo_destroy (cr); return pixbuf; } GList * gth_contact_sheet_theme_list_copy (GList *list) { GList *new_list; new_list = g_list_copy (list); g_list_foreach (new_list, (GFunc) gth_contact_sheet_theme_ref, NULL); return new_list; } void gth_contact_sheet_theme_list_free (GList *list) { g_list_foreach (list, (GFunc) gth_contact_sheet_theme_unref, NULL); g_list_free (list); }