Cairo FAQ Text
Материал из Wiki.crossplatform.ru
In this part of the Cairo graphics tutorial, we will work with text.
Soulmate
In the first example, we will display some lyrics on the GTK+ window.
#include <cairo.h> #include <gtk/gtk.h> static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cr = gdk_cairo_create(widget->window); cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); cairo_select_font_face(cr, "Purisa", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, 13); cairo_move_to(cr, 20, 30); cairo_show_text(cr, "Most relationships seem so transitory"); cairo_move_to(cr, 20, 60); cairo_show_text(cr, "They're all good but not the permanent one"); cairo_move_to(cr, 20, 120); cairo_show_text(cr, "Who doesn't long for someone to hold"); cairo_move_to(cr, 20, 150); cairo_show_text(cr, "Who knows how to love you without being told"); cairo_move_to(cr, 20, 180); cairo_show_text(cr, "Somebody tell me why I'm on my own"); cairo_move_to(cr, 20, 210); cairo_show_text(cr, "If there's a soulmate for everyone"); cairo_destroy(cr); return FALSE; } int main (int argc, char *argv[]) { GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 420, 250); gtk_window_set_title(GTK_WINDOW(window), "Soulmate"); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); return 0; }
In this example, we display part of the lyrics from the Natasha Bedingfields Soulmate song.
cairo_select_font_face(cr, "Purisa", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
Here we select the font face. The function takes three parameters, the font family, font slant and the font weight.
cairo_set_font_size(cr, 13);
Here we specify the font size.
cairo_move_to(cr, 20, 30); cairo_show_text(cr, "Most relationships seem so transitory");
We display the text on the window by specifying the position of the text and calling the cairo_show_text() function.
Letter by letter
In this effect, we will display a text letter by letter. The letters will be drawn with some delay.
#include <cairo.h> #include <gtk/gtk.h> gpointer text[7] = { "Z", "e", "t", "C", "o", "d", "e" }; gboolean timer = TRUE; static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cairo_text_extents_t extents; static gint count = 0; cr = gdk_cairo_create(widget->window); cairo_select_font_face(cr, "Courier", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, 35); cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); gint i; gint x = 0; for (i = 0; i < count; i++) { cairo_text_extents(cr, text[i], &extents); x += extents.width + 2; cairo_move_to(cr, x + 30, 50); cairo_show_text(cr, text[i]); } count++; if (count == 8) { timer = FALSE; count = 0; } cairo_destroy(cr); return FALSE; } static gboolean time_handler (GtkWidget *widget) { if (widget->window == NULL) return FALSE; if (!timer) return FALSE; gtk_widget_queue_draw(widget); return TRUE; } int main (int argc, char *argv[]) { GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 300, 90); gtk_window_set_title(GTK_WINDOW(window), "ZetCode"); gtk_widget_set_app_paintable(window, TRUE); g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) window); gtk_widget_show_all(window); gtk_main(); return 0; }
In our example, we will draw the "ZetCode" string onto the GTK+ window letter by letter with some delay.
gpointer text[7] = { "Z", "e", "t", "C", "o", "d", "e" };
We create an array of strings.
cairo_select_font_face(cr, "Courier", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
We select a Courier font face.
for (i = 0; i < count; i++) { cairo_text_extents(cr, text[i], &extents); x += extents.width + 2; cairo_move_to(cr, x + 30, 50); cairo_show_text(cr, text[i]); }
Here we draw the text letter by letter. The extents.width gives us the width of the current letter.
Puff
In the following example, we create a puff effect. The example will display a growing centered text, that will gradully fade out from some point. This is a very common effect, which you can often see in flash animations.
#include <cairo.h> #include <gtk/gtk.h> gpointer text[7] = { "Z", "e", "t", "C", "o", "d", "e" }; gboolean timer = TRUE; static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cairo_text_extents_t extents; static gdouble alpha = 1.0; static gdouble size = 1; gint x = widget->allocation.width / 2; gint y = widget->allocation.height / 2; cr = gdk_cairo_create(widget->window); cairo_set_source_rgb(cr, 0.5, 0, 0); cairo_paint(cr); cairo_select_font_face(cr, "Courier", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); size += 0.8; if (size > 20) { alpha -= 0.01; } cairo_set_font_size(cr, size); cairo_set_source_rgb(cr, 1, 1, 1); cairo_text_extents(cr, "ZetCode", &extents); cairo_move_to(cr, x - extents.width/2, y); cairo_text_path(cr, "ZetCode"); cairo_clip(cr); cairo_stroke(cr); cairo_paint_with_alpha(cr, alpha); if (alpha <= 0) { timer = FALSE; } cairo_destroy(cr); return FALSE; } static gboolean time_handler (GtkWidget *widget) { if (widget->window == NULL) return FALSE; if (!timer) return FALSE; gtk_widget_queue_draw(widget); return TRUE; } int main (int argc, char *argv[]) { GtkWidget *window; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_default_size(GTK_WINDOW(window), 350, 200); gtk_window_set_title(GTK_WINDOW(window), "puff"); gtk_widget_set_app_paintable(window, TRUE); g_timeout_add(14, (GSourceFunc) time_handler, (gpointer) window); gtk_widget_show_all(window); gtk_main(); return 0; }
The example creates a growing and fading text on the GTK+ window.
gint x = widget->allocation.width / 2; gint y = widget->allocation.height / 2;
Coordinates of the middle point.
cairo_set_source_rgb(cr, 0.5, 0, 0); cairo_paint(cr);
We set the background color to dark red color.
size += 0.8;
Each cycle, the font size will grow by 0.8 units.
if (size > 20) { alpha -= 0.01; }
The fading out begins after the font size is bigger than 20.
cairo_text_extents(cr, "ZetCode", &extents);
We get the text metrics.
cairo_move_to(cr, x - extents.width/2, y);
We use the text metrics to center the text on the window.
cairo_text_path(cr, "ZetCode"); cairo_clip(cr);
We get the path of the text and set the current clip region to it.
cairo_stroke(cr); cairo_paint_with_alpha(cr, alpha);
We paint the current path with and take alpha value into account.