vai alla Homepage di Apogeonline

 



Cos'è OpenPress
Glossario
Linux-FAQ
Documenti:

Open Source Definition

GNU General Public License

La cattedrale e il bazaar

Colonizzare la noosfera

Il calderone magico


Libri:

Italian crackdown

Open Sources

MediaMorfosi

GTK+/GNOME
sviluppo applicazioni


Telematica per la pace

Linux HOWTO: Installazione e configurazione

Linux HOWTO: Networking


Risorse
Feedback
vai alla Homepage di Apogeo Editore

Vai alla homepage di OpenPress

GTK+ / Gnome Sviluppo di Applicazioni


Funzioni grafiche

Una volta che avete capito il funzionamento dei drawable, colori, visual, GC e font, disegnare diventa veramente semplice. In questa sezione troverete un veloce riassunto delle routine di disegno di GDK. Ricordate che disegnare è un operazione sul lato server; per esempio, se chiedete di disegnare una linea, Xlib spedirà gli estremi della linea al server, e il server compierà l'azione di disegno usando il GC specificato (anche il GC risiede sul lato server). Spesso, queste considerazioni aiutano a migliorare la performance.

Punti

Potete disegnare un punto con la funzione gdk_draw_point(), oppure punti multipli con gdk_draw_points() ( Figura 17 ). Il punto è disegnato nel colore di foreground attualmente selezionato. Punti multipli vengono forniti come array. Un GdkPoint è definito come segue:


typedef struct _GdkPoint GdkPoint;

struct _GdkPoint
{
  gint16 x;
  gint16 y;
};

Ricordate che le coordinate di X hanno origine nell'angolo in alto a sinistra, sono relative al drawable e devono "stare" in un intero a 16 bit con segno.

#include <gdk/gdk.h>

void gdk_draw_point(GdkDrawable* drawable, GdkGC* gc, gint x, gint y);

void gdk_draw_points(GdkDrawable* drawable, GdkGC* gc, GdkPoint* points, gint npoints);

Figura 17. Disegno di punti

Linee

Per disegnare una linea singola, passate i sui estremi come argomenti di gdk_draw_line() ( Figura 18 ). Per disegnare linee connesse, passate una lista di punti a gdk_draw_lines(); GDK connetterà i punti. Per disegnare linee multiple che non sono necessariamente connesse, passate una lista di segmenti a gdk_draw_segments(); un GdkSegment è definito come:


typedef struct _GdkSegment GdkSegment;

struct _GdkSegment
{
  gint16 x1;
  gint16 y1;
  gint16 x2;
  gint16 y2;
};

Se linee o segmenti si intersecano nagli estremi, vengono unite con lo stile specificato nel GC.

#include <gdk/gdk.h>

void gdk_draw_line(GdkDrawable* drawable, GdkGC* gc, gint x1, gint y1, gint x2, gint y2);

void gdk_draw_lines(GdkDrawable* drawable, GdkGC* gc, GdkPoint* points, gint npoints);

void gdk_draw_segments(GdkDrawable* drawable, GdkGC* gc, GdkSegment* segments, gint nsegments);

Figura 18. Disegno di linee

Rettangoli

I rettangoli vengono disegnati con la funzione gdk_draw_rectangle() ( Figura 19 ). L'argomento filled specifica se il rettangolo deve essere riempito; TRUE indica di riempirlo.

#include <gdk/gdk.h>

void gdk_draw_rectangle(GdkDrawable* drawable, GdkGC* gc, gint filled, gint x, gint y, gint width, gint height);

Figura 19. Disegno di rettangoli.

Archi

gdk_draw_arc() disegna un ellisse oppure una porzione di essa. ( Figura 20 ). L'arco può essere riempito oppure no; il terzo argomento specifica se farlo. Gli argomenti dal quarto al settimo descrivono un rettangolo; l'ellisse viene inscritta in questo rettangolo. angle1 è l'angolo in corrispondenza del quale il disegno deve iniziare; è relativo alla posizione delle 3 dell'orologio (quindi 0 radianti). angle2 è la distanza da percorrere lungo l'arco; se positiva, il viaggio è in senso orario, altimenti in senso antiorario. Entrambi i numeri sono espressi in sessantaquattresimi di grado; quindi 360 gradi sono descritti come 360*64. Questo permette una specificazione più precisa senza dover utilizzare numeri in virgola mobile. angle2 dovrebbe essere minore di 360 gradi.

