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.
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:
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.
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:
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.
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.
Molti server X disegnano i bordi degli archi in un modo esteticamente
scadente; in particolare, circonferenze molto piccole possono non essere
poi così tonde.
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.
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.
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().
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.
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).