static PangoLayout * gimp_ruler_create_layout (GtkWidget *widget, const gchar *text) { GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (widget); PangoLayout *layout; PangoAttrList *attrs; PangoAttribute *attr; layout = gtk_widget_create_pango_layout (widget, text); attrs = pango_attr_list_new (); attr = pango_attr_scale_new (priv->font_scale); attr->start_index = 0; attr->end_index = -1; pango_attr_list_insert (attrs, attr); pango_layout_set_attributes (layout, attrs); pango_attr_list_unref (attrs); return layout; }
PangoLayout* dia_font_build_layout(const char* string, DiaFont* font, real height) { PangoLayout* layout; PangoAttrList* list; PangoAttribute* attr; guint length; PangoFontDescription *pfd; real factor; layout = pango_layout_new(dia_font_get_context()); length = string ? strlen(string) : 0; pango_layout_set_text(layout, string, length); list = pango_attr_list_new(); pfd = pango_font_description_copy (font->pfd); /* account for difference between size and height as well as between font height and given one */ factor = dia_font_get_size(font) / dia_font_get_height (font); pango_font_description_set_absolute_size (pfd, dcm_to_pdu (height) * factor); attr = pango_attr_font_desc_new(pfd); pango_font_description_free (pfd); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert(list,attr); /* eats attr */ pango_layout_set_attributes(layout,list); pango_attr_list_unref(list); pango_layout_set_indent(layout,0); pango_layout_set_justify(layout,FALSE); pango_layout_set_alignment(layout,PANGO_ALIGN_LEFT); return layout; }
void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h) { int max_w; IgtkFont* gtkfont = gtkFontGet(ih); if (!gtkfont) { if (w) *w = 0; if (h) *h = 0; return; } if (!str) { if (w) *w = 0; if (h) *h = gtkfont->charheight * 1; return; } max_w = 0; if (str[0]) { int dummy_h; pango_layout_set_attributes(gtkfont->layout, NULL); if (iupAttribGetBoolean(ih, "MARKUP")) pango_layout_set_markup(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1); else pango_layout_set_text(gtkfont->layout, iupgtkStrConvertToUTF8(str), -1); pango_layout_get_pixel_size(gtkfont->layout, &max_w, &dummy_h); } if (w) *w = max_w; if (h) *h = gtkfont->charheight * iupStrLineCount(str); }
// Although we don't use this function yet, but we must create it here. // first, for the prepare the unicode drawing support in wxUniv/x11 port. // If we use pango to draw the text, then we must set some attributes // for pango layout, such as "strikethrough" and "underline". bool wxFont::SetPangoAttrs(PangoLayout* layout) const { if ( !IsOk() || !(GetUnderlined() || GetStrikethrough()) ) return false; PangoAttrList* attrs = pango_attr_list_new(); PangoAttribute* a; if ( GetUnderlined() ) { a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); pango_attr_list_insert(attrs, a); } if ( GetStrikethrough() ) { a = pango_attr_strikethrough_new(true); pango_attr_list_insert(attrs, a); } pango_layout_set_attributes(layout, attrs); pango_attr_list_unref(attrs); return true; }
static void marlin_text_renderer_render (GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) { MarlinTextRenderer *text_renderer = MARLIN_TEXT_RENDERER (cell); GtkStyleContext *context; GtkStateFlags state; gint x0, x1, y0, y1; gint text_width; gint text_height; gint x_offset; gint y_offset; gint xpad, ypad; gfloat xalign, yalign; gboolean selected; /* setup the new widget */ marlin_text_renderer_set_widget (text_renderer, widget); state = gtk_widget_get_state_flags (widget); if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) { state |= GTK_STATE_FLAG_SELECTED; } else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT && gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT) { state = GTK_STATE_PRELIGHT; } else { state = gtk_widget_get_sensitive (widget) ? GTK_STATE_FLAG_NORMAL : GTK_STATE_INSENSITIVE; } /* render small/normal text depending on the zoom_level */ if (text_renderer->zoom_level < MARLIN_ZOOM_LEVEL_NORMAL) { if (text_renderer->follow_prelit && (flags & GTK_CELL_RENDERER_PRELIT) != 0) pango_layout_set_attributes (text_renderer->layout, eel_pango_attr_list_small_underline_single ()); else pango_layout_set_attributes (text_renderer->layout, eel_pango_attr_list_small ()); } else { if (text_renderer->follow_prelit && (flags & GTK_CELL_RENDERER_PRELIT) != 0) pango_layout_set_attributes (text_renderer->layout, eel_pango_attr_list_underline_single ()); else pango_layout_set_attributes (text_renderer->layout, NULL); } /* setup the wrapping */ if (text_renderer->wrap_width < 0) { pango_layout_set_width (text_renderer->layout, -1); pango_layout_set_wrap (text_renderer->layout, PANGO_WRAP_CHAR); } else { pango_layout_set_width (text_renderer->layout, text_renderer->wrap_width * PANGO_SCALE); pango_layout_set_wrap (text_renderer->layout, text_renderer->wrap_mode); } /* ellipsize to max lines except for selected or prelit items */ pango_layout_set_ellipsize (text_renderer->layout, PANGO_ELLIPSIZE_END); pango_layout_set_height (text_renderer->layout, -3); if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED || (flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT) { pango_layout_set_ellipsize (text_renderer->layout, PANGO_ELLIPSIZE_NONE); } gtk_cell_renderer_get_alignment (cell, &xalign, &yalign); if (xalign == 0.5f) pango_layout_set_alignment (text_renderer->layout, PANGO_ALIGN_CENTER); pango_layout_set_text (text_renderer->layout, text_renderer->text, -1); /* calculate the real text dimension */ pango_layout_get_pixel_size (text_renderer->layout, &text_width, &text_height); /* take into account the state indicator (required for calculation) */ if (text_renderer->follow_state) { text_width += 2 * text_renderer->focus_width; text_height += 2 * text_renderer->focus_width; } gtk_cell_renderer_get_padding (cell, &xpad, &ypad); /* calculate the real x-offset */ x_offset = ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ? (1.0 - xalign) : xalign) * (cell_area->width - text_width - (2 * xpad)); x_offset = MAX (x_offset, 0); /* calculate the real y-offset */ y_offset = yalign * (cell_area->height - text_height - (2 * ypad)); y_offset = MAX (y_offset, 0); context = gtk_widget_get_style_context (gtk_widget_get_parent (widget)); gtk_style_context_save (context); gtk_style_context_set_state (context, state); selected = ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED && text_renderer->follow_state); /* render the state indicator */ if (selected || text_renderer->background != NULL) { /* calculate the text bounding box (including the focus padding/width) */ x0 = cell_area->x + x_offset; y0 = cell_area->y + y_offset; x1 = x0 + text_width; y1 = y0 + text_height; cairo_move_to (cr, x0 + 5, y0); cairo_line_to (cr, x1 - 5, y0); cairo_curve_to (cr, x1 - 5, y0, x1, y0, x1, y0 + 5); cairo_line_to (cr, x1, y1 - 5); cairo_curve_to (cr, x1, y1 - 5, x1, y1, x1 - 5, y1); cairo_line_to (cr, x0 + 5, y1); cairo_curve_to (cr, x0 + 5, y1, x0, y1, x0, y1 - 5); cairo_line_to (cr, x0, y0 + 5); cairo_curve_to (cr, x0, y0 + 5, x0, y0, x0 + 5, y0); GdkRGBA color; if(text_renderer->background != NULL && !selected) { if(!gdk_rgba_parse(&color, text_renderer->background)) { g_critical("Can't parse this color value: %s", text_renderer->background); gtk_style_context_get_background_color (context, state, &color); } } else { gtk_style_context_get_background_color (context, state, &color); } gdk_cairo_set_source_rgba (cr, &color); cairo_fill (cr); } /* draw the focus indicator */ if (text_renderer->follow_state && (flags & GTK_CELL_RENDERER_FOCUSED) != 0) { gtk_render_focus (context, cr, cell_area->x + x_offset, cell_area->y + y_offset, text_width, text_height); } /* get proper sizing for the layout drawing */ if (text_renderer->follow_state) { text_width -= 2 * text_renderer->focus_width; text_height -= 2 * text_renderer->focus_width; x_offset += text_renderer->focus_width; y_offset += text_renderer->focus_width; } /* draw the text */ if (xalign == 0.5f) x_offset = (cell_area->width - text_renderer->wrap_width)/2; gtk_render_layout (context, cr, cell_area->x + x_offset + xpad, cell_area->y + y_offset + ypad, text_renderer->layout); gtk_style_context_restore (context); }
unsigned Gosu::pango::textWidth(const std::wstring& text, const std::wstring& fontFace, unsigned fontHeight, unsigned fontFlags) { g_type_init(); int dpi_x = 100, dpi_y = 100; context = pango_ft2_get_context(dpi_x, dpi_y); pango_context_set_language(context, pango_language_from_string ("en_US")); PangoDirection init_dir = PANGO_DIRECTION_LTR; pango_context_set_base_dir(context, init_dir); // static PangoFontDescription *font_description; font_description = pango_font_description_new(); pango_font_description_set_family(font_description, g_strdup(narrow(fontFace).c_str())); pango_font_description_set_style(font_description, (fontFlags & ffItalic) ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); pango_font_description_set_variant(font_description, PANGO_VARIANT_NORMAL); pango_font_description_set_weight(font_description, (fontFlags & ffBold) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); pango_font_description_set_stretch(font_description, PANGO_STRETCH_NORMAL); int init_scale = int(fontHeight/2.0 + 0.5); pango_font_description_set_size(font_description, init_scale * PANGO_SCALE); pango_context_set_font_description(context, font_description); layout = pango_layout_new(context); if(fontFlags & ffUnderline) { // PangoAttribute *attr; attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr->start_index = 0; attr->end_index = text.length(); // PangoAttrList* attrList; attrList = pango_attr_list_new(); pango_attr_list_insert(attrList, attr); pango_layout_set_attributes(layout, attrList); pango_attr_list_unref(attrList); } // IMPR: Catch errors? (Last NULL-Pointer) gchar* utf8Str = g_ucs4_to_utf8((gunichar*)text.c_str(), text.length(), NULL, NULL, NULL); pango_layout_set_text(layout, utf8Str, -1); g_free(utf8Str); PangoDirection base_dir = pango_context_get_base_dir(context); pango_layout_set_alignment(layout, base_dir == PANGO_DIRECTION_LTR ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); pango_layout_set_width(layout, -1); PangoRectangle logical_rect; pango_layout_get_pixel_extents(layout, NULL, &logical_rect); height = logical_rect.height; width = logical_rect.width; return width; }
bool wxFont::GTKSetPangoAttrs(PangoLayout* layout) const { if (!IsOk() || !(GetUnderlined() || GetStrikethrough())) return false; PangoAttrList* attrs = pango_attr_list_new(); PangoAttribute* a; if (wx_pango_version_check(1,16,0)) { // a PangoLayout which has leading/trailing spaces with underlined font // is not correctly drawn by this pango version: Pango won't underline the spaces. // This can be a problem; e.g. wxHTML rendering of underlined text relies on // this behaviour. To workaround this problem, we use a special hack here // suggested by pango maintainer Behdad Esfahbod: we prepend and append two // empty space characters and give them a dummy colour attribute. // This will force Pango to underline the leading/trailing spaces, too. const char* text = pango_layout_get_text(layout); const size_t n = strlen(text); if ((n > 0 && text[0] == ' ') || (n > 1 && text[n - 1] == ' ')) { wxCharBuffer buf(n + 6); // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format memcpy(buf.data(), "\342\200\214", 3); // copy the user string memcpy(buf.data() + 3, text, n); // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format memcpy(buf.data() + 3 + n, "\342\200\214", 3); pango_layout_set_text(layout, buf, n + 6); // Add dummy attributes (use colour as it's invisible anyhow for 0 // width spaces) to ensure that the spaces in the beginning/end of the // string are underlined too. a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614); a->start_index = 0; a->end_index = 3; pango_attr_list_insert(attrs, a); a = pango_attr_foreground_new(0x0057, 0x52A9, 0xD614); a->start_index = n + 3; a->end_index = n + 6; pango_attr_list_insert(attrs, a); } } if (GetUnderlined()) { a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); pango_attr_list_insert(attrs, a); } if (GetStrikethrough()) { a = pango_attr_strikethrough_new(true); pango_attr_list_insert(attrs, a); } pango_layout_set_attributes(layout, attrs); pango_attr_list_unref(attrs); return true; }
void textbox_set_pango_attributes ( textbox *tb, PangoAttrList *list ) { pango_layout_set_attributes ( tb->layout, list ); }
static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data) { DocInfo *dinfo = user_data; GeanyEditor *editor; cairo_t *cr; gdouble width, height; gdouble x = 0.0, y = 0.0; /*gint layout_h;*/ gint count; GString *str; if (dinfo == NULL || page_nr >= dinfo->n_pages) return; editor = dinfo->doc->editor; if (dinfo->n_pages > 0) { gdouble fraction = (page_nr + 1) / (gdouble) dinfo->n_pages; gchar *text = g_strdup_printf(_("Page %d of %d"), page_nr, dinfo->n_pages); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_widgets.progressbar), fraction); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets.progressbar), text); g_free(text); } #ifdef GEANY_PRINT_DEBUG geany_debug("draw_page = %d, pages = %d, (real) lines_per_page = %d", page_nr, dinfo->n_pages, dinfo->lines_per_page); #endif str = g_string_sized_new(256); cr = gtk_print_context_get_cairo_context(context); width = gtk_print_context_get_width(context); height = gtk_print_context_get_height(context); cairo_set_source_rgb(cr, 0, 0, 0); #ifdef GEANY_PRINT_DEBUG cairo_set_line_width(cr, 0.2); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_move_to(cr, 0, 0); pango_layout_set_width(dinfo->layout, width * PANGO_SCALE); pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_LEFT); pango_layout_set_ellipsize(dinfo->layout, FALSE); pango_layout_set_justify(dinfo->layout, FALSE); if (printing_prefs.print_page_header) add_page_header(dinfo, cr, width, page_nr); count = 0; /* the actual line counter for the current page, might be different from * dinfo->cur_line due to possible line breaks */ while (count < dinfo->lines_per_page) { gchar c = 'a'; gint style = -1; PangoAttrList *layout_attr; PangoAttribute *attr; gint colours[3] = { 0 }; gboolean add_linenumber = TRUE; gboolean at_eol; while (count < dinfo->lines_per_page && c != '\0') { at_eol = FALSE; g_string_erase(str, 0, str->len); /* clear the string */ /* line numbers */ if (printing_prefs.print_line_numbers && add_linenumber) { /* if we had a wrapped line on the last page which needs to be continued, don't * add a line number */ if (dinfo->long_line) { add_linenumber = FALSE; } else { gchar *line_number = NULL; gint cur_line_number_margin = get_line_numbers_arity(dinfo->cur_line + 1); gchar *fill = g_strnfill( dinfo->max_line_number_margin - cur_line_number_margin - 1, ' '); line_number = g_strdup_printf("%s%d ", fill, dinfo->cur_line + 1); g_string_append(str, line_number); dinfo->cur_line++; /* increase document line */ add_linenumber = FALSE; style = STYLE_LINENUMBER; c = 'a'; /* dummy value */ g_free(fill); g_free(line_number); } } /* data */ else { style = sci_get_style_at(dinfo->doc->editor->sci, dinfo->cur_pos); c = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); if (c == '\0' || style == -1) { /* if c gets 0, we are probably out of document boundaries, * so stop to break out of outer loop */ count = dinfo->lines_per_page; break; } dinfo->cur_pos++; /* convert tabs to spaces which seems to be better than using Pango tabs */ if (c == '\t') { gint tab_width = sci_get_tab_width(editor->sci); gchar *s = g_strnfill(tab_width, ' '); g_string_append(str, s); g_free(s); } /* don't add line breaks, they are handled manually below */ else if (c == '\r' || c == '\n') { gchar c_next = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); at_eol = TRUE; if (c == '\r' && c_next == '\n') dinfo->cur_pos++; /* skip LF part of CR/LF */ } else { g_string_append_c(str, c); /* finally add the character */ /* handle UTF-8: since we add char by char (better: byte by byte), we need to * keep UTF-8 characters together(e.g. two bytes for one character) * the input is always UTF-8 and c is signed, so all non-Ascii * characters are less than 0 and consist of all bytes less than 0. * style doesn't change since it is only one character with multiple bytes. */ while (c < 0) { c = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); if (c < 0) { /* only add the byte when it is part of the UTF-8 character * otherwise we could add e.g. a '\n' and it won't be visible in the * printed document */ g_string_append_c(str, c); dinfo->cur_pos++; } } } } if (! at_eol) { /* set text */ pango_layout_set_text(dinfo->layout, str->str, -1); /* attributes */ layout_attr = pango_attr_list_new(); /* foreground colour */ get_rgb_values(dinfo->styles[style][FORE], &colours[0], &colours[1], &colours[2]); attr = pango_attr_foreground_new(colours[0], colours[1], colours[2]); ADD_ATTR(layout_attr, attr); /* background colour */ get_rgb_values(dinfo->styles[style][BACK], &colours[0], &colours[1], &colours[2]); attr = pango_attr_background_new(colours[0], colours[1], colours[2]); ADD_ATTR(layout_attr, attr); /* bold text */ if (dinfo->styles[style][BOLD]) { attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); ADD_ATTR(layout_attr, attr); } /* italic text */ if (dinfo->styles[style][ITALIC]) { attr = pango_attr_style_new(PANGO_STYLE_ITALIC); ADD_ATTR(layout_attr, attr); } pango_layout_set_attributes(dinfo->layout, layout_attr); pango_layout_context_changed(dinfo->layout); pango_attr_list_unref(layout_attr); } cairo_get_current_point(cr, &x, &y); /* normal line break at eol character in document */ if (at_eol) { /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/ /*cairo_move_to(cr, 0, y + (gdouble)layout_h / PANGO_SCALE);*/ cairo_move_to(cr, 0, y + dinfo->line_height); count++; /* we added a new document line so request a new line number */ add_linenumber = TRUE; } else { gint x_offset = 0; /* maybe we need to force a line break because of too long line */ if (x >= (width - dinfo->font_width)) { /* don't start the line at horizontal origin because we need to skip the * line number margin */ if (printing_prefs.print_line_numbers) { x_offset = (dinfo->max_line_number_margin + 1) * dinfo->font_width; } /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/ /*cairo_move_to(cr, x_offset, y + (gdouble)layout_h / PANGO_SCALE);*/ /* this is faster but not exactly the same as above */ cairo_move_to(cr, x_offset, y + dinfo->line_height); cairo_get_current_point(cr, &x, &y); count++; } if (count < dinfo->lines_per_page) { /* str->len is counted in bytes not characters, so use g_utf8_strlen() */ x_offset = (g_utf8_strlen(str->str, -1) * dinfo->font_width); if (dinfo->long_line && count == 0) { x_offset = (dinfo->max_line_number_margin + 1) * dinfo->font_width; dinfo->long_line = FALSE; } pango_cairo_show_layout(cr, dinfo->layout); cairo_move_to(cr, x + x_offset, y); } else /* we are on a wrapped line but we are out of lines on this page, so continue * the current line on the next page and remember to continue in current line */ dinfo->long_line = TRUE; } } } if (printing_prefs.print_line_numbers) { /* print a thin line between the line number margin and the data */ gint y_start = 0; if (printing_prefs.print_page_header) y_start = (dinfo->line_height * 3) - 2; /* "- 2": to connect the line number line to * the page header frame */ cairo_set_line_width(cr, 0.3); cairo_move_to(cr, (dinfo->max_line_number_margin * dinfo->font_width) + 1, y_start); cairo_line_to(cr, (dinfo->max_line_number_margin * dinfo->font_width) + 1, y + dinfo->line_height); /* y is last added line, we reuse it */ cairo_stroke(cr); } if (printing_prefs.print_page_numbers) { gchar *line = g_strdup_printf("<small>- %d -</small>", page_nr + 1); pango_layout_set_markup(dinfo->layout, line, -1); pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_CENTER); cairo_move_to(cr, 0, height - dinfo->line_height); pango_cairo_show_layout(cr, dinfo->layout); g_free(line); #ifdef GEANY_PRINT_DEBUG cairo_set_line_width(cr, 0.3); cairo_move_to(cr, 0, height - (1.25 * dinfo->line_height)); cairo_line_to(cr, width - 1, height - (1.25 * dinfo->line_height)); cairo_stroke(cr); #endif } g_string_free(str, TRUE); }
static gboolean gimp_tag_popup_list_expose (GtkWidget *widget, GdkEventExpose *event, GimpTagPopup *popup) { GdkWindow *window = gtk_widget_get_window (widget); GtkStyle *style = gtk_widget_get_style (widget); cairo_t *cr; PangoAttribute *attribute; PangoAttrList *attributes; gint i; cr = gdk_cairo_create (event->window); gdk_cairo_region (cr, event->region); cairo_clip (cr); cairo_set_line_width (cr, 1.0); cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); for (i = 0; i < popup->tag_count; i++) { PopupTagData *tag_data = &popup->tag_data[i]; pango_layout_set_text (popup->layout, gimp_tag_get_name (tag_data->tag), -1); switch (tag_data->state) { case GTK_STATE_SELECTED: attributes = pango_attr_list_copy (popup->combo_entry->selected_item_attr); break; case GTK_STATE_INSENSITIVE: attributes = pango_attr_list_copy (popup->combo_entry->insensitive_item_attr); break; default: attributes = pango_attr_list_copy (popup->combo_entry->normal_item_attr); break; } if (tag_data == popup->prelight && tag_data->state != GTK_STATE_INSENSITIVE) { attribute = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); pango_attr_list_insert (attributes, attribute); } pango_layout_set_attributes (popup->layout, attributes); pango_attr_list_unref (attributes); if (tag_data->state == GTK_STATE_SELECTED) { gdk_cairo_set_source_color (cr, &popup->combo_entry->selected_item_color); cairo_rectangle (cr, tag_data->bounds.x - 1, tag_data->bounds.y - popup->scroll_y, tag_data->bounds.width + 2, tag_data->bounds.height); cairo_fill (cr); cairo_translate (cr, 0.5, 0.5); cairo_move_to (cr, tag_data->bounds.x, tag_data->bounds.y - popup->scroll_y - 1); cairo_line_to (cr, tag_data->bounds.x + tag_data->bounds.width - 1, tag_data->bounds.y - popup->scroll_y - 1); cairo_move_to (cr, tag_data->bounds.x, tag_data->bounds.y - popup->scroll_y + tag_data->bounds.height); cairo_line_to (cr, tag_data->bounds.x + tag_data->bounds.width - 1, tag_data->bounds.y - popup->scroll_y + tag_data->bounds.height); cairo_stroke (cr); cairo_translate (cr, -0.5, -0.5); } cairo_move_to (cr, (tag_data->bounds.x + GIMP_TAG_POPUP_PADDING), (tag_data->bounds.y - popup->scroll_y + GIMP_TAG_POPUP_PADDING)); pango_cairo_show_layout (cr, popup->layout); if (tag_data == popup->prelight && tag_data->state != GTK_STATE_INSENSITIVE && ! popup->single_select_disabled) { gtk_paint_focus (style, window, tag_data->state, &event->area, widget, NULL, tag_data->bounds.x, tag_data->bounds.y - popup->scroll_y, tag_data->bounds.width, tag_data->bounds.height); } } cairo_destroy (cr); return FALSE; }
static gint line_numbers_expose (GtkWidget *widget, GdkEventExpose *event) { GtkTextView *text_view; GdkWindow *win; // GtkStyle *style; PangoLayout *layout; PangoAttrList *alist; PangoAttribute *attr; GArray *numbers; GArray *pixels; gint y1, y2; gint count; gint layout_width; gint justify_width = 0; gint i; // gchar *str; gchar str [8]; /* we don't expect more than ten million lines */ GdkGC *gc; gint height; if (line_number_visible){{{{{ // omit calculation text_view = GTK_TEXT_VIEW (widget); /* See if this expose is on the line numbers window */ /* left_win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT); right_win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_RIGHT); if (event->window == left_win) { type = GTK_TEXT_WINDOW_LEFT; target = event->window; } else if (event->window == right_win) { type = GTK_TEXT_WINDOW_RIGHT; target = right_win; } else return FALSE; */ win = gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_LEFT); if (event->window != win) return FALSE; // style = gtk_style_copy (widget->style); // style = gtk_style_copy (gtk_widget_get_default_style()); y1 = event->area.y; y2 = y1 + event->area.height; gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y1, NULL, &y1); gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, y2, NULL, &y2); numbers = g_array_new (FALSE, FALSE, sizeof (gint)); pixels = g_array_new (FALSE, FALSE, sizeof (gint)); get_lines (text_view, y1, y2, pixels, numbers, &count); /* a zero-lined document should display a "1"; we don't need to worry about scrolling effects of the text widget in this special case */ if (count == 0) { gint y = 0; gint n = 0; count = 1; g_array_append_val (pixels, y); g_array_append_val (numbers, n); } DV({g_print("Painting line numbers %d - %d\n", g_array_index(numbers, gint, 0), g_array_index(numbers, gint, count - 1)); }); layout = gtk_widget_create_pango_layout (widget, ""); // str = g_strdup_printf ("%d", gtk_text_buffer_get_line_count(text_view->buffer)); g_snprintf (str, sizeof (str), "%d", MAX (99, gtk_text_buffer_get_line_count(text_view->buffer))); pango_layout_set_text (layout, str, -1); // g_free (str); pango_layout_get_pixel_size (layout, &layout_width, NULL); min_number_window_width = calculate_min_number_window_width(widget); if (layout_width > min_number_window_width) gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, layout_width + margin + submargin); else { // if ((gtk_text_view_get_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT) - 5) > layout_width) { gtk_text_view_set_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT, min_number_window_width + margin + submargin); // } justify_width = min_number_window_width - layout_width; } pango_layout_set_width (layout, layout_width); pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); alist = pango_attr_list_new(); attr = pango_attr_foreground_new( widget->style->text_aa->red, widget->style->text_aa->green, widget->style->text_aa->blue); attr->start_index = 0; attr->end_index = G_MAXUINT; pango_attr_list_insert(alist, attr); pango_layout_set_attributes(layout, alist); pango_attr_list_unref(alist); /* Draw fully internationalized numbers! */ i = 0; while (i < count) { gint pos; gtk_text_view_buffer_to_window_coords (text_view, GTK_TEXT_WINDOW_LEFT, 0, g_array_index (pixels, gint, i), NULL, &pos); // str = g_strdup_printf ("%d", g_array_index (numbers, gint, i) + 1); g_snprintf (str, sizeof (str), "%d", g_array_index (numbers, gint, i) + 1); pango_layout_set_text (layout, str, -1); gtk_paint_layout (widget->style, win, GTK_WIDGET_STATE (widget), FALSE, NULL, widget, NULL, #if GTK_CHECK_VERSION(2, 6, 0) // Is this solution??? layout_width + justify_width + margin / 2 + 1, #else layout_width + justify_width + margin / 2, #endif pos, layout); // g_free (str); ++i; } g_array_free (pixels, TRUE); g_array_free (numbers, TRUE); g_object_unref (G_OBJECT (layout)); // g_object_ref (G_OBJECT (style)); /* don't stop emission, need to draw children */ }}}}}
void GuiSolidLabelElementRenderer::OnElementStateChanged() { FontProperties font = element->GetFont(); Color color = element->GetColor(); int layoutWidth, layoutHeight; AString family = wtoa(font.fontFamily); pango_font_description_set_family(pangoFontDesc, family.Buffer()); pango_font_description_set_absolute_size(pangoFontDesc, font.size * PANGO_SCALE); if(font.italic) pango_font_description_set_style(pangoFontDesc, PANGO_STYLE_ITALIC); else pango_font_description_set_style(pangoFontDesc, PANGO_STYLE_NORMAL); if(attrList) { pango_attr_list_unref(attrList); } attrList = pango_attr_list_new(); pango_attr_list_insert(attrList, pango_attr_underline_new( font.underline ? PANGO_UNDERLINE_SINGLE : PANGO_UNDERLINE_NONE) ); pango_attr_list_insert(attrList, pango_attr_strikethrough_new ( font.strikeline ? TRUE : FALSE ) ); pango_attr_list_insert(attrList, pango_attr_weight_new ( font.bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_MEDIUM ) ); if(layout) { g_object_unref(layout); layout = NULL; } if(cairoContext) { layout = pango_cairo_create_layout(cairoContext); WString wtext = (font.fontFamily == L"Webdings") ? helpers::WebdingsMap(element->GetText()) : element->GetText(); AString text = wtoa(wtext); pango_layout_set_font_description(layout, pangoFontDesc); pango_layout_set_attributes(layout, attrList); pango_layout_set_text(layout, text.Buffer(), text.Length()); pango_layout_set_alignment(layout, element->GetHorizontalAlignment() == Alignment::Left ? PANGO_ALIGN_LEFT : element->GetHorizontalAlignment() == Alignment::Center ? PANGO_ALIGN_CENTER : element->GetHorizontalAlignment() == Alignment::Right ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_LEFT ); pango_cairo_update_layout(cairoContext, layout); pango_layout_get_pixel_size( layout, &layoutWidth, &layoutHeight); minSize.x = layoutWidth; minSize.y = layoutHeight; } }
static PangoLayout * rsvg_text_create_layout (RsvgDrawingCtx * ctx, RsvgState * state, const char *text, PangoContext * context) { PangoFontDescription *font_desc; PangoLayout *layout; PangoAttrList *attr_list; PangoAttribute *attribute; if (state->lang) pango_context_set_language (context, pango_language_from_string (state->lang)); if (state->unicode_bidi == UNICODE_BIDI_OVERRIDE || state->unicode_bidi == UNICODE_BIDI_EMBED) pango_context_set_base_dir (context, state->text_dir); font_desc = pango_font_description_copy (pango_context_get_font_description (context)); if (state->font_family) pango_font_description_set_family_static (font_desc, state->font_family); pango_font_description_set_style (font_desc, state->font_style); pango_font_description_set_variant (font_desc, state->font_variant); pango_font_description_set_weight (font_desc, state->font_weight); pango_font_description_set_stretch (font_desc, state->font_stretch); pango_font_description_set_size (font_desc, _rsvg_css_normalize_font_size (state, ctx) * PANGO_SCALE / ctx->dpi_y * 72); layout = pango_layout_new (context); pango_layout_set_font_description (layout, font_desc); pango_font_description_free (font_desc); attr_list = pango_attr_list_new (); attribute = pango_attr_letter_spacing_new (_rsvg_css_normalize_length (&state->letter_spacing, ctx, 'h') * PANGO_SCALE); attribute->start_index = 0; attribute->end_index = G_MAXINT; pango_attr_list_insert (attr_list, attribute); if (state->has_font_decor && text) { if (state->font_decor & TEXT_UNDERLINE) { attribute = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); attribute->start_index = 0; attribute->end_index = -1; pango_attr_list_insert (attr_list, attribute); } if (state->font_decor & TEXT_STRIKE) { attribute = pango_attr_strikethrough_new (TRUE); attribute->start_index = 0; attribute->end_index = -1; pango_attr_list_insert (attr_list, attribute); } } pango_layout_set_attributes (layout, attr_list); pango_attr_list_unref (attr_list); if (text) pango_layout_set_text (layout, text, -1); else pango_layout_set_text (layout, NULL, 0); pango_layout_set_alignment (layout, (state->text_dir == PANGO_DIRECTION_LTR || state->text_dir == PANGO_DIRECTION_TTB_LTR) ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT); return layout; }
static void marlin_text_renderer_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MarlinTextRenderer *text_renderer = MARLIN_TEXT_RENDERER (object); const gchar *sval; switch (prop_id) { case PROP_FOLLOW_PRELIT: text_renderer->follow_prelit = g_value_get_boolean (value); break; case PROP_FOLLOW_STATE: text_renderer->follow_state = g_value_get_boolean (value); break; case PROP_TEXT: /* release the previous text (if not static) */ if (!text_renderer->text_static) g_free (text_renderer->text); sval = g_value_get_string (value); text_renderer->text_static = (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS); text_renderer->text = (sval == NULL) ? "" : (gchar *)sval; if (!text_renderer->text_static) text_renderer->text = g_strdup (text_renderer->text); break; case PROP_BACKGROUND: g_free (text_renderer->background); sval = g_value_get_string (value); text_renderer->background = g_strdup (sval); break; case PROP_ZOOM_LEVEL: text_renderer->zoom_level = g_value_get_enum (value); if (text_renderer->layout != NULL) { if (text_renderer->zoom_level < MARLIN_ZOOM_LEVEL_NORMAL) pango_layout_set_attributes (text_renderer->layout, eel_pango_attr_list_small ()); else pango_layout_set_attributes (text_renderer->layout, NULL); } break; case PROP_WRAP_MODE: text_renderer->wrap_mode = g_value_get_enum (value); break; case PROP_WRAP_WIDTH: /* be sure to reset fixed height if wrapping is requested */ text_renderer->wrap_width = g_value_get_int (value); if (G_LIKELY (text_renderer->wrap_width >= 0)) gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (text_renderer), -1, -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void thunar_text_renderer_render (GtkCellRenderer *renderer, GdkWindow *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) { ThunarTextRenderer *text_renderer = THUNAR_TEXT_RENDERER (renderer); GtkStateType state; #if !GTK_CHECK_VERSION(2,8,0) GdkPoint points[8]; #else cairo_t *cr; #endif gint x0, x1, y0, y1; gint text_width; gint text_height; gint x_offset; gint y_offset; /* setup the new widget */ thunar_text_renderer_set_widget (text_renderer, widget); if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) { if (GTK_WIDGET_HAS_FOCUS (widget)) state = GTK_STATE_SELECTED; else state = GTK_STATE_ACTIVE; } else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT && GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) { state = GTK_STATE_PRELIGHT; } else { if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE) state = GTK_STATE_INSENSITIVE; else state = GTK_STATE_NORMAL; } /* check if we should follow the prelit state (used for single click support) */ if (text_renderer->follow_prelit && (flags & GTK_CELL_RENDERER_PRELIT) != 0) pango_layout_set_attributes (text_renderer->layout, thunar_pango_attr_list_underline_single ()); else pango_layout_set_attributes (text_renderer->layout, NULL); /* setup the wrapping */ if (text_renderer->wrap_width < 0) { pango_layout_set_width (text_renderer->layout, -1); pango_layout_set_wrap (text_renderer->layout, PANGO_WRAP_CHAR); } else { pango_layout_set_width (text_renderer->layout, text_renderer->wrap_width * PANGO_SCALE); pango_layout_set_wrap (text_renderer->layout, text_renderer->wrap_mode); } pango_layout_set_text (text_renderer->layout, text_renderer->text, -1); /* calculate the real text dimension */ pango_layout_get_pixel_size (text_renderer->layout, &text_width, &text_height); /* take into account the state indicator (required for calculation) */ if (text_renderer->follow_state) { text_width += 2 * text_renderer->focus_width; text_height += 2 * text_renderer->focus_width; } /* calculate the real x-offset */ x_offset = ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ? (1.0 - renderer->xalign) : renderer->xalign) * (cell_area->width - text_width - (2 * renderer->xpad)); x_offset = MAX (x_offset, 0); /* calculate the real y-offset */ y_offset = renderer->yalign * (cell_area->height - text_height - (2 * renderer->ypad)); y_offset = MAX (y_offset, 0); /* render the state indicator */ if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED && text_renderer->follow_state) { /* calculate the text bounding box (including the focus padding/width) */ x0 = cell_area->x + x_offset; y0 = cell_area->y + y_offset; x1 = x0 + text_width; y1 = y0 + text_height; #if GTK_CHECK_VERSION(2,8,0) /* Cairo produces nicer results than using a polygon * and so we use it directly if possible. */ cr = gdk_cairo_create (window); cairo_move_to (cr, x0 + 5, y0); cairo_line_to (cr, x1 - 5, y0); cairo_curve_to (cr, x1 - 5, y0, x1, y0, x1, y0 + 5); cairo_line_to (cr, x1, y1 - 5); cairo_curve_to (cr, x1, y1 - 5, x1, y1, x1 - 5, y1); cairo_line_to (cr, x0 + 5, y1); cairo_curve_to (cr, x0 + 5, y1, x0, y1, x0, y1 - 5); cairo_line_to (cr, x0, y0 + 5); cairo_curve_to (cr, x0, y0 + 5, x0, y0, x0 + 5, y0); gdk_cairo_set_source_color (cr, &widget->style->base[state]); cairo_fill (cr); cairo_destroy (cr); #else /* calculate a (more or less rounded) polygon */ points[0].x = x0 + 2; points[0].y = y0; points[1].x = x1 - 2; points[1].y = y0; points[2].x = x1; points[2].y = y0 + 2; points[3].x = x1; points[3].y = y1 - 2; points[4].x = x1 - 2; points[4].y = y1; points[5].x = x0 + 2; points[5].y = y1; points[6].x = x0; points[6].y = y1 - 2; points[7].x = x0; points[7].y = y0 + 2; /* render the indicator */ gdk_draw_polygon (window, widget->style->base_gc[state], TRUE, points, G_N_ELEMENTS (points)); #endif } /* draw the focus indicator */ if (text_renderer->follow_state && (flags & GTK_CELL_RENDERER_FOCUSED) != 0) { gtk_paint_focus (widget->style, window, GTK_WIDGET_STATE (widget), NULL, widget, "icon_view", cell_area->x + x_offset, cell_area->y + y_offset, text_width, text_height); } /* get proper sizing for the layout drawing */ if (text_renderer->follow_state) { text_width -= 2 * text_renderer->focus_width; text_height -= 2 * text_renderer->focus_width; x_offset += text_renderer->focus_width; y_offset += text_renderer->focus_width; } /* draw the text */ gtk_paint_layout (widget->style, window, state, TRUE, expose_area, widget, "cellrenderertext", cell_area->x + x_offset + renderer->xpad, cell_area->y + y_offset + renderer->ypad, text_renderer->layout); }
static void rotated_text_draw (GtkDrawingArea *da, cairo_t *cr, int width, int height, gpointer data) { #define RADIUS 150 #define N_WORDS 5 #define FONT "Serif 18" PangoContext *context; PangoLayout *layout; PangoFontDescription *desc; cairo_pattern_t *pattern; PangoAttrList *attrs; double device_radius; int i; /* Create a cairo context and set up a transformation matrix so that the user * space coordinates for the centered square where we draw are [-RADIUS, RADIUS], * [-RADIUS, RADIUS]. * We first center, then change the scale. */ device_radius = MIN (width, height) / 2.; cairo_translate (cr, device_radius + (width - 2 * device_radius) / 2, device_radius + (height - 2 * device_radius) / 2); cairo_scale (cr, device_radius / RADIUS, device_radius / RADIUS); /* Create and a subtle gradient source and use it. */ pattern = cairo_pattern_create_linear (-RADIUS, -RADIUS, RADIUS, RADIUS); cairo_pattern_add_color_stop_rgb (pattern, 0., .5, .0, .0); cairo_pattern_add_color_stop_rgb (pattern, 1., .0, .0, .5); cairo_set_source (cr, pattern); /* Create a PangoContext and set up our shape renderer */ context = gtk_widget_create_pango_context (GTK_WIDGET (da)); pango_cairo_context_set_shape_renderer (context, fancy_shape_renderer, NULL, NULL); /* Create a PangoLayout, set the text, font, and attributes */ layout = pango_layout_new (context); pango_layout_set_text (layout, text, -1); desc = pango_font_description_from_string (FONT); pango_layout_set_font_description (layout, desc); attrs = create_fancy_attr_list_for_layout (layout); pango_layout_set_attributes (layout, attrs); pango_attr_list_unref (attrs); /* Draw the layout N_WORDS times in a circle */ for (i = 0; i < N_WORDS; i++) { int width, height; /* Inform Pango to re-layout the text with the new transformation matrix */ pango_cairo_update_layout (cr, layout); pango_layout_get_pixel_size (layout, &width, &height); cairo_move_to (cr, - width / 2, - RADIUS * .9); pango_cairo_show_layout (cr, layout); /* Rotate for the next turn */ cairo_rotate (cr, G_PI*2 / N_WORDS); } /* free the objects we created */ pango_font_description_free (desc); g_object_unref (layout); g_object_unref (context); cairo_pattern_destroy (pattern); }
static gboolean about_dialog_timer (gpointer data) { GimpAboutDialog *dialog = data; gint timeout = 0; if (dialog->animstep == 0) { gchar *text = NULL; dialog->visible = TRUE; switch (dialog->state) { case 0: dialog->timer = g_timeout_add (30, about_dialog_timer, dialog); dialog->state += 1; return FALSE; case 1: text = insert_spacers (_("GIMP is brought to you by")); dialog->state += 1; break; case 2: if (! (dialog->index < dialog->n_authors)) dialog->index = 0; text = insert_spacers (authors[dialog->shuffle[dialog->index]]); dialog->index += 1; break; default: g_return_val_if_reached (TRUE); break; } g_return_val_if_fail (text != NULL, TRUE); pango_layout_set_text (dialog->layout, text, -1); pango_layout_set_attributes (dialog->layout, NULL); g_free (text); } if (dialog->animstep < 16) { decorate_text (dialog, 2, ((gfloat) dialog->animstep) / 15.0); } else if (dialog->animstep == 16) { timeout = 800; } else if (dialog->animstep == 17) { timeout = 30; } else if (dialog->animstep < 33) { decorate_text (dialog, 1, 1.0 - ((gfloat) (dialog->animstep - 17)) / 15.0); } else if (dialog->animstep == 33) { dialog->visible = FALSE; timeout = 300; } else { dialog->visible = FALSE; dialog->animstep = -1; timeout = 30; } dialog->animstep++; gtk_widget_queue_draw (dialog->anim_area); if (timeout > 0) { dialog->timer = g_timeout_add (timeout, about_dialog_timer, dialog); return FALSE; } /* else keep the current timeout */ return TRUE; }
static void decorate_text (GimpAboutDialog *dialog, gint anim_type, gdouble time) { GtkStyle *style = gtk_widget_get_style (dialog->anim_area); const gchar *text; const gchar *ptr; gint letter_count = 0; gint text_length = 0; gint text_bytelen = 0; gint cluster_start, cluster_end; gunichar unichr; PangoAttrList *attrlist = NULL; PangoAttribute *attr; PangoRectangle irect = {0, 0, 0, 0}; PangoRectangle lrect = {0, 0, 0, 0}; GdkColor mix; mix_colors (style->bg + GTK_STATE_NORMAL, style->fg + GTK_STATE_NORMAL, &mix, time); text = pango_layout_get_text (dialog->layout); g_return_if_fail (text != NULL); text_length = g_utf8_strlen (text, -1); text_bytelen = strlen (text); attrlist = pango_attr_list_new (); dialog->textrange[0] = 0; dialog->textrange[1] = text_bytelen; switch (anim_type) { case 0: /* Fade in */ attr = pango_attr_foreground_new (mix.red, mix.green, mix.blue); attr->start_index = 0; attr->end_index = text_bytelen; pango_attr_list_insert (attrlist, attr); break; case 1: /* Fade in, spread */ attr = pango_attr_foreground_new (mix.red, mix.green, mix.blue); attr->start_index = 0; attr->end_index = text_bytelen; pango_attr_list_change (attrlist, attr); ptr = text; cluster_start = 0; while ((unichr = g_utf8_get_char (ptr))) { ptr = g_utf8_next_char (ptr); cluster_end = (ptr - text); if (unichr == 0x200b) { lrect.width = (1.0 - time) * 15.0 * PANGO_SCALE + 0.5; attr = pango_attr_shape_new (&irect, &lrect); attr->start_index = cluster_start; attr->end_index = cluster_end; pango_attr_list_change (attrlist, attr); } cluster_start = cluster_end; } break; case 2: /* Fade in, sinewave */ attr = pango_attr_foreground_new (mix.red, mix.green, mix.blue); attr->start_index = 0; attr->end_index = text_bytelen; pango_attr_list_change (attrlist, attr); ptr = text; cluster_start = 0; while ((unichr = g_utf8_get_char (ptr))) { if (unichr == 0x200b) { cluster_end = ptr - text; attr = pango_attr_rise_new ((1.0 -time) * 18000 * sin (4.0 * time + (float) letter_count * 0.7)); attr->start_index = cluster_start; attr->end_index = cluster_end; pango_attr_list_change (attrlist, attr); letter_count++; cluster_start = cluster_end; } ptr = g_utf8_next_char (ptr); } break; case 3: /* letterwise Fade in */ ptr = text; letter_count = 0; cluster_start = 0; while ((unichr = g_utf8_get_char (ptr))) { gint border = (text_length + 15) * time - 15; gdouble pos; if (letter_count < border) pos = 0; else if (letter_count > border + 15) pos = 1; else pos = ((gdouble) (letter_count - border)) / 15; mix_colors (style->fg + GTK_STATE_NORMAL, style->bg + GTK_STATE_NORMAL, &mix, pos); ptr = g_utf8_next_char (ptr); cluster_end = ptr - text; attr = pango_attr_foreground_new (mix.red, mix.green, mix.blue); attr->start_index = cluster_start; attr->end_index = cluster_end; pango_attr_list_change (attrlist, attr); if (pos < 1.0) dialog->textrange[1] = cluster_end; letter_count++; cluster_start = cluster_end; } break; default: g_printerr ("Unknown animation type %d\n", anim_type); } pango_layout_set_attributes (dialog->layout, attrlist); pango_attr_list_unref (attrlist); }
static PangoLayout* create_layout(HippoCanvasText *text, int allocation_width) { HippoCanvasBox *box = HIPPO_CANVAS_BOX(text); PangoLayout *layout; HippoCanvasStyle *style = hippo_canvas_context_get_style(HIPPO_CANVAS_CONTEXT(text)); g_return_val_if_fail(box->context != NULL, NULL); layout = hippo_canvas_context_create_layout(box->context); if (box->font_desc) { PangoFontDescription *merged = pango_font_description_copy(hippo_canvas_style_get_font(style)); pango_font_description_merge(merged, box->font_desc, TRUE); pango_layout_set_font_description(layout, merged); pango_font_description_free(merged); } else { pango_layout_set_font_description(layout, hippo_canvas_style_get_font(style)); } { PangoAttrList *attrs; HippoTextDecoration decoration = hippo_canvas_style_get_text_decoration(style); if (text->attributes) attrs = pango_attr_list_copy(text->attributes); else attrs = pango_attr_list_new(); if (ABS(1.0 - text->font_scale) > .000001) { PangoAttribute *attr = pango_attr_scale_new(text->font_scale); attr->start_index = 0; attr->end_index = G_MAXUINT; pango_attr_list_insert(attrs, attr); } if ((decoration & HIPPO_TEXT_DECORATION_UNDERLINE) != 0) { PangoAttribute *attr = pango_attr_underline_new(TRUE); attr->start_index = 0; attr->end_index = G_MAXUINT; pango_attr_list_insert(attrs, attr); } if ((decoration & HIPPO_TEXT_DECORATION_LINE_THROUGH) != 0) { PangoAttribute *attr = pango_attr_strikethrough_new(TRUE); attr->start_index = 0; attr->end_index = G_MAXUINT; pango_attr_list_insert(attrs, attr); } pango_layout_set_attributes(layout, attrs); pango_attr_list_unref(attrs); } if (text->text != NULL) { pango_layout_set_text(layout, text->text, -1); } if (allocation_width >= 0) { int layout_width, layout_height; pango_layout_get_size(layout, &layout_width, &layout_height); layout_width /= PANGO_SCALE; layout_height /= PANGO_SCALE; /* Force layout smaller if required, but we don't want to make * the layout _wider_ because it breaks alignment, so only do * this if required. */ if (layout_width > allocation_width) { pango_layout_set_width(layout, allocation_width * PANGO_SCALE); /* If we set ellipsize, then it overrides wrapping. If we get * too-small allocation for HIPPO_CANVAS_SIZE_FULL_WIDTH, then * we want to ellipsize instead of wrapping. */ if (text->size_mode == HIPPO_CANVAS_SIZE_WRAP_WORD) { pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); } else { pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); } /* For now if we say ellipsize end, we always just want one line. * Maybe this should be an orthogonal property? */ if (text->size_mode == HIPPO_CANVAS_SIZE_ELLIPSIZE_END) { pango_layout_set_single_paragraph_mode(layout, TRUE); /* Pango's line separator character in this case is ugly, so we * fix it. Not a very efficient approach, but oh well. */ if (text->text != NULL) { char *new_text = remove_newlines(text->text); /* avoid making the layout recompute everything * if we didn't have newlines anyhow */ if (strcmp(text->text, new_text) != 0) { pango_layout_set_text(layout, new_text, -1); } g_free(new_text); } } } } return layout; }
static boolean pango_textlayout(textspan_t * span, char **fontpath) { static char buf[1024]; /* returned in fontpath, only good until next call */ static PangoFontMap *fontmap; static PangoContext *context; static PangoFontDescription *desc; static char *fontname; static double fontsize; static gv_font_map* gv_fmap; char *fnt, *psfnt = NULL; PangoLayout *layout; PangoRectangle logical_rect; cairo_font_options_t* options; PangoFont *font; #ifdef ENABLE_PANGO_MARKUP PangoAttrList *attrs; GError *error = NULL; int flags; #endif char *text; double textlayout_scale; PostscriptAlias *pA; if (!context) { fontmap = pango_cairo_font_map_new(); gv_fmap = get_font_mapping(fontmap); #ifdef HAVE_PANGO_FONT_MAP_CREATE_CONTEXT context = pango_font_map_create_context (fontmap); #else context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP(fontmap)); #endif options=cairo_font_options_create(); cairo_font_options_set_antialias(options,CAIRO_ANTIALIAS_GRAY); cairo_font_options_set_hint_style(options,CAIRO_HINT_STYLE_FULL); cairo_font_options_set_hint_metrics(options,CAIRO_HINT_METRICS_ON); cairo_font_options_set_subpixel_order(options,CAIRO_SUBPIXEL_ORDER_BGR); pango_cairo_context_set_font_options(context, options); pango_cairo_context_set_resolution(context, FONT_DPI); cairo_font_options_destroy(options); g_object_unref(fontmap); } if (!fontname || strcmp(fontname, span->font->name) != 0 || fontsize != span->font->size) { fontname = span->font->name; fontsize = span->font->size; pango_font_description_free (desc); pA = span->font->postscript_alias; if (pA) { psfnt = fnt = gv_fmap[pA->xfig_code].gv_font; if(!psfnt) psfnt = fnt = pango_psfontResolve (pA); } else fnt = fontname; desc = pango_font_description_from_string(fnt); /* all text layout is done at a scale of FONT_DPI (nominaly 96.) */ pango_font_description_set_size (desc, (gint)(fontsize * PANGO_SCALE)); if (fontpath && (font = pango_font_map_load_font(fontmap, context, desc))) { /* -v support */ const char *fontclass; fontclass = G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(font)); buf[0] = '\0'; if (psfnt) { strcat(buf, "(ps:pango "); strcat(buf, psfnt); strcat(buf, ") "); } strcat(buf, "("); strcat(buf, fontclass); strcat(buf, ") "); #ifdef HAVE_PANGO_FC_FONT_LOCK_FACE if (strcmp(fontclass, "PangoCairoFcFont") == 0) { FT_Face face; PangoFcFont *fcfont; FT_Stream stream; FT_StreamDesc streamdesc; fcfont = PANGO_FC_FONT(font); face = pango_fc_font_lock_face(fcfont); if (face) { strcat(buf, "\""); strcat(buf, face->family_name); strcat(buf, ", "); strcat(buf, face->style_name); strcat(buf, "\" "); stream = face->stream; if (stream) { streamdesc = stream->pathname; if (streamdesc.pointer) strcat(buf, (char*)streamdesc.pointer); else strcat(buf, "*no pathname available*"); } else strcat(buf, "*no stream available*"); } pango_fc_font_unlock_face(fcfont); } else #endif { PangoFontDescription *tdesc; char *tfont; tdesc = pango_font_describe(font); tfont = pango_font_description_to_string(tdesc); strcat(buf, "\""); strcat(buf, tfont); strcat(buf, "\" "); g_free(tfont); } *fontpath = buf; } } #ifdef ENABLE_PANGO_MARKUP if ((span->font) && (flags = span->font->flags)) { unsigned char buf[BUFSIZ]; agxbuf xb; agxbinit(&xb, BUFSIZ, buf); agxbput(&xb,"<span"); if (flags & HTML_BF) agxbput(&xb," weight=\"bold\""); if (flags & HTML_IF) agxbput(&xb," style=\"italic\""); if (flags & HTML_UL) agxbput(&xb," underline=\"single\""); if (flags & HTML_S) agxbput(&xb," strikethrough=\"true\""); agxbput (&xb,">"); if (flags & HTML_SUP) agxbput(&xb,"<sup>"); if (flags & HTML_SUB) agxbput(&xb,"<sub>"); agxbput (&xb,xml_string0(span->str, TRUE)); if (flags & HTML_SUB) agxbput(&xb,"</sub>"); if (flags & HTML_SUP) agxbput(&xb,"</sup>"); agxbput (&xb,"</span>"); if (!pango_parse_markup (agxbuse(&xb), -1, 0, &attrs, &text, NULL, &error)) { fprintf (stderr, "Error - pango_parse_markup: %s\n", error->message); text = span->str; attrs = NULL; } agxbfree (&xb); } else { text = span->str; attrs = NULL; } #else text = span->str; #endif layout = pango_layout_new (context); span->layout = (void *)layout; /* layout free with textspan - see labels.c */ span->free_layout = pango_free_layout; /* function for freeing pango layout */ pango_layout_set_text (layout, text, -1); pango_layout_set_font_description (layout, desc); #ifdef ENABLE_PANGO_MARKUP if (attrs) pango_layout_set_attributes (layout, attrs); #endif pango_layout_get_extents (layout, NULL, &logical_rect); /* if pango doesn't like the font then it sets width=0 but height = garbage */ if (logical_rect.width == 0) logical_rect.height = 0; textlayout_scale = POINTS_PER_INCH / (FONT_DPI * PANGO_SCALE); span->size.x = (int)(logical_rect.width * textlayout_scale + 1); /* round up so that width/height are never too small */ span->size.y = (int)(logical_rect.height * textlayout_scale + 1); /* FIXME -- Horrible kluge !!! */ /* For now we are using pango for single line blocks only. * The logical_rect.height seems to be too high from the font metrics on some platforms. * Use an assumed height based on the point size. */ span->size.y = (int)(span->font->size * 1.1 + .5); /* The y offset from baseline to 0,0 of the bitmap representation */ #if !defined(WIN32) && defined PANGO_VERSION_MAJOR && (PANGO_VERSION_MAJOR >= 1) span->yoffset_layout = pango_layout_get_baseline (layout) * textlayout_scale; #else { /* do it the hard way on rhel5/centos5 */ PangoLayoutIter *iter = pango_layout_get_iter (layout); span->yoffset_layout = pango_layout_iter_get_baseline (iter) * textlayout_scale; } #endif /* The distance below midline for y centering of text strings */ span->yoffset_centerline = 0.2 * span->font->size; if (logical_rect.width == 0) return FALSE; return TRUE; }
void ttext::recalculate(const bool force) const { if(calculation_dirty_ || force) { assert(layout_); calculation_dirty_ = false; surface_dirty_ = true; tfont font(get_font_families(font_class_), font_size_, font_style_); pango_layout_set_font_description(layout_, font.get()); if(font_style_ & ttext::STYLE_UNDERLINE) { PangoAttrList *attribute_list = pango_attr_list_new(); pango_attr_list_insert(attribute_list , pango_attr_underline_new(PANGO_UNDERLINE_SINGLE)); pango_layout_set_attributes (layout_, attribute_list); pango_attr_list_unref(attribute_list); } int maximum_width = 0; if(characters_per_line_ != 0) { PangoFont* f = pango_font_map_load_font( pango_cairo_font_map_get_default() , context_ , font.get()); PangoFontMetrics* m = pango_font_get_metrics(f, nullptr); int w = pango_font_metrics_get_approximate_char_width(m); w *= characters_per_line_; maximum_width = ceil(pango_units_to_double(w)); } else { maximum_width = maximum_width_; } if(maximum_width_ != -1) { maximum_width = std::min(maximum_width, maximum_width_); } /* * See set_maximum_width for some more background info as well. * In order to fix the problem first set a width which seems to render * correctly then lower it to fit. For the campaigns the 4 does "the * right thing" for the terrain labels it should use the value 0 to set * the ellipse properly. Need to see whether this is a bug in pango or * a bug in my understanding of the pango api. */ int hack = 4; do { pango_layout_set_width(layout_, maximum_width == -1 ? -1 : (maximum_width + hack) * PANGO_SCALE); pango_layout_get_pixel_extents(layout_, nullptr, &rect_); DBG_GUI_L << "ttext::" << __func__ << " text '" << gui2::debug_truncate(text_) << "' maximum_width " << maximum_width << " hack " << hack << " width " << rect_.x + rect_.width << ".\n"; --hack; } while(maximum_width != -1 && hack >= 0 && rect_.x + rect_.width > maximum_width); DBG_GUI_L << "ttext::" << __func__ << " text '" << gui2::debug_truncate(text_) << "' font_size " << font_size_ << " markedup_text " << markedup_text_ << " font_style " << std::hex << font_style_ << std::dec << " maximum_width " << maximum_width << " maximum_height " << maximum_height_ << " result " << rect_ << ".\n"; if(maximum_width != -1 && rect_.x + rect_.width > maximum_width) { DBG_GUI_L << "ttext::" << __func__ << " text '" << gui2::debug_truncate(text_) << " ' width " << rect_.x + rect_.width << " greater as the wanted maximum of " << maximum_width << ".\n"; } } }
static gboolean text_item_renderer (AboutRenderer *r, AboutState *state) { PangoLayout *layout = r->layout; int age = state->now - r->start_time; double rage = CLAMP (age / (double)r->duration, 0.0, 1.0); GtkWidget *widget = state->anim_area; GtkStyleContext *ctxt; const int fade = 500; int x, y, width, height; cairo_t *cr; GtkAllocation wa; GdkRGBA color; double alpha = 1; if (age >= r->duration) return FALSE; if (r->fade_in && age < fade) alpha = age / (double)fade; else if (r->fade_out && r->duration - age < fade) alpha = (r->duration - age) / (double)fade; ctxt = gtk_widget_get_style_context (widget); gtk_widget_get_allocation (widget, &wa); x = (int)(PANGO_SCALE * wa.width * (r->start.x + rage * (r->end.x - r->start.x))); y = (int)(PANGO_SCALE * wa.height * (r->start.y + rage * (r->end.y - r->start.y))); if (r->expansion.count) { PangoAttrList *attrlist = pango_layout_get_attributes (layout); const char *p, *text = pango_layout_get_text (layout); PangoRectangle ink, logical; memset (&ink, 0, sizeof (ink)); logical = ink; logical.width = (int)(rage * r->expansion.rate * r->natural_width / r->expansion.count); p = text; while (*p) { const char *next = g_utf8_next_char (p); gunichar uc = g_utf8_get_char (p); PangoAttribute *attr; if (uc == UNICODE_ZERO_WIDTH_SPACE_C) { attr = pango_attr_shape_new (&ink, &logical); attr->start_index = p - text; attr->end_index = next - text; pango_attr_list_change (attrlist, attr); } p = next; } pango_layout_set_attributes (layout, attrlist); } pango_layout_get_size (layout, &width, &height); x -= width / 2; y -= height / 2; cr = r->cr; gnm_style_context_get_color (ctxt, GTK_STATE_FLAG_NORMAL, &color); color.alpha = alpha; gdk_cairo_set_source_rgba (cr, &color); cairo_move_to (cr, x / (double)PANGO_SCALE, y / (double)PANGO_SCALE); pango_cairo_show_layout (cr, layout); return TRUE; }
/* * This function is used by gail_text_cell_get_offset_at_point() * and gail_text_cell_get_character_extents(). There is no * cached PangoLayout for gailtextcell so we must create a temporary * one using this function. */ static PangoLayout* create_pango_layout(GtkCellRendererText *gtk_renderer, GtkWidget *widget) { PangoAttrList *attr_list; PangoLayout *layout; PangoUnderline uline; PangoFontMask mask; layout = gtk_widget_create_pango_layout (widget, gtk_renderer->text); if (gtk_renderer->extra_attrs) attr_list = pango_attr_list_copy (gtk_renderer->extra_attrs); else attr_list = pango_attr_list_new (); if (gtk_renderer->foreground_set) { PangoColor color; color = gtk_renderer->foreground; add_attr (attr_list, pango_attr_foreground_new (color.red, color.green, color.blue)); } if (gtk_renderer->strikethrough_set) add_attr (attr_list, pango_attr_strikethrough_new (gtk_renderer->strikethrough)); mask = pango_font_description_get_set_fields (gtk_renderer->font); if (mask & PANGO_FONT_MASK_FAMILY) add_attr (attr_list, pango_attr_family_new (pango_font_description_get_family (gtk_renderer->font))); if (mask & PANGO_FONT_MASK_STYLE) add_attr (attr_list, pango_attr_style_new (pango_font_description_get_style (gtk_renderer->font))); if (mask & PANGO_FONT_MASK_VARIANT) add_attr (attr_list, pango_attr_variant_new (pango_font_description_get_variant (gtk_renderer->font))); if (mask & PANGO_FONT_MASK_WEIGHT) add_attr (attr_list, pango_attr_weight_new (pango_font_description_get_weight (gtk_renderer->font))); if (mask & PANGO_FONT_MASK_STRETCH) add_attr (attr_list, pango_attr_stretch_new (pango_font_description_get_stretch (gtk_renderer->font))); if (mask & PANGO_FONT_MASK_SIZE) add_attr (attr_list, pango_attr_size_new (pango_font_description_get_size (gtk_renderer->font))); if (gtk_renderer->scale_set && gtk_renderer->font_scale != 1.0) add_attr (attr_list, pango_attr_scale_new (gtk_renderer->font_scale)); if (gtk_renderer->underline_set) uline = gtk_renderer->underline_style; else uline = PANGO_UNDERLINE_NONE; if (uline != PANGO_UNDERLINE_NONE) add_attr (attr_list, pango_attr_underline_new (gtk_renderer->underline_style)); if (gtk_renderer->rise_set) add_attr (attr_list, pango_attr_rise_new (gtk_renderer->rise)); pango_layout_set_attributes (layout, attr_list); pango_layout_set_width (layout, -1); pango_attr_list_unref (attr_list); return layout; }
PangoLayout* gdip_pango_setup_layout (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GDIPCONST GpFont *font, GDIPCONST RectF *rc, RectF *box, GDIPCONST GpStringFormat *format, int **charsRemoved) { GpStringFormat *fmt; PangoLayout *layout; PangoContext *context; PangoRectangle logical; /* logical size of text (used for alignment) */ PangoRectangle ink; /* ink size of text (to pixel boundaries) */ PangoAttrList *list = NULL; GString *ftext; PangoTabArray *tabs; PangoLayoutIter *iter; int i; int FrameWidth; /* rc->Width (or rc->Height if vertical) */ int FrameHeight; /* rc->Height (or rc->Width if vertical) */ int FrameX; /* rc->X (or rc->Y if vertical) */ int FrameY; /* rc->Y (or rc->X if vertical) */ int y0; /* y0,y1,clipNN used for checking line positions vs. clip rectangle */ int y1; double clipx1; double clipx2; double clipy1; double clipy2; int trimSpace; /* whether or not to trim the space */ gchar *text = ucs2_to_utf8 (stringUnicode, length); if (!text) return NULL; length = strlen(text); if (charsRemoved) { (*charsRemoved) = GdipAlloc (sizeof (int) * length); if (!*charsRemoved) { GdipFree (text); return NULL; } memset (*charsRemoved, 0, sizeof (int) * length); } /* TODO - Digit substitution */ // g_warning ("layout >%s< (%d) [x %g, y %g, w %g, h %g] [font %s, %g points]", text, length, rc->X, rc->Y, rc->Width, FrameHeight, font->face, font->emSize); /* a NULL format is valid, it means get the generic default values (and free them later) */ if (!format) { GpStatus status = GdipStringFormatGetGenericDefault ((GpStringFormat **)&fmt); if (status != Ok) { GdipFree (text); return NULL; } } else { fmt = (GpStringFormat *)format; } layout = pango_cairo_create_layout (graphics->ct); /* context is owned by Pango (i.e. not referenced counted) do not free */ context = pango_layout_get_context (layout); pango_layout_set_font_description (layout, gdip_get_pango_font_description ((GpFont*) font)); if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height)); FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width)); FrameX = SAFE_FLOAT_TO_UINT32 (rc->Y); FrameY = SAFE_FLOAT_TO_UINT32 (rc->X); } else { FrameWidth = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Width)); FrameHeight = MAKE_SAFE_FOR_PANGO (SAFE_FLOAT_TO_UINT32 (rc->Height)); FrameX = SAFE_FLOAT_TO_UINT32 (rc->X); FrameY = SAFE_FLOAT_TO_UINT32 (rc->Y); } //g_warning("FW: %d\tFH: %d", FrameWidth, FrameHeight); if ((FrameWidth <= 0) || (fmt->formatFlags & StringFormatFlagsNoWrap)) { pango_layout_set_width (layout, -1); //g_warning ("Setting width: %d", -1); } else { pango_layout_set_width (layout, FrameWidth * PANGO_SCALE); //g_warning ("Setting width: %d", FrameWidth * PANGO_SCALE); } if ((rc->Width != 0) && (rc->Height != 0) && ((fmt->formatFlags & StringFormatFlagsNoClip) == 0)) { // g_warning ("\tclip [%g %g %g %g]", rc->X, rc->Y, rc->Width, rc->Height); /* We do not call cairo_reset_clip because we want to take previous clipping into account */ /* Use rc instead of frame variables because this is pre-transform */ gdip_cairo_rectangle (graphics, rc->X, rc->Y, rc->Width, rc->Height, TRUE); cairo_clip (graphics->ct); } /* with GDI+ the API not the renderer makes the direction decision */ pango_layout_set_auto_dir (layout, FALSE); if (!(fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) != !(fmt->formatFlags & StringFormatFlagsDirectionVertical)) { pango_context_set_base_dir (context, PANGO_DIRECTION_WEAK_RTL); pango_layout_context_changed (layout); /* horizontal alignment */ switch (fmt->alignment) { case StringAlignmentNear: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; case StringAlignmentCenter: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; case StringAlignmentFar: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; } } else { /* pango default base dir is WEAK_LTR, which is what we want */ /* horizontal alignment */ switch (fmt->alignment) { case StringAlignmentNear: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; case StringAlignmentCenter: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; case StringAlignmentFar: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; } } #ifdef PANGO_VERSION_CHECK #if PANGO_VERSION_CHECK(1,16,0) if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { if (fmt->formatFlags & StringFormatFlagsDirectionRightToLeft) { cairo_rotate (graphics->ct, M_PI/2.0); cairo_translate (graphics->ct, 0, -FrameHeight); pango_cairo_update_context (graphics->ct, context); } else { cairo_rotate (graphics->ct, 3.0*M_PI/2.0); cairo_translate (graphics->ct, -FrameWidth, 0); pango_cairo_update_context (graphics->ct, context); } /* only since Pango 1.16 */ pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO); pango_context_set_gravity_hint (context, PANGO_GRAVITY_HINT_LINE); pango_layout_context_changed (layout); } #endif #endif /* TODO - StringFormatFlagsDisplayFormatControl scan and replace them ??? */ /* Trimming options seem to apply only to the end of the string - gdi+ will still wrap * with preference to word first, then character. Unfortunately, pango doesn't have * any way to differentiate wrapping behavior from trimming behavior that I could find */ pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR); switch (fmt->trimming) { case StringTrimmingNone: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingCharacter: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingWord: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); break; case StringTrimmingEllipsisCharacter: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; case StringTrimmingEllipsisWord: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; case StringTrimmingEllipsisPath: pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_MIDDLE); if (!(fmt->formatFlags & StringFormatFlagsNoWrap)) pango_layout_set_height (layout, FrameHeight == 0 ? G_MAXINT32 : FrameHeight * PANGO_SCALE); break; } /* some stuff can only be done by manipulating the attributes (but we can avoid this most of the time) */ if ((fmt->formatFlags & StringFormatFlagsNoFontFallback) || (font->style & (FontStyleUnderline | FontStyleStrikeout))) { list = gdip_get_layout_attributes (layout); /* StringFormatFlagsNoFontFallback */ if (fmt->formatFlags & StringFormatFlagsNoFontFallback) { PangoAttribute *attr = pango_attr_fallback_new (FALSE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } if (font->style & FontStyleUnderline) { PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } if (font->style & FontStyleStrikeout) { PangoAttribute *attr = pango_attr_strikethrough_new (TRUE); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert (list, attr); } } if (fmt->numtabStops > 0) { float tabPosition; tabs = pango_tab_array_new (fmt->numtabStops, FALSE); tabPosition = fmt->firstTabOffset; for (i = 0; i < fmt->numtabStops; i++) { tabPosition += fmt->tabStops[i]; pango_tab_array_set_tab (tabs, i, PANGO_TAB_LEFT, (gint)min (tabPosition, PANGO_MAX) * PANGO_SCALE); } pango_layout_set_tabs (layout, tabs); pango_tab_array_free (tabs); } //g_warning ("length before ws removal: %d", length); trimSpace = (fmt->formatFlags & StringFormatFlagsMeasureTrailingSpaces) == 0; switch (fmt->hotkeyPrefix) { case HotkeyPrefixHide: /* we need to remove any accelerator from the string */ ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved); break; case HotkeyPrefixShow: /* optimization: is seems that we never see the hotkey when using an underline font */ if (font->style & FontStyleUnderline) { /* so don't bother drawing it (and simply add the '&' character) */ ftext = gdip_process_string (text, length, 1, trimSpace, NULL, charsRemoved); } else { /* find accelerator and add attribute to the next character (unless it's the prefix too) */ if (!list) list = gdip_get_layout_attributes (layout); ftext = gdip_process_string (text, length, 1, trimSpace, list, charsRemoved); } break; default: ftext = gdip_process_string (text, length, 0, trimSpace, NULL, charsRemoved); break; } length = ftext->len; //g_warning ("length after ws removal: %d", length); if (list) { pango_layout_set_attributes (layout, list); pango_attr_list_unref (list); } // g_warning("\tftext>%s< (%d)", ftext->str, -1); pango_layout_set_text (layout, ftext->str, ftext->len); GdipFree (text); g_string_free(ftext, TRUE); /* Trim the text after the last line for ease of counting lines/characters */ /* Also prevents drawing whole lines outside the boundaries if NoClip was specified */ /* In case of pre-existing clipping, use smaller of clip rectangle or our specified height */ if (FrameHeight > 0) { cairo_clip_extents (graphics->ct, &clipx1, &clipy1, &clipx2, &clipy2); if (clipy2 > 0 && !(fmt->formatFlags & StringFormatFlagsNoClip)) clipy2 = min (clipy2, FrameHeight + FrameY); else clipy2 = FrameHeight + FrameY; iter = pango_layout_get_iter (layout); do { if (iter == NULL) break; pango_layout_iter_get_line_yrange (iter, &y0, &y1); //g_warning("yrange: %d %d clipy2: %f", y0 / PANGO_SCALE, y1 / PANGO_SCALE, clipy2); /* StringFormatFlagsLineLimit */ if (((fmt->formatFlags & StringFormatFlagsLineLimit) && y1 / PANGO_SCALE > clipy2) || (y0 / PANGO_SCALE > clipy2)) { PangoLayoutLine *line = pango_layout_iter_get_line_readonly (iter); pango_layout_set_text (layout, pango_layout_get_text (layout), line->start_index); break; } } while (pango_layout_iter_next_line (iter)); pango_layout_iter_free (iter); } pango_layout_get_pixel_extents (layout, &ink, &logical); // g_warning ("\tlogical\t[x %d, y %d, w %d, h %d][x %d, y %d, w %d, h %d]", logical.x, logical.y, logical.width, logical.height, ink.x, ink.y, ink.width, ink.height); if ((fmt->formatFlags & StringFormatFlagsNoFitBlackBox) == 0) { /* By default don't allow overhang - ink space may be larger than logical space */ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { box->X = min (ink.y, logical.y); box->Y = min (ink.x, logical.x); box->Height = max (ink.width, logical.width); box->Width = max (ink.height, logical.height); } else { box->X = min (ink.x, logical.x); box->Y = min (ink.y, logical.y); box->Height = max (ink.height, logical.height); box->Width = max (ink.width, logical.width); } } else { /* Allow overhang */ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { box->X = logical.y; box->Y = logical.x; box->Height = logical.width; box->Width = logical.height; } else { box->X = logical.x; box->Y = logical.y; box->Height = logical.height; box->Width = logical.width; } } // g_warning ("\tbox\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height); /* vertical alignment*/ if (fmt->formatFlags & StringFormatFlagsDirectionVertical) { switch (fmt->lineAlignment) { case StringAlignmentNear: break; case StringAlignmentCenter: box->X += (rc->Width - box->Width) / 2; break; case StringAlignmentFar: box->X += (rc->Width - box->Width); break; } } else { switch (fmt->lineAlignment) { case StringAlignmentNear: break; case StringAlignmentCenter: box->Y += (rc->Height - box->Height) / 2; break; case StringAlignmentFar: box->Y += (rc->Height - box->Height); break; } } // g_warning ("va-box\t[x %g, y %g, w %g, h %g]", box->X, box->Y, box->Width, box->Height); pango_cairo_update_layout (graphics->ct, layout); return layout; }
static void gimp_tag_popup_constructed (GObject *object) { GimpTagPopup *popup = GIMP_TAG_POPUP (object); GimpTaggedContainer *container; GtkWidget *entry; GtkAllocation entry_allocation; GtkStyle *frame_style; gint x; gint y; gint width; gint height; gint popup_height; GHashTable *tag_hash; GList *tag_list; GList *tag_iterator; gint i; gint max_height; gint screen_height; gchar **current_tags; gint current_count; GdkRectangle popup_rects[2]; /* variants of popup placement */ GdkRectangle popup_rect; /* best popup rect in screen coordinates */ if (G_OBJECT_CLASS (parent_class)->constructed) G_OBJECT_CLASS (parent_class)->constructed (object); entry = GTK_WIDGET (popup->combo_entry); gtk_window_set_screen (GTK_WINDOW (popup), gtk_widget_get_screen (entry)); popup->context = gtk_widget_create_pango_context (GTK_WIDGET (popup)); popup->layout = pango_layout_new (popup->context); gtk_widget_get_allocation (entry, &entry_allocation); gtk_widget_style_get (GTK_WIDGET (popup), "scroll-arrow-vlength", &popup->scroll_arrow_height, NULL); pango_layout_set_attributes (popup->layout, popup->combo_entry->normal_item_attr); current_tags = gimp_tag_entry_parse_tags (GIMP_TAG_ENTRY (popup->combo_entry)); current_count = g_strv_length (current_tags); container = GIMP_TAG_ENTRY (popup->combo_entry)->container; tag_hash = container->tag_ref_counts; tag_list = g_hash_table_get_keys (tag_hash); tag_list = g_list_sort (tag_list, gimp_tag_compare_func); popup->tag_count = g_list_length (tag_list); popup->tag_data = g_new0 (PopupTagData, popup->tag_count); for (i = 0, tag_iterator = tag_list; i < popup->tag_count; i++, tag_iterator = g_list_next (tag_iterator)) { PopupTagData *tag_data = &popup->tag_data[i]; gint j; tag_data->tag = tag_iterator->data; tag_data->state = GTK_STATE_NORMAL; for (j = 0; j < current_count; j++) { if (! gimp_tag_compare_with_string (tag_data->tag, current_tags[j])) { tag_data->state = GTK_STATE_SELECTED; break; } } } g_list_free (tag_list); g_strfreev (current_tags); if (GIMP_TAG_ENTRY (popup->combo_entry)->mode == GIMP_TAG_ENTRY_MODE_QUERY) { for (i = 0; i < popup->tag_count; i++) { if (popup->tag_data[i].state != GTK_STATE_SELECTED) { popup->tag_data[i].state = GTK_STATE_INSENSITIVE; } } gimp_container_foreach (GIMP_CONTAINER (container), (GFunc) gimp_tag_popup_check_can_toggle, popup); } frame_style = gtk_widget_get_style (popup->frame); width = (entry_allocation.width - 2 * frame_style->xthickness); height = (gimp_tag_popup_layout_tags (popup, width) + 2 * frame_style->ythickness); gdk_window_get_origin (gtk_widget_get_window (entry), &x, &y); max_height = entry_allocation.height * 10; screen_height = gdk_screen_get_height (gtk_widget_get_screen (entry)); popup_height = MIN (height, max_height); popup_rects[0].x = x; popup_rects[0].y = 0; popup_rects[0].width = entry_allocation.width; popup_rects[0].height = y + entry_allocation.height; popup_rects[1].x = x; popup_rects[1].y = y; popup_rects[1].width = popup_rects[0].width; popup_rects[1].height = screen_height - popup_rects[0].height; if (popup_rects[0].height >= popup_height) { popup_rect = popup_rects[0]; popup_rect.y += popup_rects[0].height - popup_height; popup_rect.height = popup_height; } else if (popup_rects[1].height >= popup_height) { popup_rect = popup_rects[1]; popup_rect.height = popup_height; } else { if (popup_rects[0].height >= popup_rects[1].height) { popup_rect = popup_rects[0]; popup_rect.y += popup->scroll_arrow_height + frame_style->ythickness; } else { popup_rect = popup_rects[1]; popup_rect.y -= popup->scroll_arrow_height + frame_style->ythickness; } popup_height = popup_rect.height; } if (popup_height < height) { popup->arrows_visible = TRUE; popup->upper_arrow_state = GTK_STATE_INSENSITIVE; gtk_alignment_set_padding (GTK_ALIGNMENT (popup->alignment), popup->scroll_arrow_height + 2, popup->scroll_arrow_height + 2, 0, 0); popup_height -= 2 * popup->scroll_arrow_height + 4; popup->scroll_height = height - popup_rect.height; popup->scroll_y = 0; popup->scroll_step = 0; } gtk_widget_set_size_request (popup->tag_area, width, popup_height); gtk_window_move (GTK_WINDOW (popup), popup_rect.x, popup_rect.y); gtk_window_resize (GTK_WINDOW (popup), popup_rect.width, popup_rect.height); }
static void text_entry_update_layout(struct text_entry *entry) { char *text; PangoAttrList *attr_list; assert(entry->cursor <= (strlen(entry->text) + (entry->preedit.text ? strlen(entry->preedit.text) : 0))); if (entry->preedit.text) { text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1); strncpy(text, entry->text, entry->cursor); strcpy(text + entry->cursor, entry->preedit.text); strcpy(text + entry->cursor + strlen(entry->preedit.text), entry->text + entry->cursor); } else { text = strdup(entry->text); } if (entry->cursor != entry->anchor) { int start_index = MIN(entry->cursor, entry->anchor); int end_index = MAX(entry->cursor, entry->anchor); PangoAttribute *attr; attr_list = pango_attr_list_copy(entry->preedit.attr_list); if (!attr_list) attr_list = pango_attr_list_new(); attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert(attr_list, attr); attr = pango_attr_foreground_new(65535, 65535, 65535); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert(attr_list, attr); } else { attr_list = pango_attr_list_ref(entry->preedit.attr_list); } if (entry->preedit.text && !entry->preedit.attr_list) { PangoAttribute *attr; if (!attr_list) attr_list = pango_attr_list_new(); attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr->start_index = entry->cursor; attr->end_index = entry->cursor + strlen(entry->preedit.text); pango_attr_list_insert(attr_list, attr); } if (entry->layout) { pango_layout_set_text(entry->layout, text, -1); pango_layout_set_attributes(entry->layout, attr_list); } free(text); pango_attr_list_unref(attr_list); }
static void draw_text_line(DiaRenderer *self, TextLine *text_line, Point *pos, Alignment alignment, Color *color) { DiaPsFt2Renderer *renderer = DIA_PS_FT2_RENDERER(self); PangoLayout *layout; int line, linecount; double xpos = pos->x, ypos = pos->y; char *text = text_line_get_string(text_line); /* TODO: we could probably pass the alignment down to the PS file? */ xpos -= text_line_get_alignment_adjustment (text_line, alignment); /* Using the global PangoContext does not allow to have renderer specific * different ones. Or it implies the push/pop _context mess. Anyway just * get rid of warnings for now. But the local code may be resurreted * sooner or later... --hb */ #define USE_GLOBAL_CONTEXT #ifndef USE_GLOBAL_CONTEXT PangoAttrList* list; PangoAttribute* attr; guint length; #endif if ((!text)||(text == (const char *)(1))) return; lazy_setcolor(DIA_PS_RENDERER(renderer),color); #define ANNOYING_SCALE_FACTOR 5.9 /* Make sure the letters aren't too wide. */ #ifdef USE_GLOBAL_CONTEXT layout = dia_font_build_layout(text, text_line_get_font(text_line), text_line_get_height(text_line)*ANNOYING_SCALE_FACTOR); #else /* approximately what would be required but w/o dia_font_get_context() */ dia_font_set_height(text_line_get_font(text_line), text_line_get_height(text_line)); layout = pango_layout_new(dia_font_get_context()); length = text ? strlen(text) : 0; pango_layout_set_text(layout,text,length); list = pango_attr_list_new(); attr = pango_attr_font_desc_new(dia_font_get_description(text_line_get_font(text_line))); attr->start_index = 0; attr->end_index = length; pango_attr_list_insert(list,attr); pango_layout_set_attributes(layout,list); pango_attr_list_unref(list); pango_layout_set_indent(layout,0); pango_layout_set_justify(layout,FALSE); #endif pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); linecount = pango_layout_get_line_count(layout); for (line = 0; line < linecount; line++) { PangoLayoutLine *layoutline = pango_layout_get_line(layout, line); /* Not sure scale is the right one here. */ text_line_adjust_layout_line(text_line, layoutline, ANNOYING_SCALE_FACTOR); postscript_draw_contour(DIA_PS_RENDERER(renderer), DPI, /* dpi_x */ layoutline, xpos, ypos); ypos += 10;/* Some line height thing??? */ } }
/* split a text buffer into chunks using the passed Pango layout */ GList * split_for_layout(PangoLayout * layout, const gchar * text, PangoAttrList * attributes, BalsaPrintSetup * psetup, gboolean is_header, GArray ** offsets) { GList *split_list = NULL; PangoLayoutIter *iter; const gchar *start; gint p_offset; gboolean add_tab; gint p_y0; gint p_y1; gint p_y_pos; gint p_height; /* set the text and its attributes, then get an iter */ pango_layout_set_text(layout, text, -1); if (attributes) pango_layout_set_attributes(layout, attributes); if (offsets) *offsets = g_array_new(FALSE, FALSE, sizeof(guint)); iter = pango_layout_get_iter(layout); /* loop over lines */ start = text; p_offset = 0; add_tab = FALSE; p_y_pos = C_TO_P(psetup->c_y_pos); p_height = C_TO_P(psetup->c_height); do { pango_layout_iter_get_line_yrange(iter, &p_y0, &p_y1); if (p_y_pos + p_y1 - p_offset > p_height) { gint index; gint tr; gchar *chunk; gboolean ends_with_nl; if (offsets) { guint offs = start - text; *offsets = g_array_append_val(*offsets, offs); } pango_layout_xy_to_index(layout, 0, p_y0, &index, &tr); ends_with_nl = text[index - 1] == '\n'; if (ends_with_nl) index--; chunk = g_strndup(start, text + index - start); if (add_tab) split_list = g_list_append(split_list, g_strconcat("\t", chunk, NULL)); else split_list = g_list_append(split_list, g_strdup(chunk)); add_tab = is_header && !ends_with_nl; g_free(chunk); start = text + index; if (ends_with_nl) start++; if (*start == '\0') p_y_pos = p_height; else { p_y_pos = 0; psetup->page_count++; } p_offset = p_y0; } } while (pango_layout_iter_next_line(iter)); pango_layout_iter_free(iter); /* append any remaining stuff */ if (*start != '\0') { p_y_pos += p_y1 - p_offset; if (offsets) { guint offs = start - text; *offsets = g_array_append_val(*offsets, offs); } if (add_tab) split_list = g_list_append(split_list, g_strconcat("\t", start, NULL)); else split_list = g_list_append(split_list, g_strdup(start)); } /* remember the new y position in cairo units */ psetup->c_y_pos = P_TO_C(p_y_pos); /* return the list */ return split_list; }
/* This function is used by gtk_text_cell_accessible_get_offset_at_point() * and gtk_text_cell_accessible_get_character_extents(). There is no * cached PangoLayout so we must create a temporary one using this function. */ static PangoLayout * create_pango_layout (GtkTextCellAccessible *text) { GdkRGBA *foreground_rgba; PangoAttrList *attr_list, *attributes; PangoLayout *layout; PangoUnderline uline, underline; PangoFontMask mask; PangoFontDescription *font_desc; gboolean foreground_set, strikethrough_set, strikethrough; gboolean scale_set, underline_set, rise_set; gchar *renderer_text; gdouble scale; gint rise; GtkRendererCellAccessible *gail_renderer; GtkCellRendererText *gtk_renderer; gail_renderer = GTK_RENDERER_CELL_ACCESSIBLE (text); gtk_renderer = GTK_CELL_RENDERER_TEXT (gail_renderer->renderer); g_object_get (gtk_renderer, "text", &renderer_text, "attributes", &attributes, "foreground-set", &foreground_set, "foreground-rgba", &foreground_rgba, "strikethrough-set", &strikethrough_set, "strikethrough", &strikethrough, "font-desc", &font_desc, "scale-set", &scale_set, "scale", &scale, "underline-set", &underline_set, "underline", &underline, "rise-set", &rise_set, "rise", &rise, NULL); layout = gtk_widget_create_pango_layout (get_widget (text), renderer_text); if (attributes) attr_list = pango_attr_list_copy (attributes); else attr_list = pango_attr_list_new (); if (foreground_set) { add_attr (attr_list, pango_attr_foreground_new (foreground_rgba->red * 65535, foreground_rgba->green * 65535, foreground_rgba->blue * 65535)); } if (strikethrough_set) add_attr (attr_list, pango_attr_strikethrough_new (strikethrough)); mask = pango_font_description_get_set_fields (font_desc); if (mask & PANGO_FONT_MASK_FAMILY) add_attr (attr_list, pango_attr_family_new (pango_font_description_get_family (font_desc))); if (mask & PANGO_FONT_MASK_STYLE) add_attr (attr_list, pango_attr_style_new (pango_font_description_get_style (font_desc))); if (mask & PANGO_FONT_MASK_VARIANT) add_attr (attr_list, pango_attr_variant_new (pango_font_description_get_variant (font_desc))); if (mask & PANGO_FONT_MASK_WEIGHT) add_attr (attr_list, pango_attr_weight_new (pango_font_description_get_weight (font_desc))); if (mask & PANGO_FONT_MASK_STRETCH) add_attr (attr_list, pango_attr_stretch_new (pango_font_description_get_stretch (font_desc))); if (mask & PANGO_FONT_MASK_SIZE) add_attr (attr_list, pango_attr_size_new (pango_font_description_get_size (font_desc))); if (scale_set && scale != 1.0) add_attr (attr_list, pango_attr_scale_new (scale)); if (underline_set) uline = underline; else uline = PANGO_UNDERLINE_NONE; if (uline != PANGO_UNDERLINE_NONE) add_attr (attr_list, pango_attr_underline_new (underline)); if (rise_set) add_attr (attr_list, pango_attr_rise_new (rise)); pango_layout_set_attributes (layout, attr_list); pango_layout_set_width (layout, -1); pango_attr_list_unref (attr_list); pango_font_description_free (font_desc); pango_attr_list_unref (attributes); g_free (renderer_text); gdk_rgba_free (foreground_rgba); return layout; }
static void gtk_numerable_icon_ensure_emblem (GtkNumerableIcon *self) { cairo_t *cr; cairo_surface_t *surface; PangoLayout *layout; GEmblem *emblem; gint width, height; gdouble scale; PangoAttrList *attr_list; PangoAttribute *attr; GdkPixbuf *pixbuf; /* don't draw anything if the count is zero */ if (self->priv->rendered_string == NULL) { g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (self)); return; } surface = get_image_surface (self); cr = cairo_create (surface); layout = get_pango_layout (self); pango_layout_get_pixel_size (layout, &width, &height); /* scale the layout to be 0.75 of the size still available for drawing */ scale = ((get_surface_size (surface) - 2 * get_border_size (self)) * 0.75) / (MAX (height, width)); attr_list = pango_attr_list_new (); attr = pango_attr_scale_new (scale); pango_attr_list_insert (attr_list, attr); attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); pango_attr_list_insert (attr_list, attr); pango_layout_set_attributes (layout, attr_list); /* update these values */ pango_layout_get_pixel_size (layout, &width, &height); /* move to the center */ cairo_move_to (cr, get_surface_size (surface) / 2. - (gdouble) width / 2., get_surface_size (surface) / 2. - (gdouble) height / 2.); gdk_cairo_set_source_rgba (cr, self->priv->foreground); pango_cairo_show_layout (cr, layout); cairo_destroy (cr); pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, get_surface_size (surface), get_surface_size (surface)); emblem = g_emblem_new (G_ICON (pixbuf)); g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (self)); g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (self), emblem); g_object_unref (layout); g_object_unref (emblem); g_object_unref (pixbuf); cairo_surface_destroy (surface); pango_attr_list_unref (attr_list); }