2013-04-18 15 views
7

Il valore predefinito per [NSTextView selectedTextAttributes] è inutilizzabile nella mia app, perché consente all'utente di selezionare i colori (evidenziazione della sintassi) che sono quasi esattamente come il colore di sfondo.Come posso impostare [NSTextView selectedTextAttributes] su una finestra di sfondo?

ho scritto un po 'di matematica per determinare un colore adatto e posso usare questo per impostarlo:

textView.selectedTextAttributes = @{ 
    NSBackgroundColorAttributeName: [NSColor yellowColor], 
    NSForegroundColorAttributeName: [NSColor redColor] 
    }; 

Ma quando la finestra è in background, si utilizza ancora il grigio chiaro di default del sistema.

Ho allegato schermate del codice precedente con finestra attiva e inattiva. - Come posso cambiare il colore di sfondo del testo selezionato della finestra inattiva?

active inactive

+0

Avete provato la sottoclasse di NSWindow e l'esecuzione di override di 'resignKeyWindow'? – CodaFi

+0

@CodaFi cosa devo fare in quel metodo? Ho appena provato a impostare selectedTextAttirbutes ma non ha alcun effetto. –

+1

Hm ... Controlla NSWindow.h. C'è un carico di funzioni che puoi usare per aggrapparti quando la finestra si dimette/ottiene lo stato della chiave. Puoi assegnare gli attributi da lì. – CodaFi

risposta

6

È possibile ignorare il colore sovrascrivendo il metodo di NSLayoutManager disegno.

final class LayoutManager1: NSLayoutManager { 
    override func fillBackgroundRectArray(rectArray: UnsafePointer<NSRect>, count rectCount: Int, forCharacterRange charRange: NSRange, color: NSColor) { 
     let color1 = color == NSColor.secondarySelectedControlColor() ? NSColor.redColor() : color 
     color1.setFill() 
     super.fillBackgroundRectArray(rectArray, count: rectCount, forCharacterRange: charRange, color: color1) 
     color.setFill() 
    } 
} 

E sostituire il gestore di layout di NSTextView ad esso.

textView.textContainer!.replaceLayoutManager(layoutManager1) 

Ecco full working example.


quanto @ Kyle chiede ragione di setFill, aggiungo qualche aggiornamento.

Da manuale di Apple:

... il charRange e parametri di colore sono passati a solo scopo informativo; il colore è già impostato nello stato della grafica. Se per qualsiasi motivo lo modifichi, devi ripristinarlo prima del che ritorna da questo metodo. ...

che significa passare in altri colori in super chiamata non ha alcun effetto, e solo bisogno di NSColor.setFill per farlo funzionare con super chiamata. Inoltre, il manuale richiede di riportarlo a quello originale.

+0

Solo curioso, perché chiamare 'setFill'? Mi aspetto che passare il nuovo colore a 'fillBackgroundRectArray' gestirà tutto correttamente? – Kyle

+1

@Kyle Ho aggiornato la mia risposta per fornire quell'informazione. È troppo lungo per essere in commento. – Eonil

5

Non è quando la finestra è in background è quando non è selezionata la NSTextView. Non penso che tu possa cambiare questo comportamento. enter image description here

È possibile creare una stringa attribuita e aggiungere l'attributo NSBackgroundColorAttributeName all'intervallo del testo selezionato quando perde lo stato attivo. La stringa attribuita rimane dello stesso colore anche quando viene persa la messa a fuoco.

NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"hello world"]; 
[string addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:NSMakeRange(1, 7)]; 
[string addAttribute:NSBackgroundColorAttributeName value:[NSColor yellowColor] range:NSMakeRange(1, 7)]; 
[self.myTextView insertText:string]; 

enter image description here

EDIT Abhi Beckert: questo è come ho implementato questa risposta (nota ho anche dovuto disabilitare il costruito nel attributi del testo selezionato, oppure si sovrascrivono quelle Sto installando):

@implementation MyTextView 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    if (!(self = [super initWithCoder:aDecoder])) 
    return nil; 

    // disable built in selected text attributes 
    self.selectedTextAttributes = @{}; 

    return self; 
} 

- (id)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)container 
{ 
    if (!(self = [super initWithFrame:frameRect textContainer:container])) 
    return nil; 

    // disable built in selected text attributes 
    self.selectedTextAttributes = @{}; 

    return self; 
} 

- (void)setSelectedRanges:(NSArray *)ranges affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag 
{ 
    // remove from old ranges 
    for (NSValue *value in self.selectedRanges) { 
    if (value.rangeValue.length == 0) 
     continue; 

    [self.textStorage removeAttribute:NSBackgroundColorAttributeName range:value.rangeValue]; 
    } 

    // apply to new ranges 
    for (NSValue *value in ranges) { 
    if (value.rangeValue.length == 0) 
     continue; 

    [self.textStorage addAttribute:NSBackgroundColorAttributeName value:[NSColor yellowColor] range:value.rangeValue]; 
    } 

    [super setSelectedRanges:ranges affinity:affinity stillSelecting:stillSelectingFlag]; 
} 

@end 
+0

Grazie! Ho avuto il mio overclide di sottoclasse setSelectedRange: per applicare manualmente gli attributi all'archivio di testo, e quindi impostare il SelectedTextAttribtues su un dizionario vuoto, e funziona. Modificherò la tua risposta in un secondo per avere il codice che ho usato. –

+0

Felice di poterti aiutare! –

+0

Attenzione che l'impostazione degli attributi per l'archiviazione del testo significa che si salvano gli attributi come parte di un testo colorato, come avviene negli editor di testo RTF. Raccomanderei invece di utilizzare gli attributi temporanei di NSLayoutManager, che sono designati come target per lo stile transitorio. – ctietze

Problemi correlati