Lo sappiamo. Siamo ripetitivi.
Un altro articolo su esperienze di programmazione MacOSX sembra eccessivo e fuori luogo in questo sito che dovrebbe essere dedicato all’ibridazione.
E invece vi sbagliate di grosso.
Per settimana ho cercato su Internet informazioni per realizzare una NSCell (e per esigenze di editabilità del valore che sia derivazione di NSTextFieldCell) capace di avere il ArrowLinkButton (se si chiama così) come in iTunes: ho trovato di tutto, ma nulla che fosse del minimo aiuto. La cosa che più si avvicinava era un progetto (http://sunflower.coleharbour.ca/cocoamondo/2008/12/the-mondotextfield-a-formal-introduction/) per un bottone in una TextFieldCell capace di aprire una finestra come Quick Look.
Provando a seguire quelle linee guida mi sono ritrovato in un vicolo cieco quando il tutto, collocato all’interno di una TableView quale sua collocazione naturale, mostrava tutta la astrusità dell’implementazione quando nell’aggiornamento delle celle di tutta la tabella si aveva un fastidioso “flickering” dell’oggetto Button collocato in bella mostra sulla TextFieldCell e anzi si notava proprio il tempo di disegno del bottone.
Qualcosa ho studiato, e mi rendo conto del diverso peso (nell’architettura Cocoa) di un oggetto NSCell rispetto ad un oggetto NSButton e della dicotomia nell’uso della ereditarietà di certi oggetti Cocoa rispetto ai due questi oggetti. L’implementazione corretta doveva dunque passare per un NSButtonCell e riferirsi ad un NSControl generale che sbrigasse le questioni degli eventi, perché la mia è questione estetica, e le questioni estetiche le cura prevalentemente un oggetto di derivazione NSCell.
Ora so che l’intuizione era quella giusta, ma non avevo nessun esempio sotto mano che mi facesse vedere in concreto come personalizzare oggetti NSCell nella maniera in cui serviva a me, ne tanto meno come sbrigare la gestione di eventi in relazione al contesto particolarissimo in cui collocavo la mia implementazione, ossia una NSTableView.
La documentazione ADC è fatta abbastanza bene, ma è carente di grafici che pongano in relazione non tanto le classi, quanto il flusso di eventi in relazioni a oggetti e loro metodi, ed in particolare quelli invocati dall’implementazione per proprio conto (direi metodi di implementazione) e quelli di delega.
Manca il “chi fa cosa” e “perché lo fa”.
Lo si deve ricostruire con esperienza, prove o suggerimenti.
E proprio questi andavo cercando.
Poi il lampo di genio (o semplice fortuna): mi sono ricordato che in Cocoa esiste un elemento derivato da NSCell che ha l’aspetto e il comportamento di quello che stavo tentando di realizzare. Si tratta della NSSearchFieldCell (http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSSearchFieldCell_Class/Reference/Reference.html).
Perfetto! mi dico. Ma come implementare un oggetto simile?
Dalla documentazione non si ricava mai nulla sul “come” implementare, ovvio; e allora un altro lampo (mi sa che devo cambiare la lampadina della scrivania: queste intermittenze sono fastidiose): GNUStep !!!
Nel progetto Open Source che noi amiamo deve esserci il sorgente di una implementazione di tale oggetto (presente fin dal 10.1). Ed infatti c’è: ovviamente un bel NSSearchFieldCell.m.
Cominciando a studiare il sorgente ho capito molte più cose di tante chiacchiere apparse sul web che a questo punto posso definire futili se non inutili.
La questione è ora semplice: una personalizzazione di NSTextFieldCell mi consente di aggiustare la dimensione nominale della cella testo (metodi -editWithFrame:inView:editor:delegate:event: e -selectWithFrame:inView:editor:delegate:start:length:) e aggiungerne di altre (di altro tipo, come pulsanti, ovvero NSButtonCell). Poi mi occorre personalizzare il metodo -mouseDown: del NSControl che detiene la NSTextFieldCell (e nel mio caso si tratta di una NSTableView) al fine di gestire il primo click a favore di pulsanti interni alla cella, altrimenti “consumato” dal NSControl per la gestione della selezione della specifica riga/cella nella tabella. Infine mi occorre personalizzare il controllo degli eventi mouse per il bottone all’interno della cella (-trackMouse:inRect:ofView:untilMouseUp:) al fine di gestire accettabilità del “click” e transizioni intermedie nell’aspetto del pulsante.
La questione sul cosa fare quando poi il pulsante è premuto diviene una questione di target/action abbastanza nota: inutile soffermarci.
L’analisi del comportamento del ArrowLinkButton in iTunes impone infine l’adozione di un metodo delega che consenta la manipolazione dell stato di visualizzazione del pulsante (disabilitato) sulla riga attualmente in uso (“play-mode”, parlando di iTunes).
Qualche sforzo si è dovuto comunque sostenere per ottenere l’aspetto estetico del pulsante nei suoi 3 stati: visualizzato in una cella selezionata, visualizzato in una cella non selezionata, visualizzato in una cella selezionata e a sua volta selezionato (mouse down senza mouse up). Per questo ci è venuto incontro TheGIMP!, naturalmente.
E’ stato impossibile usare direttamente NSFollowLinkFreeTemplate (disponibile nel framework 10.5, ma non 10.4) che non rende esteticamente allo stesso modo di iTunes, anche e non solo per il fatto che non si è voluto interferire con il meccanismo di evidenziazione della cella/riga (implementato probabilmente da NSTableView più che da NSTextFieldCell).
Il risultato (immagine a destra) direi che è soddisfacente rispetto alla versione iTunes (immagine a sinistra), in termini estetici e di efficienza del codice.
La cosa è talmente semplice che ora la sto estendendo per avere anche il checkbox prima del testo proprio come sono le celle nella colonna “titolo” in iTunes.
La cosa sarà ovviamente ripresa per realizzare versioni specializzate delle celle per una NSOutlineView al fine di avere il BagCounter, EjectButton, FollowLinkButton, e tante altre “cosucce” presenti nelle SourceListView di iTunes e del mondo iLife in generale.
E questo lo si deve essenzialmente al lavoro di chi ha ricreato in Open Source il framework Cocoa (o quasi), ovverosia al progetto GNUStep, che in questo caso mi consente e ci consente di offrire un nuovo oggetto grafico per MacOSX e per GNUStep: un iTunesTextFieldCell.