Per disegnare una circonferenza, disegnate da 0 a 360*64 dentro un quadrato.


  gdk_draw_arc(drawable, gc, TRUE,
               0, 0,
               50, 50,
               0, 360*64);

Per disegnare un ellisse cambiate il rapporto tra i lati e dimezzate la lunghezza dell'arco:


  gdk_draw_arc(drawable, gc, TRUE,
               0, 0,
               100, 50,
               0, 180*64);

Molti server X disegnano i bordi degli archi in un modo esteticamente scadente; in particolare, circonferenze molto piccole possono non essere poi così tonde.

#include <gdk/gdk.h>

void gdk_draw_arc(GdkDrawable* drawable, GdkGC* gc, gint filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2);

Figura 20. Disegno di archi

Poligoni

gdk_draw_polygon() disegna un poligono riempito oppure non. ( Figura 21 ). Notate che per disegnare un poligono non riempito potete utilizzare anche la funzione gdk_draw_lines() (la scelta è totalmente indifferente). Gli argomenti di gdk_draw_polygon() sono simili a quelli di gdk_draw_lines(). Il poligno non deve essere per forza convesso. Può anche intersecare se stesso. I poligoni auto-intersecanti sono riempiti con la regola del "pari e dispari" (even-odd rule) la quale specifica che i poligoni che sono formati da un numero pari di poligoni sovrapposti non vengono riempiti. Quindi, se il poligono non si sovrappone a se stesso, viene riempito completamente. Se una regione si sovrappone a un altra, non viene riempito.

#include <gdk/gdk.h>

void gdk_draw_polygon(GdkDrawable* drawable, GdkGC* gc, gint filled, GdkPoint* points, gint npoints);

Figura 21. Disegno di poligoni

Testo

Ci sono due funzioni per disegnare stringhe; come ottimizzazione, gdk_draw_text() accetta la lunghezza della stringa da disegnare. gdk_draw_string() utilizza strlen() per calcolare la lunghezza al posto vostro. Per il resto, le due funzioni sono identiche. Le coordinate x e y specificano la posizione del lato sinistro della linea di base del testo. Consultate la sezione I font per maggiori informazioni sui font e sulle metriche. Il testo viene disegnato con il colore di foreground.

Non esiste modo di disegnare testo scalato o ruotato con GDK. GnomeCanvasText offre un modo lento e di bassa qualità per disegnare testo ruotato o scalato (vedere la sezione Oggetti testuali nel il capitolo GnomeCanvas ). Se avete bisogno di scaling di qualità dovrete utilizzare librerie aggiuntive, come la libreria t1lib per i font di Tipo 1 oppure FreeType per font True Type. Un altra possibilità è quella di utilizzare l'estensione Postscript di X (XDPS); Il progetto GNU lavora su una implementazione libera di XDPS. Anche il progetto Gnome ha una soluzione in via di sviluppo, come parte della libreria gnome-print.

#include <gdk/gdk.h>

void gdk_draw_string(GdkDrawable* drawable, GdkFont* font, GdkGC* gc, gint x, gint y, const gchar* text);

void gdk_draw_text(GdkDrawable* drawable, GdkFont* font, GdkGC* gc, gint x, gint y, const gchar* text, gint text_length);

Figura 22. Disegno di testo

Pixmap

gdk_draw_pixmap() copia una regione da una pixmap a un altro drawable (pixmap o finestra). I drawable di origine e destinazione devono avere la stessa profondità e visual. Se passate -1 come lunghezza o altezza, viene utilizzata la dimensione totale della pixmap sorgente. La sorgente può essere un drawable qualunque, compreso una finestra, ma gdk_window_copy_area() renderà il vostro codice più chiaro se l'origine è una finestra. Figura 23 mostra gdk_draw_pixmap().

#include <gdk/gdk.h>

void gdk_draw_pixmap(GdkDrawable* drawable, GdkGC* gc, GdkDrawable* src, gint xsrc, gint ysrc, gint xdest, gint ydest, gint width, gint height);

Figura 23. Disegno di pixmap

Buffer RGB

Il modulo GdkRGB di GDK permette di copiare un immagine sul lato client dentro un drawable. Se avete bisogno di manipolare intensivamente le immagini, oppure copiare immagini verso il server, questo è il modo corretto di farlo. Non potete manipolare direttamente una GdkPixmap poiché essa è un oggetto che risiede sul lato server. Copiare i dati dell'immagine verso il server con la funzione gdk_draw_point() sarebbe incredibilmente lento poiché ogni punto richiederebbe un messaggio verso il server (probabilmente più di uno, poiché dovrete modificare il GC per ogni punto).

