2012-06-08 4 views
0

Я пытаюсь создать NSTextView, который ведет себя как серия страниц пишущей машинки - каждая страница имеет фиксированное количество доступных строк и столбцов.Жесткая упаковка в NSTextView

Основное представление идеально соответствует дисплею, который, в свою очередь, соответствует формату файла. Страницы заканчиваются символом формы '\f'. Например, два 4x4 страницы будут выглядеть при сохранении (пробелы между символами для удобства чтения):

T H I S \n 
P A G E \n 
I S \n 
F U L L \n 
\f 
N O T \n 
T H I S \n 
O N E \n 
\n 
\f 

Несколько вещей, чтобы заметить:

  • Newlines и форм-каналы не сосчитать в строк/столбцы всего
  • Линия короче, чем количество столбцов не заполняется конечными пробела (хотя они могут быть, если редактор работал в режиме перезаписи)
  • Страницы короче, чем количество строк являются проложенным ш Ith Newlines

Я попробовал несколько подходов, как преобразование текста в NSArray линиях и расщепление длинных линий на каждом textDidChange уведомления, а затем установить текст в сцепленные строки, но это действительно неэффективно, и теряет курсор если ввод текста происходит в любом месте, кроме конца документа.

В конце концов, я думаю, что мне бы хотелось, чтобы это было как большая страница, заполненная пробелами, а ввод текста происходит только в режиме перезаписи, но обертывается в конце строк. Я не знаю, с чего начать этот подход. Какие-либо предложения?

+0

Возможно, более простой вопрос? Я не уверен, лучшее место для решения этого вопроса - в текстовом представлении, диспетчере компоновки, наборе текста, текстовом хранилище или в другом месте. Может быть, только указатель в правильном направлении будет достаточно, чтобы понять остальное. – squidpickles

ответ

0

Я нашел приемлемое, если не идеальное решение для упаковки путем подкласса NSTextStorage.

Он ведет себя так, как ожидалось, при добавлении текста в конец документа, будь то вставка или ввод текста. Он также ведет себя при удалении или замене текста. Единственное место, которое немного странно, - это вставить текст в середину уже полных строк. Это вызовет обертку только до вставленный текст. Он отлично работает, но это означает, что продолжение ввода в этом положении приведет к созданию нескольких коротких строк.

Например, текст ниже обертывается в 20 столбцах. Исходный текст: x, а вставленный текст: o. Вставляемый текст начинается во второй строке, на восьмом символе.

xxxxxxxxxxxxxxxxxxxx 
xxxxxxx 
ooooooo 
ooooooo 
oooooooxxxxxxxxxxxxx 
xxxxxxxxxxxxxxxxxxxx 
xxxxxxxxxxxxxxxxxxxx 
xxxxxxxxxxxxxxxxxxxx 

код ниже:

- (void)breakLinesInArray:(NSMutableArray *)lines atLength:(NSUInteger)length 
charsPreceding:(NSUInteger)preceding charsFollowing:(NSUInteger)following 
{ 
    NSUInteger line = 0; 
    while (line < [lines count]) { 
     NSUInteger maxLineLength = length; 
     if (line == 0) { 
      maxLineLength = length - preceding; 
     } else if (line == [lines count] - 1) { 
      maxLineLength = length - following; 
     } 
     NSString *original = [lines objectAtIndex:line]; 
     if (maxLineLength > 0 && [original length] > maxLineLength) { 
      NSString *first = [original substringToIndex:maxLineLength]; 
      NSString *second = [original substringFromIndex:maxLineLength]; 
      [lines replaceObjectAtIndex:line withObject:first]; 
      [lines insertObject:second atIndex:line + 1]; 
     } 
     ++line; 
    } 
} 

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str 
{ 
    static const NSUInteger kMaxLineLength = 20; 
    NSString *text = [text_ string]; 
    NSUInteger firstLineStart = 0; 
    NSUInteger lastLineEnd = 0; 
    NSMutableArray *lines = [NSMutableArray arrayWithArray:[str componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]]; 
    [text getLineStart:&firstLineStart end:nil contentsEnd:&lastLineEnd forRange:range]; 
    NSUInteger firstLineStartFragmentLength = range.location - firstLineStart; 
    NSUInteger lastLineEndFragmentLength = lastLineEnd - (range.location + range.length); 
    [self breakLinesInArray:lines atLength:kMaxLineLength charsPreceding:firstLineStartFragmentLength charsFollowing:lastLineEndFragmentLength]; 
    NSString *newString = [lines componentsJoinedByString:@"\n"]; 
    NSInteger changeInLength = [newString length] - range.length; 
    NSInteger newLastLineLength = firstLineStartFragmentLength + lastLineEndFragmentLength + changeInLength; 
    if ((firstLineStartFragmentLength || lastLineEndFragmentLength) && newLastLineLength > (NSInteger)kMaxLineLength) { 
     newString = [@"\n" stringByAppendingString:newString]; 
     ++changeInLength; 
    } 
    [text_ replaceCharactersInRange:range withString:newString]; 
    [self edited:NSTextStorageEditedCharacters range:range changeInLength:changeInLength]; 
} 
Смежные вопросы