Desenhando textos ad-hoc com Gtk2 e Pango

Daniel Ruoso
Publicado em 23/12/2006

r3 - 23 Dec 2006 - DanielRuoso

Desenhando textos ad-hoc com Gtk2 e Pango

Às vezes é necessário desenhar um texto qualquer na tela com Gtk2, como parte de um gráfico. Como este tema em especial tem pouquíssima documentação, segue aqui o caminho das pedras para conseguir escrever um texto qualquer com Gtk2 e Pango.

O Gtk2 é um toolkit poderoso. Muito mais poderoso do que muitos julgam, e, justamente por isso, as vezes não é tão simples utilizá-lo. Por exemplo, eu cheguei na questão desse artigo quando estava precisando desenhar um texto qualquer utilizando um Gtk2::DrawingArea. Eu poderia ter utilizado o draw_text, mas este método está obsoleto e não colabora muito com UTF8 e coisas assim. Eu já sabia que o Gtk2 tem um ótimo suporte a UTF8 e por isso queria fazer o negócio direito.

Pois bem, sabia que o engodo começava no Pango, mas a única documentação que existe são as APIs, então, bem, fui à tentativa e erro.

Não pretendo aqui passar todos os passos de erro, mas quero sim explicar como ficou o resultado final.

Pango Context

O Pango Context é um elemento chave para tudo funcionar. Você não consegue fazer praticamente nada sem ter um contexto válido. O segredo é saber que qualquer widget implementa o método get_pango_context. Com esse método você tem o contexto no seu estado ideal, uma vez que você chama ele do próprio widget onde voce vai pintar alguma coisa.

Font Description

A outra coisa que voce precisa é conseguir um FontDescription, ou seja, para definir com qual fonte voce vai escrever. A classe Gtk2::Pango::FontDescription tem o método from_string que serve para construir a fonte a partir de uma descrição amigável. Algo como "Sans 10".

Layout

Por fim, o último elemento que voce precisa ter antes de mandar pintar o texto é o Layout. Como estamos falando em internacionalização, UTF-8 e coisa e tal, não existe a noção de "coloque o texto aqui". Um conjunto maior de variáveis influencia nisso, mas felizmente o Pango cuida disso, a única coisa que voce precisa é criar um layout, o resto ele faz. Para criar um layout basta chamar o método new da classe Gtk2::Pango::Layout, que recebe o Pango Context. Depois basta passar a string (em UTF8, mas você realmente não precisa se preocupar com isso) utilizando o método set_text do layout e dizer a fonte usando o set_font_description.

Finalmente, desenhando.

Aqui está a parte ainda mais obscura. Por causa do conjunto gigantesco de possibilidades de onde e como o texto vai aparecer, voce não diz tem os métodos de pintura de texto no GdkWindow, mas sim, surpreendentemente, no GdkStyle, que é acessível em qualquer widget pelo método homonimo style.

O método de pintura do texto é, por fim, o paint_layout, que vai fazer toda a magia negra necessária para fazer o texto aparecer com os glyphs específicos (mesmo que voce escreva em japonês).

Código de Exemplo

 #!/usr/bin/perl
 use strict;
 use warnings;
 use Gtk2 qw(-init -threads-init);

 my $canvas_width = 0;
 my $canvas_height = 0;

 my $mainwindow = Gtk2::Window->new("toplevel");
 my $draw = Gtk2::DrawingArea->new();
 $draw->signal_connect(expose_event => \&drawit);
 $draw->signal_connect(configure_event => \&configureit);
 $mainwindow->add($draw);
 $mainwindow->show_all();
 Gtk2->main();




 sub configureit {
         my $draw = shift;
         my $event = shift;
         $canvas_width = $event->width;
         $canvas_height = $event->height;
 }

 sub drawit {
         my $draw = shift;
         my $event = shift;
         my ($x,$y,$w,$h) = ($event->area->x, $event->area->y, $event->area->width, $event->area->height);
         # Obtendo o Graphic Context do widget.
         my $gc = $draw->style->fg_gc($draw->state);
         # Limpando a área a ser pintada.
         $draw->window->clear_area($x, $y, $w, $h);
         # Vou mexer só na parte que precisa ser atualizada
         $gc->set_clip_rectangle(Gtk2::Gdk::Rectangle->new($x, $y, $w, $h));

         # Pintar o fundo de branco.
         $gc->set_rgb_fg_color(Gtk2::Gdk::Color->new(255*257,255*257,255*257));
         $draw->window->draw_rectangle($gc,1,0,0,$canvas_width,$canvas_height);
         $gc->set_rgb_fg_color(Gtk2::Gdk::Color->new(0,0,0));

         # obter o Pango Context
         my $pangoc = $draw->get_pango_context();
         # criar o Font Description
         my $fontdesc = Gtk2::Pango::FontDescription->from_string("Sans 10");
         # Criar o layout
         my $layout = Gtk2::Pango::Layout->new($pangoc);
         # definir a fonte
         $layout->set_font_description($fontdesc);
         # definir o texto
         $layout->set_text("Algum Texto áæß");
         # Desenhar...
         my $rect = Gtk2::Gdk::Rectangle->new(int($canvas_width/2)-75+2,int($canvas_height/2)-100+2,146,20);
         $draw->style->paint_layout($draw->window,$draw->state,1,$rect,undef,undef,$rect->x,$rect->y,$layout);




         # Desfazendo o clip
         $gc->set_clip_rectangle(undef);
 }




AUTHOR

Daniel Ruoso

blog comments powered by Disqus