Dibujar con Cairo en tus extensiones

Este es uno de los capítulos del tutorial Crea tu propia extensión para GNOME Shell. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.

Para poder dar la máxima información al usuario de la forma mas sencilla posible es inevitable recurrir a los gráficos. Esta solución permite que de un solo vistazo el usuario sepa como está por ejemplo el uso de sus particiones. Ahora bien, para conseguir estas soluciones tan particulares tenemos que trabajar un poco mas. Necesitamos recurrir a Cairo.

Soy consciente de que introducir Cairo así de buenas a primeras puede ser algo desconcertante, sobre todo para aquel que se introduce en el desarrollo de extensiones para GNOME Shell. Sin embargo, no es una librería desconocida, para aquel que desarrolla en el ecosistema de GNOME. Y en el caso de que seas un desarrollador novel, en seguida verás las posibilidades que te ofrece Cairo para mejorar el aspecto visual de tus aplicaciones. Cairo, te permitirá llevar tus aplicaciones a otro nivel…

Dibujar con Cairo

¿Que es Cairo?

Cairo es una librería gráfica 2D que nos permite sacar información por diferentes medios. Así, por ejemplo, podemos trabajar directamente en imágenes, dibujar mediante aceleración por hardware con OpenGL, generar archivos PostScript. Igualmente, también podemos generar archivos vectorizados en PDF. Y al igual que podemos hacer con archivos PDF también podemos hacer con archivos SVG. También utiliza la interfaz Xlib para sacar imágenes al sistema X Windows.

Esto tiene la ventaja que con un mismo procedimiento puedes obtener el mismo resultado en diferentes medios. Así, puedes generar un archivo PDF o mostrar un gráfico en pantalla. Con la ventaja de que podemos utilizar la aceleración por hardware en aquellos dispositivos que lo permitan.

Por otro lado la API de cairo facilita operaciones similares a los operadores utilizados en PostScript y PDF. Las operaciones en Cairo, incluyen tanto la generación de líneas y curvas, como figuras geométricas, tanto el borde de las mismas, como su relleno. Por otro lado, también permite la transformación, como puede ser el escalado, rotación, traslación, etc.

Cairo está implementado en C, pero existe interfaz para muchos lenguajes de programación. Así, puedes utilizar Cairo desde Python o JavaScript entre otros.

¿Porque utilizar Cairo?

Como he comentado en la introducción, la mejor manera de mostrar información al usuario es gráficamente. Solo tenemos que recordar el dicho de mas vale una imagen que mil palabras (en nuestro caso mil números).

Pero además a esto, le tenemos que unir lo que hemos comentado en el punto anterior, y es que podemos convertir fácilmente esa salida que vemos por pantalla en un informa PDF…. Interesante, ¿no te parece?

Cairo y GNOME Shell

Estoy en el proceso de desarrollar diferentes extensiones para GNOME Shell. En ese proceso, y para mostrar información relevante al usuario estoy utilizando precisamente Cairo. Por ejemplo, en uno de los casos, lo que estoy es mostrando la situación de las diferentes particiones que tenemos montadas en nuestro equipo. Esto se muestra mediante un anillo, que en función de lo lleno que está la partición aparecerá mas o menos completo. Por otro lado, y desde el punto de vista de la productividad, estoy implementando Pomodoro-Indicator para GNOME Shell. El objetivo es que de forma gráfica, puedas ver cuantos pomodoros has consumido, cuanto tiempo te queda del que estás haciendo ahora, etc.

Clutter.Canvas

En el caso de GNOME Shell podemos utilizar Clutter.Canvas. Mediante este tipo de objeto podemos implementar nuestros dibujos. ¿Como hacerlo?. Para implementar nuestros dibujos, utilizaremos el evento draw. Dado que GNOME Shell, utiliza JavaScript para su implementación, el siguiente ejemplo utiliza este lenguaje,

