From 405a237c21d370f80e243ca5907e889a36c76418 Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Mon, 27 Mar 2006 19:27:57 -0600 Subject: [PATCH] Print styles and colors --- moo.kdevelop | 10 +- moo/mooedit/mootextprint.c | 396 ++++++++++++++++++++++++++++++++++--- moo/mooedit/mootextprint.h | 4 + 3 files changed, 381 insertions(+), 29 deletions(-) diff --git a/moo.kdevelop b/moo.kdevelop index 120b2ad2..fca252dc 100644 --- a/moo.kdevelop +++ b/moo.kdevelop @@ -36,7 +36,7 @@ gtk-print - medit + ./medit executable / @@ -288,16 +288,16 @@ - + A new empty GAP source file - + A new empty C++ file. - + A new empty header file for C/C++. - + A new empty C file. diff --git a/moo/mooedit/mootextprint.c b/moo/mooedit/mootextprint.c index 9554392b..5766f3e9 100644 --- a/moo/mooedit/mootextprint.c +++ b/moo/mooedit/mootextprint.c @@ -42,7 +42,13 @@ G_DEFINE_TYPE(MooPrintOperation, moo_print_operation, GTK_TYPE_PRINT_OPERATION) enum { PROP_0, - PROP_DOC + PROP_DOC, + PROP_BUFFER, + PROP_WRAP, + PROP_WRAP_MODE, + PROP_ELLIPSIZE, + PROP_FONT, + PROP_USE_STYLES }; @@ -74,6 +80,36 @@ moo_print_operation_set_property (GObject *object, moo_print_operation_set_doc (print, g_value_get_object (value)); break; + case PROP_BUFFER: + moo_print_operation_set_buffer (print, g_value_get_object (value)); + break; + + case PROP_WRAP: + print->wrap = g_value_get_boolean (value) != 0; + g_object_notify (object, "wrap"); + break; + + case PROP_WRAP_MODE: + print->wrap_mode = g_value_get_enum (value); + g_object_notify (object, "wrap-mode"); + break; + + case PROP_ELLIPSIZE: + print->ellipsize = g_value_get_boolean (value) != 0; + g_object_notify (object, "ellipsize"); + break; + + case PROP_FONT: + g_free (print->font); + print->font = g_value_dup_string (value); + g_object_notify (object, "font"); + break; + + case PROP_USE_STYLES: + print->use_styles = g_value_get_boolean (value); + g_object_notify (object, "use-styles"); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -94,6 +130,30 @@ moo_print_operation_get_property (GObject *object, g_value_set_object (value, print->doc); break; + case PROP_BUFFER: + g_value_set_object (value, print->buffer); + break; + + case PROP_WRAP: + g_value_set_boolean (value, print->wrap); + break; + + case PROP_WRAP_MODE: + g_value_set_enum (value, print->wrap_mode); + break; + + case PROP_ELLIPSIZE: + g_value_set_boolean (value, print->ellipsize); + break; + + case PROP_FONT: + g_value_set_string (value, print->font); + break; + + case PROP_USE_STYLES: + g_value_set_boolean (value, print->use_styles); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -120,7 +180,56 @@ moo_print_operation_class_init (MooPrintOperationClass *klass) "doc", "doc", GTK_TYPE_TEXT_VIEW, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_BUFFER, + g_param_spec_object ("buffer", + "buffer", + "buffer", + GTK_TYPE_TEXT_BUFFER, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_FONT, + g_param_spec_string ("font", + "font", + "font", + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_WRAP, + g_param_spec_boolean ("wrap", + "wrap", + "wrap", + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_WRAP_MODE, + g_param_spec_enum ("wrap-mode", + "wrap-mode", + "wrap-mode", + PANGO_TYPE_WRAP_MODE, + PANGO_WRAP_WORD_CHAR, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_ELLIPSIZE, + g_param_spec_boolean ("ellipsize", + "ellipsize", + "ellipsize", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_USE_STYLES, + g_param_spec_boolean ("use-styles", + "use-styles", + "use-styles", + TRUE, + G_PARAM_READWRITE)); } @@ -128,6 +237,7 @@ static void moo_print_operation_init (MooPrintOperation *print) { load_default_settings (); + gtk_print_operation_set_print_settings (GTK_PRINT_OPERATION (print), print_settings); @@ -136,8 +246,10 @@ moo_print_operation_init (MooPrintOperation *print) page_setup); print->last_line = -1; - print->wrap = FALSE; - print->ellipsize = TRUE; + print->wrap = TRUE; + print->wrap_mode = PANGO_WRAP_WORD_CHAR; + print->ellipsize = FALSE; + print->use_styles = TRUE; } @@ -148,6 +260,9 @@ moo_print_operation_set_doc (MooPrintOperation *print, g_return_if_fail (MOO_IS_PRINT_OPERATION (print)); g_return_if_fail (!doc || GTK_IS_TEXT_VIEW (doc)); + if (print->doc == doc) + return; + if (print->doc) g_object_unref (print->doc); if (print->buffer) @@ -165,6 +280,36 @@ moo_print_operation_set_doc (MooPrintOperation *print, { print->buffer = NULL; } + + g_object_freeze_notify (G_OBJECT (print)); + g_object_notify (G_OBJECT (print), "doc"); + g_object_notify (G_OBJECT (print), "buffer"); + g_object_thaw_notify (G_OBJECT (print)); +} + + +void +moo_print_operation_set_buffer (MooPrintOperation *print, + GtkTextBuffer *buffer) +{ + g_return_if_fail (MOO_IS_PRINT_OPERATION (print)); + g_return_if_fail (!buffer || GTK_IS_TEXT_BUFFER (buffer)); + + if (print->buffer == buffer) + return; + + if (print->doc) + g_object_unref (print->doc); + if (print->buffer) + g_object_unref (print->buffer); + + print->doc = NULL; + print->buffer = buffer; + + if (print->buffer) + g_object_ref (print->buffer); + + g_object_notify (G_OBJECT (print), "buffer"); } @@ -221,7 +366,7 @@ moo_print_operation_begin_print (GtkPrintOperation *operation, GtkTextIter iter, print_end; GTimer *timer; - g_return_if_fail (print->doc != NULL); + g_return_if_fail (print->buffer != NULL); g_return_if_fail (print->first_line >= 0); g_return_if_fail (print->last_line < 0 || print->last_line >= print->first_line); g_return_if_fail (print->first_line < gtk_text_buffer_get_line_count (print->buffer)); @@ -239,7 +384,7 @@ moo_print_operation_begin_print (GtkPrintOperation *operation, if (print->font) font = pango_font_description_from_string (print->font); - if (!font) + if (!font && print->doc) { PangoContext *widget_ctx; @@ -259,7 +404,7 @@ moo_print_operation_begin_print (GtkPrintOperation *operation, if (print->wrap) { pango_layout_set_width (print->layout, print->page.width * PANGO_SCALE); - pango_layout_set_wrap (print->layout, PANGO_WRAP_CHAR); + pango_layout_set_wrap (print->layout, print->wrap_mode); } else if (print->ellipsize) { @@ -355,6 +500,221 @@ moo_print_operation_begin_print (GtkPrintOperation *operation, } +static GSList * +iter_get_attrs (GtkTextIter *iter, + const GtkTextIter *limit) +{ + GtkTextIter end; + GtkTextAttributes values; + gboolean has_attributes = FALSE; + GSList *attrs = NULL, *tags; + PangoAttribute *bg = NULL, *fg = NULL, *style = NULL, *ul = NULL; + PangoAttribute *weight = NULL, *st = NULL; + + tags = gtk_text_iter_get_tags (iter); + gtk_text_iter_forward_to_tag_toggle (iter, NULL); + + if (gtk_text_iter_compare (iter, limit) > 0) + *iter = *limit; + + while (tags) + { + GtkTextTag *tag = tags->data; + gboolean bg_set, fg_set, style_set, ul_set, weight_set, st_set; + + g_object_get (tag, + "background-set", &bg_set, + "foreground-set", &fg_set, + "style-set", &style_set, + "underline-set", &ul_set, + "weight-set", &weight_set, + "strikethrough-set", &st_set, + NULL); + + if (bg_set) + { + GdkColor *color = NULL; + if (bg) pango_attribute_destroy (bg); + g_object_get (tag, "background-gdk", &color, NULL); + bg = pango_attr_background_new (color->red, color->green, color->blue); + gdk_color_free (color); + } + + if (fg_set) + { + GdkColor *color = NULL; + if (fg) pango_attribute_destroy (fg); + g_object_get (tag, "foreground-gdk", &color, NULL); + fg = pango_attr_foreground_new (color->red, color->green, color->blue); + gdk_color_free (color); + } + + if (style_set) + { + PangoStyle style_value; + if (style) pango_attribute_destroy (style); + g_object_get (tag, "style", &style_value, NULL); + style = pango_attr_style_new (style_value); + } + + if (ul_set) + { + PangoUnderline underline; + if (ul) pango_attribute_destroy (ul); + g_object_get (tag, "underline", &underline, NULL); + ul = pango_attr_underline_new (underline); + } + + if (weight_set) + { + PangoWeight weight_value; + if (weight) pango_attribute_destroy (weight); + g_object_get (tag, "weight", &weight_value, NULL); + weight = pango_attr_weight_new (weight_value); + } + + if (st_set) + { + gboolean strikethrough; + if (st) pango_attribute_destroy (st); + g_object_get (tag, "strikethrough", &strikethrough, NULL); + st = pango_attr_strikethrough_new (strikethrough); + } + + tags = g_slist_delete_link (tags, tags); + } + + if (bg) + attrs = g_slist_prepend (attrs, bg); + if (fg) + attrs = g_slist_prepend (attrs, fg); + if (style) + attrs = g_slist_prepend (attrs, style); + if (ul) + attrs = g_slist_prepend (attrs, ul); + if (weight) + attrs = g_slist_prepend (attrs, weight); + if (st) + attrs = g_slist_prepend (attrs, st); + + return attrs; +} + + +static void +fill_layout (PangoLayout *layout, + const GtkTextIter *start, + const GtkTextIter *end) +{ + char *text; + PangoAttrList *attr_list; + GtkTextIter segm_start, segm_end; + int start_index; + + text = gtk_text_iter_get_text (start, end); + pango_layout_set_text (layout, text, -1); + + attr_list = NULL; + segm_start = *start; + start_index = gtk_text_iter_get_line_index (start); + + while (gtk_text_iter_compare (&segm_start, end) < 0) + { + GSList *attrs; + + segm_end = segm_start; + attrs = iter_get_attrs (&segm_end, end); + + if (attrs) + { + int si, ei; + + si = gtk_text_iter_get_line_index (&segm_start) - start_index; + ei = gtk_text_iter_get_line_index (&segm_end) - start_index; + + while (attrs) + { + PangoAttribute *a = attrs->data; + + a->start_index = si; + a->end_index = ei; + + if (!attr_list) + attr_list = pango_attr_list_new (); + + pango_attr_list_insert (attr_list, a); + + attrs = g_slist_delete_link (attrs, attrs); + } + } + + segm_start = segm_end; + } + + pango_layout_set_attributes (layout, attr_list); + + if (attr_list) + pango_attr_list_unref (attr_list); +} + + +static void +print_page (MooPrintOperation *print, + const GtkTextIter *start, + const GtkTextIter *end, + cairo_t *cr) +{ + char *text; + GtkTextIter line_start, line_end; + double offset; + + cairo_set_source_rgb (cr, 0, 0, 0); + + if (!print->use_styles) + { + text = gtk_text_buffer_get_text (print->buffer, start, end, FALSE); + pango_layout_set_text (print->layout, text, -1); + g_free (text); + + cairo_move_to (cr, print->page.x, print->page.y); + pango_cairo_show_layout (cr, print->layout); + + return; + } + + line_start = *start; + offset = 0; + + while (gtk_text_iter_compare (&line_start, end) < 0) + { + PangoRectangle line_rect; + + if (gtk_text_iter_ends_line (&line_start)) + { + pango_layout_set_text (print->layout, "", 0); + pango_layout_set_attributes (print->layout, NULL); + } + else + { + line_end = line_start; + gtk_text_iter_forward_to_line_end (&line_end); + + if (gtk_text_iter_compare (&line_end, end) > 0) + line_end = *end; + + fill_layout (print->layout,&line_start, &line_end); + } + + cairo_move_to (cr, 0, offset); + pango_cairo_show_layout (cr, print->layout); + + pango_layout_get_pixel_extents (print->layout, NULL, &line_rect); + offset += line_rect.height; + gtk_text_iter_forward_line (&line_start); + } +} + + static void moo_print_operation_draw_page (GtkPrintOperation *operation, GtkPrintContext *context, @@ -366,7 +726,7 @@ moo_print_operation_draw_page (GtkPrintOperation *operation, MooPrintOperation *print = MOO_PRINT_OPERATION (operation); GTimer *timer; - g_return_if_fail (print->doc != NULL); + g_return_if_fail (print->buffer != NULL); g_return_if_fail (print->pages != NULL); g_return_if_fail (print->layout != NULL); g_return_if_fail (page_nr < print->pages->len); @@ -374,7 +734,6 @@ moo_print_operation_draw_page (GtkPrintOperation *operation, timer = g_timer_new (); cr = gtk_print_context_get_cairo (context); - cairo_set_source_rgb (cr, 0, 0, 0); start = g_array_index (print->pages, GtkTextIter, page_nr); @@ -383,12 +742,7 @@ moo_print_operation_draw_page (GtkPrintOperation *operation, else gtk_text_buffer_get_end_iter (print->buffer, &end); - text = gtk_text_buffer_get_text (print->buffer, &start, &end, FALSE); - pango_layout_set_text (print->layout, text, -1); - g_free (text); - - cairo_move_to (cr, print->page.x, print->page.y); - pango_cairo_show_layout (cr, print->layout); + print_page (print, &start, &end, cr); g_message ("page %d: %f s", page_nr, g_timer_elapsed (timer, NULL)); g_timer_destroy (timer); @@ -401,7 +755,7 @@ moo_print_operation_end_print (GtkPrintOperation *operation, { MooPrintOperation *print = MOO_PRINT_OPERATION (operation); - g_return_if_fail (print->doc != NULL); + g_return_if_fail (print->buffer != NULL); g_object_unref (print->layout); g_array_free (print->pages, TRUE); @@ -425,17 +779,11 @@ moo_edit_print (GtkTextView *view, print = g_object_new (MOO_TYPE_PRINT_OPERATION, "doc", view, NULL); - { - GtkTextIter start, end; - GtkTextBuffer *buffer = gtk_text_view_get_buffer (view); - gtk_text_buffer_get_bounds (buffer, &start, &end); - g_assert (strlen (gtk_text_buffer_get_text (buffer, &start, &end, FALSE)) > 0); - g_assert (MOO_PRINT_OPERATION(print)->last_line < 0); - } - if (!parent) parent = GTK_WIDGET (view); + parent = gtk_widget_get_toplevel (parent); + if (GTK_WIDGET_TOPLEVEL (parent)) parent_window = GTK_WINDOW (parent); diff --git a/moo/mooedit/mootextprint.h b/moo/mooedit/mootextprint.h index 8a701ec8..123e3037 100644 --- a/moo/mooedit/mootextprint.h +++ b/moo/mooedit/mootextprint.h @@ -41,7 +41,9 @@ struct _MooPrintOperation int last_line; /* -1 to print everything after first_line */ char *font; /* overrides font set in the doc */ gboolean wrap; + PangoWrapMode wrap_mode; gboolean ellipsize; + gboolean use_styles; /* aux stuff */ GArray *pages; /* GtkTextIter's pointing to pages start */ @@ -65,6 +67,8 @@ GType moo_print_operation_get_type (void) G_GNUC_CONST; void moo_print_operation_set_doc (MooPrintOperation *print, GtkTextView *doc); +void moo_print_operation_set_buffer (MooPrintOperation *print, + GtkTextBuffer *buffer); void moo_edit_page_setup (GtkTextView *view, GtkWidget *parent);