diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-06-12 19:18:34 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-06-22 13:54:02 -0400 |
commit | 058a84471065c337bd08a7d69fc544c72facc126 (patch) | |
tree | 029955459271d6b988275a10397bf71499afc328 /docs | |
parent | deb9c06d48884a01be7e038ed8bec6aced66c858 (diff) | |
download | pango-058a84471065c337bd08a7d69fc544c72facc126.tar.gz |
docs: Add a complex layout example
Diffstat (limited to 'docs')
-rw-r--r-- | docs/meson.build | 2 | ||||
-rw-r--r-- | docs/pango.toml.in | 2 | ||||
-rw-r--r-- | docs/pango_layout.md | 168 | ||||
-rw-r--r-- | docs/parshape.png | bin | 0 -> 48251 bytes |
4 files changed, 172 insertions, 0 deletions
diff --git a/docs/meson.build b/docs/meson.build index 0d320590..58543b01 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -8,6 +8,7 @@ pango_content_files = [ 'pango_bidi.md', 'pango_cairo.md', 'pango_user.md', + 'pango_layout.md', 'pango-name.png', 'layout-light.png', 'layout-dark.png', @@ -56,6 +57,7 @@ pango_content_files = [ 'rotated-text.png', 'bullets.png', 'first-steps.png', + 'parshape.png', ] doc_conf = configuration_data() diff --git a/docs/pango.toml.in b/docs/pango.toml.in index bb6ff539..77f73456 100644 --- a/docs/pango.toml.in +++ b/docs/pango.toml.in @@ -51,6 +51,7 @@ content_files = [ "pango_bidi.md", "pango_cairo.md", "pango_user.md", + "pango_layout.md", ] content_images = [ @@ -101,6 +102,7 @@ content_images = [ "rotated-text.png", "bullets.png", "first-steps.png", + "parshape.png", ] urlmap_file = "urlmap.js" diff --git a/docs/pango_layout.md b/docs/pango_layout.md new file mode 100644 index 00000000..a4d8e122 --- /dev/null +++ b/docs/pango_layout.md @@ -0,0 +1,168 @@ +--- +Title: Complex layout +--- + +# Complex layout + +The central object in high-level Pango API is [class@Pango.Layout]. +It is well-suited for breaking text into lines that fill a rectangular +area, since that is commonly how paragraphs are formatted in books. +But in real-life situations, text does not always fit in a box. +Examples of more complicated requirements are fitting text around +an image, or flowing text between multiple frames. + +For cases like these, it is better to use [class@Pango.LineBreaker] +directly instead of `PangoLayout` (`PangoLayout` is using a line +breaker internally). The way `PangoLineBreaker` works is to let +applications access the formatted result one line at a time, place +it, and change parameters such as the line width before requesting +the next one. + +The following example shows how to use `PangoLineBreaker` to +produce an unusually shaped paragraph with a hole in the middle. + +## Using GtkLineBreaker + +``` +#include <pango/pango.h> +#include <pango/pangocairo.h> + +static PangoLines * +format_text (const char *text) +{ + PangoContext *context; + PangoLineBreaker *breaker; + PangoLines *lines; + int x, y, width; + int inc, m, w, w2; + + context = pango_font_map_create_context (pango_font_map_get_default ()); + breaker = pango_line_breaker_new (context); + + pango_line_breaker_add_text (breaker, text, -1, NULL); + + lines = pango_lines_new (); + + m = 200; + w = 10; + w2 = -200; + inc = 40; + + y = 40 * PANGO_SCALE; + x = (m - w / 2) * PANGO_SCALE; + width = w * PANGO_SCALE; + + while (pango_line_breaker_has_line (breaker)) + { + PangoLine *line; + PangoRectangle ext; + gboolean ltr; + + line = pango_line_breaker_next_line (breaker, + x, width, + PANGO_WRAP_CHAR, + PANGO_ELLIPSIZE_NONE); + + pango_line_get_extents (line, NULL, &ext); + line = pango_line_justify (line, width); + pango_lines_add_line (lines, line, x, y - ext.y); + + ltr = pango_line_breaker_get_direction (breaker) == PANGO_DIRECTION_LTR; + + if (w2 > 0 && ltr && x <= m * PANGO_SCALE) + x = (m + w2 / 2) * PANGO_SCALE; + else if (w2 > 0 && !ltr && x > m * PANGO_SCALE) + x = (m - w2 / 2) * PANGO_SCALE; + else + { + y += ext.height; + + w += inc; + w2 += inc; + if (w + inc >= 340 || w + inc < 0) + inc = - inc; + + if (w2 > 0) + width = ((w - w2) / 2) * PANGO_SCALE; + else + width = w * PANGO_SCALE; + + if (ltr) + x = (m - w / 2) * PANGO_SCALE; + else + x = (m + w / 2) * PANGO_SCALE; + } + } + + g_object_unref (breaker); + g_object_unref (context); + + return lines; +} + +static void +draw_lines (cairo_t *cr, PangoLines *lines) +{ + for (int i = 0; i < pango_lines_get_line_count (lines); i++) + { + PangoLine *line = pango_lines_get_lines (lines)[i]; + int x, y; + + pango_lines_get_line_position (lines, i, &x, &y); + + cairo_save (cr); + cairo_move_to (cr, x / (double)PANGO_SCALE, y / (double)PANGO_SCALE); + pango_cairo_show_line (cr, line); + cairo_restore (cr); + } +} + +int +main (int argc, char *argv[]) +{ + const char *filename; + PangoLines *lines; + cairo_surface_t *surface; + cairo_t *cr; + char *text; + gsize length; + GError *error = NULL; + + if (argc != 3) + { + g_printerr ("Usage: %s INPUT_FILENAME OUTPUT_FILENAME\n", argv[0]); + return 1; + } + + if (!g_file_get_contents (argv[1], &text, &length, &error)) + { + g_printerr ("%s\n", error->message); + return 1; + } + + filename = argv[2]; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 600); + cr = cairo_create (surface); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + lines = format_text (text); + draw_lines (cr, lines); + g_object_unref (lines); + + cairo_surface_write_to_png (surface, filename); + g_print ("Output written to %s\n", filename); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + return 0; +} +``` + +Once you build and run the example code above, you should see the +following result: + +![Output of the example](parshape.png) diff --git a/docs/parshape.png b/docs/parshape.png Binary files differnew file mode 100644 index 00000000..6ac8a05d --- /dev/null +++ b/docs/parshape.png |