canvas.connect('draw', (canvas, cr, width, height) =>{
    cr.setSourceRGBA(1, 1, 1, 1);
    cr.rectangle(0, 0, width, height);
    cr.fill();
}

En este sencillo ejemplo, hemos dibujado un cuadrado de color negro, de las dimensiones definidas por el propio canvas. ¿Sencillo verdad?

Podemos dibujar diferentes formas geométricas, así como líneas y curvas y por supuesto texto.

Respecto al texto, y para conseguir que este estuviera centrado, he tenido que escribir un poquito mas de código. Además he tenido que utilizar una librería extra que es PangoCairo. Lo cierto es que me ha llevado un tiempo descubrir como resolver este problema. Te indico a continuación como puedes hacer para centrar texto,

write_centered_text(cr, x, y, text, font, size){
    let pg_layout = PangoCairo.create_layout(cr);
    let pg_context = pg_layout.get_context();
    pg_layout.set_font_description(
        Pango.FontDescription.from_string('%s %s'.format(font, size)));
    pg_layout.set_text(text, -1);

    PangoCairo.update_layout(cr, pg_layout);
    let text_size = pg_layout.get_pixel_size();

    cr.moveTo(x - text_size[0]/2, y - size/2);
    cr.setFontSize(size);
    cr.showText(text);
}

Así de primeras te puede resultar curioso, pero no si sigues el código verás que tiene toda su lógica.

Gtk.DrawingArea

La otra clase apropiada para implementar tus dibujos es Gtk.DrawingArea. En este caso, y para terminar de despistarte, voy a comentarlo en Python, porque todavía sigo muy apegado a este lenguaje de programación para desarrollar las aplicaciones en el escritorio. Todo ello, a pesar de las recomendaciones de los desarrolladores de GNOME para que utilicemos JavaScript…. pero, poco a poco.

En el caso de la clase Gtk.DrawingArea también se hace uso del evento draw para realizar los dibujos. Por ejemplo,

class MiAreaDeDibujo(Gtk.DrawingArea):
    def __init__(self):
        self.connect('draw', self.on_expose, None)

    def on_expose(self, widget, cr, data):
        cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
        cr.rectangle(0, 0, self.get_allocated_width(), self.get_allocated_height())
        cr.fill()

Como ves la implementación tanto en JavaScript como en Python es muy similar. Aunque tengo que confesarte, que para mi sigue siendo mas sencillo en Python. Y sigue siendo mas sencillo en Python, por dos razones. Por un lado, porque llevo mucho mas tiempo desarrollando en este lenguaje, pero por otro, y quizá mas importante, porque actualmente está mucho mejor documentado.

Esto que acabo de implementar en Python, también lo podemos hacer en JavaScript, para que te puedas hacer una idea de su parecido.

drawingArea = new Gtk.DrawingArea();
drawingArea.connect('draw', (widget, cr)=>{
    cr.setSourceRGBA(1.0, 1.0, 1.0, 1.0);
    cr.rectangle(0,
                 0,
                 this.get_allocated_width(),
                 this.get_allocated_height());
    cr.fill();
});

Me encanta la sencilla de JavaScript para asociar funciones a eventos… esto es algo, que me resulta realmente cómodo… aunque la parte de this todavía me lleva un poco despistado.

Conclusiones

Espero que a pesar de mis divagaciones con Python y JavaScript, te habrás podido hacer una idea del potencial que tiene Cairo para poder representar de forma gráfica información. Si con estas pocas líneas de código no han sido suficientes para convencerte de las posibilidades, en breve liberaré dos extensiones para GNOME Shell.

Estas dos extensiones te proporcionarán una mejor idea de como exprimir al máximo el potencial de Cairo. Una de las herramientas es Disk Usage Space. Se trata de un sencillo indicador para Ubuntu que te muestra el estado de llenado de las particiones de tu equipo. Esto se hace de forma gráfica y con colores totalmente personalizables. La otra de las herramientas tal y como he adelantado es Pomodoro Indicator. Esta vez Pomodoro Indicator será para GNOME Shell, aprovechando todas las posibilidades que nos ofrece la API. Verás como es posible, de una forma gráfica, aumentar tu productividad hasta límites inimaginables…

Sin embargo, lo mas importante que te debes llevar al leer este artículo, es las tremendas posibilidades que Cairo nos ofrece para representar de forma gráfica y sencilla, información. Quizá me ha quedado pendiente, las posibilidades que ofrece para exportar a otros formatos como puede ser a una imagen o un archivo PDF. Esto podría ser realmente interesante para guardar la evolución del espacio en tus discos de forma totalmente gráfica y visual… pero, todo se andará….


Más información,
* Cairo

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *