diff options
Diffstat (limited to 'libnautilus-extensions/nautilus-smooth-text-layout.c')
-rw-r--r-- | libnautilus-extensions/nautilus-smooth-text-layout.c | 1289 |
1 files changed, 0 insertions, 1289 deletions
diff --git a/libnautilus-extensions/nautilus-smooth-text-layout.c b/libnautilus-extensions/nautilus-smooth-text-layout.c deleted file mode 100644 index 52fcb3dd2..000000000 --- a/libnautilus-extensions/nautilus-smooth-text-layout.c +++ /dev/null @@ -1,1289 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ - -/* nautilus-smooth-text-layout.c - A GtkObject subclass for dealing with smooth text. - - Copyright (C) 2000 Eazel, Inc. - - The Gnome Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Authors: Ramiro Estrugo <ramiro@eazel.com> -*/ - -#include <config.h> -#include "nautilus-smooth-text-layout.h" - -#include "nautilus-gtk-macros.h" -#include "nautilus-gdk-extensions.h" -#include "nautilus-gdk-pixbuf-extensions.h" -#include "nautilus-string.h" -#include "nautilus-glyph.h" -#include "nautilus-debug-drawing.h" - -#include <libgnome/gnome-i18n.h> - -#define MIN_FONT_SIZE 5 -#define DEFAULT_LINE_SPACING 0 -#define DEFAULT_FONT_SIZE 14 - -#define UNDEFINED_DIMENSION -1 - -/* This magic string is copied from GtkLabel. It lives there unlocalized as well. */ -#define DEFAULT_LINE_WRAP_WIDTH_TEXT "This is a good enough length for any line to have." - -#define DEFAULT_LINE_BREAK_CHARACTERS _(" -_,;.?/&") - -/* Detail member struct */ -struct NautilusSmoothTextLayoutDetails -{ - NautilusDimensions dimensions; - - char *text; - int text_length; - - /* Smooth attributes */ - NautilusScalableFont *font; - int font_size; - int line_spacing; - int empty_line_height; - - /* Text lines */ - GList *text_line_list; - int max_line_width; - int num_empty_lines; - int line_wrap_width; - int total_line_height; - - gboolean wrap; - char *line_break_characters; -}; - -/* GtkObjectClass methods */ -static void nautilus_smooth_text_layout_initialize_class (NautilusSmoothTextLayoutClass *smooth_text_layout_class); -static void nautilus_smooth_text_layout_initialize (NautilusSmoothTextLayout *smooth_text_layout); -static void nautilus_smooth_text_layout_destroy (GtkObject *object); - -/* Private functions */ -static void smooth_text_layout_set_text (NautilusSmoothTextLayout *smooth_text_layout, - const char *text, - int text_length); -static void smooth_text_layout_clear_lines (NautilusSmoothTextLayout *smooth_text_layout); -static void smooth_text_layout_ensure_lines (const NautilusSmoothTextLayout *smooth_text_layout); -static int smooth_text_layout_get_num_empty_lines (const NautilusSmoothTextLayout *smooth_text_layout); -static int smooth_text_layout_get_empty_line_height (const NautilusSmoothTextLayout *smooth_text_layout); -static int smooth_text_layout_get_max_line_width (const NautilusSmoothTextLayout *smooth_text_layout); -static int smooth_text_layout_get_total_line_height (const NautilusSmoothTextLayout *smooth_text_layout); -static int smooth_text_layout_get_line_wrap_width (const NautilusSmoothTextLayout *smooth_text_layout); -static GList *smooth_text_layout_line_list_new (const char *text, - int text_length, - NautilusScalableFont *font, - int font_size); -static void smooth_text_layout_line_list_free (GList *smooth_line_list); -void smooth_text_layout_line_list_draw_to_pixbuf (GList *smooth_line_list, - GdkPixbuf *pixbuf, - int x, - int y, - GtkJustification justification, - gboolean underlined, - int empty_line_height, - int max_line_width, - int line_spacing, - guint32 color, - int opacity); -static GList *smooth_text_layout_line_list_new_wrapped (const char *text, - int text_length, - NautilusScalableFont *font, - int font_size, - int max_width, - const char *line_break_characters); - -/* - * The following text_layout stuff was shamelessly plundered - * from libgnomeui/gnome-icon-text.[ch] by Federico Mena. - * - * It was hacked to use NautilusScalableFont and GdkPixbuf - * instead of GdkFont and GdkDrawable. We want to use the - * same layout algorithm in Nautilus so that both the smooth - * and not smooth text rendering cases have predictably - * similar result. - * - * I also made some minor Nautilus-like style changes. -re - - */ -typedef struct -{ - char *text; - int width; - guint text_length; -} NautilusTextLayoutRow; - -typedef struct -{ - GList *rows; - const NautilusScalableFont *font; - int font_size; - int width; - int height; - int baseline_skip; -} NautilusTextLayout; - -NautilusTextLayout *nautilus_text_layout_new (const NautilusScalableFont *font, - int font_size, - const char *text, - const char *separators, - int max_width, - gboolean confine); -void nautilus_text_layout_free (NautilusTextLayout *text_info); - -NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusSmoothTextLayout, nautilus_smooth_text_layout, GTK_TYPE_OBJECT) - -/* Class init methods */ -static void -nautilus_smooth_text_layout_initialize_class (NautilusSmoothTextLayoutClass *smooth_text_layout_class) -{ - GtkObjectClass *object_class = GTK_OBJECT_CLASS (smooth_text_layout_class); - - /* GtkObjectClass */ - object_class->destroy = nautilus_smooth_text_layout_destroy; -} - -void -nautilus_smooth_text_layout_initialize (NautilusSmoothTextLayout *smooth_text_layout) -{ - smooth_text_layout->details = g_new0 (NautilusSmoothTextLayoutDetails, 1); - smooth_text_layout->details->line_break_characters = g_strdup (DEFAULT_LINE_BREAK_CHARACTERS); - smooth_text_layout->details->font = nautilus_scalable_font_get_default_font (); - smooth_text_layout->details->font_size = DEFAULT_FONT_SIZE; - smooth_text_layout->details->line_spacing = DEFAULT_LINE_SPACING; - smooth_text_layout_clear_lines (smooth_text_layout); -} - -/* GtkObjectClass methods */ -static void -nautilus_smooth_text_layout_destroy (GtkObject *object) -{ - NautilusSmoothTextLayout *smooth_text_layout; - - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (object)); - - smooth_text_layout = NAUTILUS_SMOOTH_TEXT_LAYOUT (object); - - smooth_text_layout_clear_lines (smooth_text_layout); - /* FIXME: it seems like we should unref the font here. */ - g_free (smooth_text_layout->details->line_break_characters); - g_free (smooth_text_layout->details->text); - - g_free (smooth_text_layout->details); - - /* Chain destroy */ - NAUTILUS_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object)); -} - -/* Private NautilusSmoothTextLayout functions */ -static void -smooth_text_layout_clear_lines (NautilusSmoothTextLayout *smooth_text_layout) -{ - - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - smooth_text_layout_line_list_free (smooth_text_layout->details->text_line_list); - smooth_text_layout->details->text_line_list = NULL; - smooth_text_layout->details->dimensions.width = UNDEFINED_DIMENSION; - smooth_text_layout->details->dimensions.height = UNDEFINED_DIMENSION; - smooth_text_layout->details->max_line_width = UNDEFINED_DIMENSION; - smooth_text_layout->details->num_empty_lines = UNDEFINED_DIMENSION; - smooth_text_layout->details->empty_line_height = UNDEFINED_DIMENSION; - smooth_text_layout->details->line_wrap_width = UNDEFINED_DIMENSION; - smooth_text_layout->details->total_line_height = UNDEFINED_DIMENSION; - -} - -static void -smooth_text_layout_ensure_lines (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - if (smooth_text_layout->details->text_line_list != NULL) { - return; - } - - /* We cheat a little here. Pretend text_line_list or wrap_text_layouts are mutable */ - if (smooth_text_layout->details->wrap) { - smooth_text_layout->details->text_line_list = - smooth_text_layout_line_list_new_wrapped (smooth_text_layout->details->text, - smooth_text_layout->details->text_length, - smooth_text_layout->details->font, - smooth_text_layout->details->font_size, - smooth_text_layout_get_line_wrap_width (smooth_text_layout), - smooth_text_layout->details->line_break_characters); - } else { - smooth_text_layout->details->text_line_list = - smooth_text_layout_line_list_new (smooth_text_layout->details->text, - smooth_text_layout->details->text_length, - smooth_text_layout->details->font, - smooth_text_layout->details->font_size); - } -} - -static GList * -smooth_text_layout_line_list_new (const char *text, - int text_length, - NautilusScalableFont *font, - int font_size) -{ - GList *line_list = NULL; - const char *line; - const char *end; - - g_return_val_if_fail (NAUTILUS_IS_SCALABLE_FONT (font), NULL); - g_return_val_if_fail (text_length >= 0, NULL); - g_return_val_if_fail (font_size >= MIN_FONT_SIZE, NULL); - - end = text + text_length; - - line = text; - - while (line != NULL && line <= end) { - const char *next_line; - int length; - NautilusGlyph *glyph = NULL; - - next_line = strchr (line, '\n'); - - if (next_line != NULL) { - length = next_line - line; - } else { - length = end - line; - } - - g_assert (length >= 0); - - if (length > 0) { - glyph = nautilus_glyph_new (font, font_size, line, length); - } - - line_list = g_list_append (line_list, glyph); - - if (next_line != NULL) { - line = next_line + 1; - } - else { - line = NULL; - } - } - - return line_list; -} - -static void -smooth_text_layout_line_list_free (GList *smooth_line_list) -{ - GList *node; - - node = smooth_line_list; - while (node) { - if (node->data != NULL) { - nautilus_glyph_free (node->data); - } - node = node->next; - } - - g_list_free (smooth_line_list); -} - -void -smooth_text_layout_line_list_draw_to_pixbuf (GList *text_line_list, - GdkPixbuf *pixbuf, - int x, - int y, - GtkJustification justification, - gboolean underlined, - int empty_line_height, - int max_line_width, - int line_spacing, - guint32 color, - int opacity) -{ - GList *node; - - g_return_if_fail (text_line_list != NULL); - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (pixbuf)); - g_return_if_fail (justification >= GTK_JUSTIFY_LEFT && justification <= GTK_JUSTIFY_FILL); - g_return_if_fail (empty_line_height > 0); - g_return_if_fail (max_line_width > 0); - g_return_if_fail (line_spacing >= 0); - - /* FIXME bugzilla.eazel.com 5087: Make sure the color we are fed is opaque. The real solution is - * to fix the callers. - */ - color = color | 0xFF000000; - - node = text_line_list; - while (node) { - if (node->data != NULL) { - NautilusGlyph *glyph; - int text_x = 0; - int text_y = 0; - - glyph = node->data; - - g_assert (max_line_width >= nautilus_glyph_get_width (glyph)); - - switch (justification) { - case GTK_JUSTIFY_LEFT: - text_x = x; - break; - - case GTK_JUSTIFY_CENTER: - case GTK_JUSTIFY_FILL: - text_x = x + (max_line_width - nautilus_glyph_get_width (glyph)) / 2; - break; - - case GTK_JUSTIFY_RIGHT: - text_x = x + (max_line_width - nautilus_glyph_get_width (glyph)); - break; - - default: - g_assert_not_reached (); - text_x = x; - } - - text_y = y; - - nautilus_glyph_draw_to_pixbuf (glyph, pixbuf, text_x, text_y, NULL, color, opacity); - - /* Underline the text if needed */ - if (underlined) { - ArtIRect underline_rect; - - nautilus_glyph_get_underline_rectangle (glyph, &underline_rect); - underline_rect.y0 += text_y; - underline_rect.y1 += text_y; - underline_rect.x0 += text_x; - underline_rect.x1 += text_x; - nautilus_gdk_pixbuf_fill_rectangle_with_color (pixbuf, - &underline_rect, - color); - } - - y += nautilus_glyph_get_height (glyph) + line_spacing; - } else { - y += empty_line_height; - } - node = node->next; - } -} - -static GList * -smooth_text_layout_line_list_new_wrapped (const char *text, - int text_length, - NautilusScalableFont *font, - int font_size, - int max_width, - const char *line_break_characters) -{ - GList *line_list = NULL; - GList *layout_list = NULL; - GList *layout_node; - const char *line; - const char *end; - - g_return_val_if_fail (NAUTILUS_IS_SCALABLE_FONT (font), NULL); - g_return_val_if_fail (text_length >= 0, NULL); - g_return_val_if_fail (font_size >= MIN_FONT_SIZE, NULL); - g_return_val_if_fail (max_width > 0, NULL); - g_return_val_if_fail (line_break_characters != NULL, NULL); - g_return_val_if_fail (line_break_characters[0] != '\0', NULL); - - end = text + text_length; - line = text; - - while (line != NULL && line <= end) { - /* NULL layout means empty line */ - NautilusTextLayout *layout = NULL; - const char *next_line; - int length; - next_line = strchr (line, '\n'); - - if (next_line != NULL) { - length = next_line - line; - } else { - length = end - line; - } - - g_assert (length >= 0); - - if (length > 0) { - char *null_terminated_line; - null_terminated_line = g_strndup (line, length); - layout = nautilus_text_layout_new (font, - font_size, - null_terminated_line, - line_break_characters, - max_width, - TRUE); - g_free (null_terminated_line); - } - - layout_list = g_list_append (layout_list, layout); - - if (next_line != NULL) { - line = next_line + 1; - } - else { - line = NULL; - } - } - - layout_node = layout_list; - while (layout_node != NULL) { - if (layout_node->data != NULL) { - NautilusTextLayout *layout; - GList *layout_row_node; - g_assert (layout_node->data != NULL); - layout = layout_node->data; - - layout_row_node = layout->rows; - while (layout_row_node != NULL) { - /* NULL glyph means empty line */ - NautilusGlyph *glyph = NULL; - - if (layout_row_node->data != NULL) { - const NautilusTextLayoutRow *row; - row = layout_row_node->data; - - glyph = nautilus_glyph_new (font, font_size, row->text, row->text_length); - } else { - } - - line_list = g_list_append (line_list, glyph); - - layout_row_node = layout_row_node->next; - } - - nautilus_text_layout_free (layout); - } else { - line_list = g_list_append (line_list, NULL); - } - layout_node = layout_node->next; - } - - g_list_free (layout_list); - - return line_list; -} - -static int -smooth_text_layout_get_empty_line_height (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - if (smooth_text_layout->details->empty_line_height == UNDEFINED_DIMENSION) { - smooth_text_layout->details->empty_line_height = smooth_text_layout->details->font_size / 2; - } - - return smooth_text_layout->details->empty_line_height; -} - -static int -smooth_text_layout_get_num_empty_lines (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - if (smooth_text_layout->details->num_empty_lines == UNDEFINED_DIMENSION) { - GList *node; - - smooth_text_layout->details->num_empty_lines = 0; - node = smooth_text_layout->details->text_line_list; - while (node) { - if (node->data == NULL) { - smooth_text_layout->details->num_empty_lines++; - } - node = node->next; - } - } - - return smooth_text_layout->details->num_empty_lines; -} - -static int -smooth_text_layout_get_max_line_width (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - if (smooth_text_layout->details->max_line_width == UNDEFINED_DIMENSION) { - GList *node; - - smooth_text_layout->details->max_line_width = 0; - node = smooth_text_layout->details->text_line_list; - while (node) { - if (node->data != NULL) { - smooth_text_layout->details->max_line_width = MAX (smooth_text_layout->details->max_line_width, - nautilus_glyph_get_width (node->data)); - } - node = node->next; - } - } - - return smooth_text_layout->details->max_line_width; -} - -static int -smooth_text_layout_get_total_line_height (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - if (smooth_text_layout->details->total_line_height == UNDEFINED_DIMENSION) { - GList *node; - - smooth_text_layout->details->total_line_height = 0; - node = smooth_text_layout->details->text_line_list; - while (node) { - if (node->data != NULL) { - smooth_text_layout->details->total_line_height += - nautilus_glyph_get_height (node->data); - } else { - smooth_text_layout->details->total_line_height += - smooth_text_layout_get_empty_line_height (smooth_text_layout); - } - - node = node->next; - } - } - - return smooth_text_layout->details->total_line_height; -} - -static int -smooth_text_layout_get_line_wrap_width (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - if (smooth_text_layout->details->line_wrap_width == UNDEFINED_DIMENSION) { - smooth_text_layout->details->line_wrap_width = - nautilus_scalable_font_text_width (smooth_text_layout->details->font, - smooth_text_layout->details->font_size, - DEFAULT_LINE_WRAP_WIDTH_TEXT, - strlen (DEFAULT_LINE_WRAP_WIDTH_TEXT)); - - } - - return smooth_text_layout->details->line_wrap_width; -} - -/* Public NautilusSmoothTextLayout methods */ - -/** - * nautilus_smooth_text_layout_new: - * @family: The desired smooth_text_layout family. - * @weight: The desired smooth_text_layout weight. - * @slant: The desired smooth_text_layout slant. - * @set_width: The desired smooth_text_layout set_width. - * - * Returns a new smooth_text_layout. - * - */ -NautilusSmoothTextLayout * -nautilus_smooth_text_layout_new (const char *text, - int text_length, - NautilusScalableFont *font, - int font_size, - gboolean wrap) -{ - NautilusSmoothTextLayout *smooth_text_layout; - - g_return_val_if_fail (NAUTILUS_IS_SCALABLE_FONT (font), NULL); - g_return_val_if_fail (font_size >= MIN_FONT_SIZE, NULL); - - smooth_text_layout = NAUTILUS_SMOOTH_TEXT_LAYOUT (gtk_object_new (nautilus_smooth_text_layout_get_type (), NULL)); - gtk_object_ref (GTK_OBJECT (smooth_text_layout)); - gtk_object_sink (GTK_OBJECT (smooth_text_layout)); - - smooth_text_layout_set_text (smooth_text_layout, text, text_length); - nautilus_smooth_text_layout_set_font (smooth_text_layout, font); - nautilus_smooth_text_layout_set_font_size (smooth_text_layout, font_size); - nautilus_smooth_text_layout_set_wrap (smooth_text_layout, wrap); - - return smooth_text_layout; -} - -void -nautilus_smooth_text_layout_draw_to_pixbuf (const NautilusSmoothTextLayout *smooth_text_layout, - GdkPixbuf *destination_pixbuf, - int source_x, - int source_y, - const ArtIRect *destination_area, - GtkJustification justification, - gboolean underlined, - guint32 color, - int opacity) -{ - NautilusDimensions dimensions; - ArtIRect target; - ArtIRect source; - int target_width; - int target_height; - int source_width; - int source_height; - GdkPixbuf *sub_pixbuf; - - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (destination_pixbuf)); - g_return_if_fail (destination_area != NULL); - g_return_if_fail (justification >= GTK_JUSTIFY_LEFT && justification <= GTK_JUSTIFY_FILL); - g_return_if_fail (!art_irect_empty (destination_area)); - - smooth_text_layout_ensure_lines (smooth_text_layout); - - dimensions = nautilus_smooth_text_layout_get_dimensions (smooth_text_layout); - - g_return_if_fail (source_x >= 0); - g_return_if_fail (source_y >= 0); - g_return_if_fail (source_x < dimensions.width); - g_return_if_fail (source_y < dimensions.height); - - /* Clip the destination area to the pixbuf dimensions; bail if no work */ - target = nautilus_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); - if (art_irect_empty (&target)) { - return; - } - - /* Assign the source area */ - nautilus_art_irect_assign (&source, - source_x, - source_y, - dimensions.width - source_x, - dimensions.height - source_y); - - /* Adjust the target width if the source area is smaller than the - * source pixbuf dimensions */ - target_width = target.x1 - target.x0; - target_height = target.y1 - target.y0; - source_width = source.x1 - source.x0; - source_height = source.y1 - source.y0; - - target.x1 = target.x0 + MIN (target_width, source_width); - target.y1 = target.y0 + MIN (target_height, source_height); - - /* Use a sub area pixbuf for simplicity */ - sub_pixbuf = nautilus_gdk_pixbuf_new_from_pixbuf_sub_area (destination_pixbuf, &target); - - smooth_text_layout_line_list_draw_to_pixbuf (smooth_text_layout->details->text_line_list, - sub_pixbuf, - -source_x, - -source_y, - justification, - underlined, - smooth_text_layout_get_empty_line_height (smooth_text_layout), - smooth_text_layout_get_max_line_width (smooth_text_layout), - smooth_text_layout->details->line_spacing, - color, - opacity); - - gdk_pixbuf_unref (sub_pixbuf); -} - -void -nautilus_smooth_text_layout_draw_to_pixbuf_shadow (const NautilusSmoothTextLayout *smooth_text_layout, - GdkPixbuf *destination_pixbuf, - int source_x, - int source_y, - const ArtIRect *destination_area, - int shadow_offset, - GtkJustification justification, - gboolean underlined, - guint32 color, - guint32 shadow_color, - int opacity) -{ - NautilusDimensions dimensions; - ArtIRect target; - ArtIRect source; - int target_width; - int target_height; - int source_width; - int source_height; - GdkPixbuf *sub_pixbuf; - - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - g_return_if_fail (nautilus_gdk_pixbuf_is_valid (destination_pixbuf)); - g_return_if_fail (destination_area != NULL); - g_return_if_fail (shadow_offset > 0); - g_return_if_fail (justification >= GTK_JUSTIFY_LEFT && justification <= GTK_JUSTIFY_FILL); - g_return_if_fail (!art_irect_empty (destination_area)); - - smooth_text_layout_ensure_lines (smooth_text_layout); - - dimensions = nautilus_smooth_text_layout_get_dimensions (smooth_text_layout); - dimensions.width += shadow_offset; - dimensions.height += shadow_offset; - - g_return_if_fail (source_x >= 0); - g_return_if_fail (source_y >= 0); - g_return_if_fail (source_x < dimensions.width); - g_return_if_fail (source_y < dimensions.height); - - /* Clip the destination area to the pixbuf dimensions; bail if no work */ - target = nautilus_gdk_pixbuf_intersect (destination_pixbuf, 0, 0, destination_area); - if (art_irect_empty (&target)) { - return; - } - - /* Assign the source area */ - nautilus_art_irect_assign (&source, - source_x, - source_y, - dimensions.width - source_x, - dimensions.height - source_y); - - /* Adjust the target width if the source area is smaller than the - * source pixbuf dimensions */ - target_width = target.x1 - target.x0; - target_height = target.y1 - target.y0; - source_width = source.x1 - source.x0; - source_height = source.y1 - source.y0; - - target.x1 = target.x0 + MIN (target_width, source_width); - target.y1 = target.y0 + MIN (target_height, source_height); - - /* Use a sub area pixbuf for simplicity */ - sub_pixbuf = nautilus_gdk_pixbuf_new_from_pixbuf_sub_area (destination_pixbuf, &target); - - /* Draw the shadow text */ - smooth_text_layout_line_list_draw_to_pixbuf (smooth_text_layout->details->text_line_list, - sub_pixbuf, - -source_x + shadow_offset, - -source_y + shadow_offset, - justification, - underlined, - smooth_text_layout_get_empty_line_height (smooth_text_layout), - smooth_text_layout_get_max_line_width (smooth_text_layout), - smooth_text_layout->details->line_spacing, - shadow_color, - opacity); - - /* Draw the text */ - smooth_text_layout_line_list_draw_to_pixbuf (smooth_text_layout->details->text_line_list, - sub_pixbuf, - -source_x, - -source_y, - justification, - underlined, - smooth_text_layout_get_empty_line_height (smooth_text_layout), - smooth_text_layout_get_max_line_width (smooth_text_layout), - smooth_text_layout->details->line_spacing, - color, - opacity); - - gdk_pixbuf_unref (sub_pixbuf); -} - -NautilusDimensions -nautilus_smooth_text_layout_get_dimensions (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), NAUTILUS_DIMENSIONS_EMPTY); - - smooth_text_layout_ensure_lines (smooth_text_layout); - - if (smooth_text_layout->details->dimensions.width == UNDEFINED_DIMENSION) { - const int max_line_width = smooth_text_layout_get_max_line_width (smooth_text_layout); - const int num_lines = g_list_length (smooth_text_layout->details->text_line_list); - const int num_empty_lines = smooth_text_layout_get_num_empty_lines (smooth_text_layout); - const int total_line_height = smooth_text_layout_get_total_line_height (smooth_text_layout); - - g_assert (num_lines >= 0); - g_assert (num_empty_lines >= 0); - g_assert (num_lines >= num_empty_lines); - - smooth_text_layout->details->dimensions.width = max_line_width; - smooth_text_layout->details->dimensions.height = total_line_height; - - if (num_lines > 1) { - smooth_text_layout->details->dimensions.height += - (num_lines - 1) * smooth_text_layout->details->line_spacing; - } - } - - return smooth_text_layout->details->dimensions; -} - -int -nautilus_smooth_text_layout_get_width (const NautilusSmoothTextLayout *smooth_text_layout) -{ - NautilusDimensions dimensions; - - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - dimensions = nautilus_smooth_text_layout_get_dimensions (smooth_text_layout); - - return dimensions.width; -} - -int -nautilus_smooth_text_layout_get_height (const NautilusSmoothTextLayout *smooth_text_layout) -{ - NautilusDimensions dimensions; - - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - dimensions = nautilus_smooth_text_layout_get_dimensions (smooth_text_layout); - - return dimensions.height; -} - -void -nautilus_smooth_text_layout_set_wrap (NautilusSmoothTextLayout *smooth_text_layout, - gboolean wrap) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - if (smooth_text_layout->details->wrap == wrap) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - smooth_text_layout->details->wrap = wrap; -} - -gboolean -nautilus_smooth_text_layout_get_wrap (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), FALSE); - - return smooth_text_layout->details->wrap; -} - -void -nautilus_smooth_text_layout_set_font (NautilusSmoothTextLayout *smooth_text_layout, - NautilusScalableFont *font) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - g_return_if_fail (NAUTILUS_IS_SCALABLE_FONT (font)); - - if (smooth_text_layout->details->font == font) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - gtk_object_unref (GTK_OBJECT (smooth_text_layout->details->font)); - gtk_object_ref (GTK_OBJECT (font)); - smooth_text_layout->details->font = font; -} - -NautilusScalableFont * -nautilus_smooth_text_layout_get_font (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), NULL); - - gtk_object_ref (GTK_OBJECT (smooth_text_layout->details->font)); - return smooth_text_layout->details->font; -} - -void -nautilus_smooth_text_layout_set_font_size (NautilusSmoothTextLayout *smooth_text_layout, - int font_size) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - g_return_if_fail (font_size >= MIN_FONT_SIZE); - - if (smooth_text_layout->details->font_size == font_size) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - smooth_text_layout->details->font_size = font_size; -} - -int -nautilus_smooth_text_layout_get_font_size (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - return smooth_text_layout->details->font_size; -} - -void -nautilus_smooth_text_layout_set_line_spacing (NautilusSmoothTextLayout *smooth_text_layout, - int line_spacing) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - if (smooth_text_layout->details->line_spacing == line_spacing) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - smooth_text_layout->details->line_spacing = line_spacing; -} - -int -nautilus_smooth_text_layout_get_line_spacing (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - return smooth_text_layout->details->line_spacing; -} - -void -nautilus_smooth_text_layout_set_empty_line_height (NautilusSmoothTextLayout *smooth_text_layout, - int empty_line_height) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - if (smooth_text_layout->details->empty_line_height == empty_line_height) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - smooth_text_layout->details->empty_line_height = empty_line_height; -} - -int -nautilus_smooth_text_layout_get_empty_line_height (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), 0); - - return smooth_text_layout->details->empty_line_height; -} - -static void -smooth_text_layout_set_text (NautilusSmoothTextLayout *smooth_text_layout, - const char *text, - int text_length) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - if (smooth_text_layout->details->text == text - && smooth_text_layout->details->text_length == text_length) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - g_free (smooth_text_layout->details->text); - smooth_text_layout->details->text = g_strdup (text); - smooth_text_layout->details->text_length = text_length; -} - -void -nautilus_smooth_text_layout_set_line_break_characters (NautilusSmoothTextLayout *smooth_text_layout, - const char *line_break_characters) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - g_return_if_fail (nautilus_strlen (line_break_characters) > 0); - - if (nautilus_str_is_equal (smooth_text_layout->details->line_break_characters, line_break_characters)) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - g_free (smooth_text_layout->details->line_break_characters); - smooth_text_layout->details->line_break_characters = g_strdup (line_break_characters); -} - -char * -nautilus_smooth_text_layout_get_line_break_characters (const NautilusSmoothTextLayout *smooth_text_layout) -{ - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout), FALSE); - - return g_strdup (smooth_text_layout->details->text); -} - -void -nautilus_smooth_text_layout_set_line_wrap_width (NautilusSmoothTextLayout *smooth_text_layout, - int line_wrap_width) -{ - g_return_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (smooth_text_layout)); - - if (smooth_text_layout->details->line_wrap_width == line_wrap_width) { - return; - } - - smooth_text_layout_clear_lines (smooth_text_layout); - smooth_text_layout->details->line_wrap_width = line_wrap_width; -} - -/* - * The following text_layout stuff was shamelessly plundered - * from libgnomeui/gnome-icon-text.[ch] by Federico Mena. - * - * It was hacked to use NautilusScalableFont and GdkPixbuf - * instead of GdkFont and GdkDrawable. We want to use the - * same layout algorithm in Nautilus so that both the smooth - * and not smooth text rendering cases have predictably - * similar result. - * - * I also made some minor Nautilus-like style changes. -re - * - */ -static void -text_layout_free_row (gpointer data, - gpointer user_data) -{ - NautilusTextLayoutRow *row; - - if (data) { - row = data; - g_free (row->text); - g_free (row); - } -} - -/** - * nautilus_text_layout_free: - * @ti: An icon text info structure. - * - * Frees a &NautilusTextLayout structure. You should call this instead of - * freeing the structure yourself. - */ -void -nautilus_text_layout_free (NautilusTextLayout *text_layout) -{ - g_list_foreach (text_layout->rows, text_layout_free_row, NULL); - g_list_free (text_layout->rows); - g_free (text_layout); -} - -/** - * nautilus_text_layout_new: - * @font: Name of the font that will be used to render the text. - * @text: Text to be formatted. - * @separators: Separators used for word wrapping, can be NULL. - * @max_width: Width in pixels to be used for word wrapping. - * @confine: Whether it is mandatory to wrap at @max_width. - * - * Creates a new &NautilusTextLayout structure by wrapping the specified - * text. If non-NULL, the @separators argument defines a set of characters - * to be used as word delimiters for performing word wrapping. If it is - * NULL, then only spaces will be used as word delimiters. - * - * The @max_width argument is used to specify the width at which word - * wrapping will be performed. If there is a very long word that does not - * fit in a single line, the @confine argument can be used to specify - * whether the word should be unconditionally split to fit or whether - * the maximum width should be increased as necessary. - * - * Return value: A newly-created &NautilusTextLayout structure. - */ -NautilusTextLayout * -nautilus_text_layout_new (const NautilusScalableFont *font, - int font_size, - const char *text, - const char *separators, - int max_width, - gboolean confine) -{ - NautilusTextLayout *text_layout; - NautilusTextLayoutRow *row; - const char *row_end; - const char *s, *word_start, *word_end, *old_word_end; - char *sub_text; - int i, w_len; - int w; - const char *text_iter; - int text_len, separators_len; - - g_return_val_if_fail (font != NULL, NULL); - g_return_val_if_fail (font_size > 0, NULL); - g_return_val_if_fail (text != NULL, NULL); - g_return_val_if_fail (nautilus_strlen (text) > 0, NULL); - - if (!separators) - separators = " "; - - text_len = strlen (text); - - separators_len = strlen (separators); - - text_layout = g_new0 (NautilusTextLayout, 1); - - text_layout->rows = NULL; - text_layout->font = font; - text_layout->font_size = font_size; - text_layout->width = 0; - text_layout->height = 0; - text_layout->baseline_skip = font_size; - - word_end = NULL; - - text_iter = text; - while (*text_iter) { - for (row_end = text_iter; *row_end != 0 && *row_end != '\n'; row_end++); - - /* Accumulate words from this row until they don't fit in the max_width */ - - s = text_iter; - - while (s < row_end) { - word_start = s; - old_word_end = word_end; - for (word_end = word_start; *word_end; word_end++) { - const char *p; - for (p = separators; *p; p++) { - if (*word_end == *p) - goto found; - } - } - found: - if (word_end < row_end) - word_end++; - - if (nautilus_scalable_font_text_width (font, font_size, text_iter, word_end - text_iter) > max_width) { - if (word_start == text_iter) { - if (confine) { - /* We must force-split the word. Look for a proper - * place to do it. - */ - - w_len = word_end - word_start; - - for (i = 1; i < w_len; i++) { - w = nautilus_scalable_font_text_width (font, font_size, word_start, i); - if (w > max_width) { - if (i == 1) - /* Shit, not even a single character fits */ - max_width = w; - else - break; - } - } - - /* Create sub-row with the chars that fit */ - - sub_text = g_strndup (word_start, i - 1); - - row = g_new0 (NautilusTextLayoutRow, 1); - row->text = sub_text; - row->text_length = i - 1; - row->width = nautilus_scalable_font_text_width (font, font_size, - sub_text, - strlen (sub_text)); - - text_layout->rows = g_list_append (text_layout->rows, row); - - if (row->width > text_layout->width) - text_layout->width = row->width; - - text_layout->height += text_layout->baseline_skip; - - /* Bump the text pointer */ - - text_iter += i - 1; - s = text_iter; - - continue; - } else - max_width = nautilus_scalable_font_text_width (font, font_size, word_start, word_end - word_start); - - continue; /* Retry split */ - } else { - word_end = old_word_end; /* Restore to region that does fit */ - break; /* Stop the loop because we found something that doesn't fit */ - } - } - - s = word_end; - } - - /* Append row */ - - if (text_iter == row_end) { - /* We are on a newline, so append an empty row */ - - text_layout->rows = g_list_append (text_layout->rows, NULL); - text_layout->height += text_layout->baseline_skip / 2; - - /* Next! */ - - text_iter = row_end + 1; - } else { - /* Create subrow and append it to the list */ - - int sub_len; - sub_len = word_end - text_iter; - - sub_text = g_strndup (text_iter, sub_len); - - row = g_new0 (NautilusTextLayoutRow, 1); - row->text = sub_text; - row->text_length = sub_len; - row->width = nautilus_scalable_font_text_width (font, font_size, sub_text, sub_len); - - text_layout->rows = g_list_append (text_layout->rows, row); - - if (row->width > text_layout->width) - text_layout->width = row->width; - - text_layout->height += text_layout->baseline_skip; - - /* Next! */ - - text_iter = word_end; - } - } - - return text_layout; -} - -#if !defined (NAUTILUS_OMIT_SELF_CHECK) - -gboolean -nautilus_smooth_text_layout_compare (NautilusSmoothTextLayout *x, - NautilusSmoothTextLayout *y) -{ - GList *xp, *yp; - - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (x), FALSE); - g_return_val_if_fail (NAUTILUS_IS_SMOOTH_TEXT_LAYOUT (y), FALSE); - - /* Compare simple things */ - if (x->details->dimensions.width != y->details->dimensions.width - || x->details->dimensions.height != y->details->dimensions.height - || x->details->text_length != y->details->text_length - || memcmp (x->details->text, y->details->text, x->details->text_length) != 0 - || x->details->font != y->details->font - || x->details->font_size != y->details->font_size - || x->details->line_spacing != y->details->line_spacing - || x->details->empty_line_height != y->details->empty_line_height - || x->details->max_line_width != y->details->max_line_width - || x->details->num_empty_lines != y->details->num_empty_lines - || x->details->line_wrap_width != y->details->line_wrap_width - || x->details->total_line_height != y->details->total_line_height - || x->details->wrap != y->details->wrap - || strcmp (x->details->line_break_characters, y->details->line_break_characters) != 0) { - return FALSE; - } - - /* Compare glyphs */ - smooth_text_layout_ensure_lines (x); - smooth_text_layout_ensure_lines (y); - for (xp = x->details->text_line_list, yp = y->details->text_line_list; - xp != NULL && yp != NULL; - xp = xp->next, yp = yp->next) { - if ((xp->data == NULL) != (yp->data == NULL)) { - return FALSE; - } - if (xp->data != NULL - && !nautilus_glyph_compare (xp->data, yp->data)) { - return FALSE; - } - } - if (xp != NULL || yp != NULL) { - return FALSE; - } - - return TRUE; -} - -#endif /* NAUTILUS_OMIT_SELF_CHECK */ |