Internamente, GdkRGB usa un oggetto chiamato GdkImage per copiare velocemente i dati verso il server in una richiesta singola. Questo è ancora abbastanza lento ma GdkRGB è molto ottimizzato e utilizzerà la memoria condivisa se il client e il server sono sulla stessa macchina. Questo diventa il modo più semplice, data l'architettura di X.

Le funzioni di GdkRGB sono dichiarate in un header separato, gdk/gdkrgb.h. Prima di utilizzare una qualunque funzione di GdkRGB, dovete inizializzare il modulo con gdk_rgb_init() ( Figura 24 ); questo permette l'allocazione di alcune strutture dati interne di GdkRGB.

Il drawable di cui volete copiare il buffer RGB deve usare il visual e la colormap di GdkRGB. Se il drawable è parte di un widget, il modo più semplice è fare il push del visual e del drawable prima di creare il widget.


  GtkWidget* widget;
  gtk_widget_push_visual(gdk_rgb_get_visual());
  gtk_widget_push_colormap(gdk_rgb_get_cmap());
  widget = gtk_whatever_new();
  gtk_widget_pop_visual();
  gtk_widget_pop_colormap();

La versione attuale di GTK+ si comporta meglio se lo fate durante la creazione della finestra toplevel che contiene il drawable. In linea di principo, comunque, potete farlo per il drawable specifico.

GdkRGB comprende diversi tipi di dati immagine, compresi i dati a 24 e 32 bit , dati a 8 bit in scala di grigi, e dati indicizzati a 8 bit (una GdkRgbCmap). In questa sezione viene descritto soltanto il caso più semplice, quello dei dati a 24-bit. Questo tipo di buffer viene renderizzato con gdk_draw_rgb_image(). Esistono funzioni separate per renderizzare altri tipi di buffer, ma tutte funzionano più o meno nello stesso modo.

Un buffer a 24-bit è un array di byte a una dimensione; ogni tripletta di byte forma un pixel (il byte 0 è il rosso,il byte 1 è il verde, il byte 2 è il blu). Tre numeri descrivono la dimensione dell'array e la locazione dei byte al suo interno:

  • width è il numero di pixel (triplette di byte) per ogni riga nell'immagine.

  • height è il numero delle righe.

  • rowstride è il numero del byte tra le righe. Cioè, per un buffer con rowstride r, se la riga n inizia alla posizione i nell'array, la riga n+1 inizia nella posizione i+r. Il rowstride non è necessariamente il triplo della larghezza in pixel del buffer; GdkRGB è più veloce se il puntatore dell'origine e il rowstride sono allineati sul confine dei 4 byte.

Gli argomenti x, y, width, e height della funzione gdk_rgb_draw_image() definiscono una regione del drawable di destinazione in cui copiare il buffer RGB. Il buffer deve avere almeno width colonne e height righe. Il pixel alla riga 0, colonna 0 del buffer verrà copiato nel punto (x, y) del drawable.

Il dithering simula un alto numero di colori sui display con una palette limitata. Il dithering ha significato soltanto sui display a 8 e 16 bit. I display a 24 bit non hanno una palette limitata. L'argomento dither è un tipo enumerato; ha tre possibili valori:

  • GDK_RGB_DITHER_NONE indica di non applicare alcun dithering. É appropriato per testo oppure disegno di linee con pochi colori, inappopriato per immagini fotografiche.

  • GDK_RGB_DITHER_NORMAL specifica il dithering per display a 8 bit, ma non per display a 16 bit. Fornisce di solito il miglior rapporto qualità/performance.

  • GDK_RGB_DITHER_MAX specifica che il dithering sarà fatto per display a 8 e 16 bit. Il guadagno sui display a 16 bit probabilmente non compensa la perdita di velocità.

L'argomento gc di gdk_draw_rgb_image() è semplicemente passato a gdk_draw_image() (ricordate che GdkRGB usa GdkImage intenamente). Vengono usati i componenti significativi del GC (la clip mask, la funzione di disegno e il subwindow mode).

#include <gdk/gdkrgb.h>

void gdk_rgb_init(void);

GdkColormap* gdk_rgb_get_cmap(void);

GdkVisual* gdk_rgb_get_visual(void);

void gdk_draw_rgb_image(GdkDrawable* drawable, GdkGC* gc, gint x, gint y, gint width, gint height, GdkRGBDither dither, guchar* rgb_buf, gint rowstride);

Figura 24. GdkRGB


Copyright © 1995-1999 Apogeo srl, Milano