Questa sezione introduce l'architettura del canvas, incluso l'inserimento dei suoi oggetti all'interno di gruppi, dotati di gerarchia, e il sistema di coordinate utilizzato.
Gli oggetti del canvas vengono organizzati in una struttura ad albero. È possibile raggruppare oggetti, per spostarli in gruppo. L'autore dell'architettura del canvas, Federico Mena Quintero, utilizza come esempio pratico un editor per i diagrammi di circuiti. Ciascun gruppo può contenere dei sotto-gruppi. Per ciascuno di questi, il canvas mantiene uno stack di ordinamento: oggetti che si trovano in alto nello stack oscurano gli oggetti che si trovano in basso.
Per implementare questo, il canvas fornisce un oggetto particolare, chiamato GnomeCanvasGroup. Come suggerisce il nome stesso, un CanvasGroup può raggruppare un serie di oggetti del canvas assieme in modo da manipolare tutti questi come un unico elemento. Un GnomeCanvasGroup è invisibile. Per visualizzare se stesso, visualizza ricorsivamente gli oggetti al suo interno. Quando create un nuovo GnomeCanvas, un gruppo di default, chiamato "root", verrà creato per voi. Tutti gli oggetti del canvas vengono aggiunti all'albero al di sotto del gruppo root. Il widget Canvas dialoga unicamente attraverso il gruppo root. Tutti gli elementi presenti vengono gestiti dall'elemento superiore.
Viene fornita una funzione accessoria per accedere al gruppo root del canvas, mostrata in
Figura 1
.
Gli oggetti devono sempre essere parte di un gruppo. Non esiste un oggetto canvas "orfano". Quando create un oggetto dovete specificare il gruppo di appartenenza. È inoltre possibile cambiare il gruppo dopo la creazione dell'oggetto. Tuttavia, gli oggetti sono permanentemente legati al GnomeCanvas all'interno del quale sono stati creati. Non è possibile scambiare oggetti tra canvas diversi.
Molte delle caratteristiche del canvas vengono implementate attraverso una traduzione fra diversi sistemi di coordinate. Gli oggetti del canvas possono essere spostati, ruotati, ridimensionati attraverso trasformazioni affini, descritte in dettaglio più avanti. Ecco i più importanti sistemi di coordinate che vengono utilizzate nel canvas e nella scrittura di oggetti personalizzati:
Le coordinate globali sono un sistema di coordinate assoluto. Ad esempio, una coordinata globale si riferisce sempre allo stesso punto del canvas. Queste sono concettualmente infinite e rappresentate tramite un double. Il sistema di coordinate globali è quello reale, di primo livello, non modificabile, canonico. Coerenti con il sistema X Window e GDK, la coordinata Y aumenta spostandosi verso il basso.
Le coordinate ad oggetto sono le coordinate utilizzate da particolari oggetti del canvas. Le coordinate ad oggetto esistono poiché ogni oggetto associa una trasformazione affina a queste. Nel caso del GnomeCanvasGroup, questa trasformazione viene applicata al gruppo figlio. Per convertire particolari elementi del gruppo dal sistema di coordinate globali a quello ad oggetto, è necessario applicare la trasformazione all'elemento di primo livello, iniziando dal gruppo root. Come le coordinate globali, le coordinate ad oggetto sono concettualmente infinite.
Le coordinate canvas sono le coordinate dei pixel. Mentre le coordinate globali e ad oggetto vengono indicate con numeri in virgola mobile, la coordinate canvas sono rappresentate da numeri interi. Per utilizzare il canvas, dovete specificare una regione di "scroll", che corrisponde ad un rettangolo di spazio, espresso in coordinate globali, visibile all'utente. Le coordinate canvas sono relative a questo rettangolo. Questo sistema di coordinate viene utilizzato anche per rappresentare il fattore di ridimensionamento, costituendo il numero di pixel per unità globale. La conversione da coordinate globali a canvas viene eseguita direttamente dal GnomeCanvas sottraendo le coordinate X e Y della regione di scroll, moltiplicando per il fattore di dimensione e quindi approssimando a un numero intero. Le coordinate canvas (0,0) rappresentano l'angolo in alto a sinistra della regione di scroll.
Le coordinate buffer sono le coordinate canvas modificate
da un riferimento. Alcune implementazioni degli oggetti del canvas
utilizzano queste coordinate durante la visualizzazione. Il canvas
fornisce all'oggetto un buffer (che può trattarsi di un GdkDrawable oppure di un buffer RGB, opzione dipendente dalla modalità del canvas). Il canvas fornisce all'oggetto indicazioni su quale regione dello schermo il buffer rappresenta (il buffer viene definito tramite un riferimento X e un riferimento Y, larghezza e altezza). I riferimento X e Y sono espressi in coordinate canvas, equivalenti a (0,0) in coordinate buffer. Per convertire le coordinate canvas a coordinate buffer, sottraete semplicemente il riferimento. Le coordinate buffer sono valide unicamente da (0,0) alla larghezza e altezza massime del buffer.
Le coordinate window vengono utilizzate
raramente. Il canvas copia eventualmente ciascun buffer temporanee in
una GdkWindow (per essere precisi,
vengono copiati in un GTK_LAYOUT(canvas)->bin_window). Le
coordinate window sono relative a questa GdkWindow. In alcuni rari casi è necessario disegnare la finestra direttamente utilizzando un oggetto canvas, oppure poter rispondere a un evento nella finestra (come il drag-and-drop). È necessario successivamente convertire le coordinate window in uno dei sistemi di coordinate precedentemente descritti.
Quando vengono utilizzati oggetti del canvas preesistenti, gli unici sistemi di coordinate interessati sono quello globale e quello ad oggetto. Quando scrivete un oggetto personalizzato, avrete inoltre necessità di utilizzare le coordinate canvas e buffer.
Esistono due modi per convertire i dati fra i vari sistemi di coordinate. Uno di
questi consiste nell'ottenere e utilizzare le trasformazioni affini
direttamente, come descritto nella sezione successiva del libro. Il metodo
più semplice consiste nell'utilizzare le funzioni fornite appositamente,
descritte ne . La conversione
tra i sistemi di coordinate canvas e ad oggetto richiede che queste siano
convertite prima in coordinate globali come stadio intermedio del processo.
Una affinitá è una matrice di trasformazione composta da sei numeri
reali che possono essere applicati a una coppia ordinata. A seconda dal contenuto dell'affinitá, il punto può essere:
Traslato - spostato a una distanza arbitraria in entrambe le dimensioni.
Ruotato per un determinato valore, espresso in gradi.
Scalato in base ad un fattore di scala.
Concettualmente, un'affinitá definisce la relazione fra i punti di un piano. Per
qualunque punto (A, B), l'affinitá definisce un singolo punto trasformato corrispondente. La corrispondenza è uno-a-uno, quindi utilizzando il punto manipolato è possibile risalire al punto originale.
Le trasformazioni affini possono assumere interessanti proprietà che e rendono
utili nella grafica computerizzata. Queste possono essere
composite, concatenate oppure
moltiplicate (i tre termini sono, in questo contesto,
sinonimi). È possibile comporre un qualunque numero di trasformazioni affini
per crearne una singola.
libart_lgpl contiene un modulo per la manipolazione
delle trasformazioni affini. Queste vengono rappresentate come un array di sei numeri a doppia precisione. Le funzione sono descritte in
Figura 3
.
art_affine_point() applica una trasformazione
affine a un singolo punto, tramite il secondo argomento (src) e il risultato viene copiato nel primo argomento (dst). Un ArtPoint consiste in una struttura molto semplice:
Una trasformazione affine può essere invertita. Se questa converte un punto nel sistema di coordinate A in punto per il sistema di coordinate B, il suo inverso converte punti dal sistema B al sistema A. art_affiner_invert() riempie il suo primo argomento con l'inverso del secondo.
art_affine_multiply() compone due trasfomazioni afini come descritto precedentemente in questa sezione, posizionando il risultato nel primo argomento.
Sono fornite quattro funzioni per crearle con particolari proprietà.
art_affine_identity() crea una trasformazione
affine identità. Applicare una identità a un punto non ha alcun effetto.
art_affine_rotate() fornisce una trasformazione per ruotare i punti di theta gradi.
art_affine_translate() fornisce una
trasformazione per traslare i punti tx nella dimensione X e ty nella dimensione Y.
art_affine_scale() fornisce una trasformazione per scalare il piano tramite i fattori dimensionali fortni ( un fattore uguale a 1.0 non esegue la scala, inferiore riduce le dimensioni, maggiori espande il piano).
art_affine_rectilinear() restituisce TRUE se la trasformazione ruota rettangoli allineati agli assi in modo che questi restino allienati. Quindi, la funzione restituisce TRUE se la rotazione corrisponde a 0, 90, 180 o 270 gradi.
Potete richiedere al widget canvas di calcolare un affinamento che converta le coordinate fra i vari sistemi presenti. Queste funzioni sono mostrate in
Figura 4
. Ciascuna di queste riempie un array che voi gli passate con il tipo di trasformazione richiesto.