2016-08-12 19:49:17 +00:00
//
// HFTextRepresenter . m
// HexFiend_2
//
// Copyright 2007 ridiculous_fish . All rights reserved .
//
# import < HexFiend / HFTextRepresenter_Internal . h >
# import < HexFiend / HFRepresenterTextView . h >
# import < HexFiend / HFPasteboardOwner . h >
# import < HexFiend / HFByteArray . h >
# import < HexFiend / HFTextVisualStyleRun . h >
@ implementation HFTextRepresenter
- ( Class ) _textViewClass {
UNIMPLEMENTED ( ) ;
}
- ( instancetype ) init {
self = [ super init ] ;
NSColor * color1 = [ NSColor colorWithCalibratedWhite : 1.0 alpha : 1.0 ] ;
NSColor * color2 = [ NSColor colorWithCalibratedRed : .87 green : .89 blue : 1. alpha : 1. ] ;
_rowBackgroundColors = [ @ [ color1 , color2 ] retain ] ;
return self ;
}
- ( void ) dealloc {
if ( [ self isViewLoaded ] ) {
[ [ self view ] clearRepresenter ] ;
}
[ _rowBackgroundColors release ] ;
[ super dealloc ] ;
}
- ( void ) encodeWithCoder : ( NSCoder * ) coder {
HFASSERT ( [ coder allowsKeyedCoding ] ) ;
[ super encodeWithCoder : coder ] ;
[ coder encodeBool : _behavesAsTextField forKey : @ "HFBehavesAsTextField" ] ;
[ coder encodeObject : _rowBackgroundColors forKey : @ "HFRowBackgroundColors" ] ;
}
- ( instancetype ) initWithCoder : ( NSCoder * ) coder {
HFASSERT ( [ coder allowsKeyedCoding ] ) ;
self = [ super initWithCoder : coder ] ;
_behavesAsTextField = [ coder decodeBoolForKey : @ "HFBehavesAsTextField" ] ;
_rowBackgroundColors = [ [ coder decodeObjectForKey : @ "HFRowBackgroundColors" ] retain ] ;
return self ;
}
- ( NSView * ) createView {
HFRepresenterTextView * view = [ [ [ self _textViewClass ] alloc ] initWithRepresenter : self ] ;
[ view setAutoresizingMask : NSViewHeightSizable ] ;
return view ;
}
- ( HFByteArrayDataStringType ) byteArrayDataStringType {
UNIMPLEMENTED ( ) ;
}
- ( HFRange ) entireDisplayedRange {
HFController * controller = [ self controller ] ;
unsigned long long contentsLength = [ controller contentsLength ] ;
HFASSERT ( controller ! = NULL ) ;
HFFPRange displayedLineRange = [ controller displayedLineRange ] ;
NSUInteger bytesPerLine = [ controller bytesPerLine ] ;
unsigned long long lineStart = HFFPToUL ( floorl ( displayedLineRange . location ) ) ;
unsigned long long lineEnd = HFFPToUL ( ceill ( displayedLineRange . location + displayedLineRange . length ) ) ;
HFASSERT ( lineEnd >= lineStart ) ;
HFRange byteRange = HFRangeMake ( HFProductULL ( bytesPerLine , lineStart ) , HFProductULL ( lineEnd - lineStart , bytesPerLine ) ) ;
if ( byteRange . length = = 0 ) {
/ * This can happen if we are too small to even show one line * /
return HFRangeMake ( 0 , 0 ) ;
}
else {
HFASSERT ( byteRange . location <= contentsLength ) ;
byteRange . length = MIN ( byteRange . length , contentsLength - byteRange . location ) ;
HFASSERT ( HFRangeIsSubrangeOfRange ( byteRange , HFRangeMake ( 0 , [ controller contentsLength ] ) ) ) ;
return byteRange ;
}
}
- ( NSRect ) furthestRectOnEdge : ( NSRectEdge ) edge forByteRange : ( HFRange ) byteRange {
HFASSERT ( byteRange . length > 0 ) ;
HFRange displayedRange = [ self entireDisplayedRange ] ;
HFRange intersection = HFIntersectionRange ( displayedRange , byteRange ) ;
2017-01-22 19:53:52 +00:00
NSRect result = { { 0 , } , } ;
2016-08-12 19:49:17 +00:00
if ( intersection . length > 0 ) {
NSRange intersectionNSRange = NSMakeRange ( ll2l ( intersection . location - displayedRange . location ) , ll2l ( intersection . length ) ) ;
if ( intersectionNSRange . length > 0 ) {
result = [ [ self view ] furthestRectOnEdge : edge forRange : intersectionNSRange ] ;
}
}
else if ( byteRange . location < displayedRange . location ) {
/ * We ' re below it . * /
return NSMakeRect ( - CGFLOAT_MAX , - CGFLOAT_MAX , 0 , 0 ) ;
}
else if ( byteRange . location >= HFMaxRange ( displayedRange ) ) {
/ * We ' re above it * /
return NSMakeRect ( CGFLOAT_MAX , CGFLOAT_MAX , 0 , 0 ) ;
}
else {
/ * Shouldn ' t be possible to get here * /
[ NSException raise : NSInternalInconsistencyException format : @ "furthestRectOnEdge: expected an intersection, or a range below or above the byte range, but nothin'" ] ;
}
return result ;
}
- ( NSPoint ) locationOfCharacterAtByteIndex : ( unsigned long long ) index {
NSPoint result ;
HFRange displayedRange = [ self entireDisplayedRange ] ;
if ( HFLocationInRange ( index , displayedRange ) || index = = HFMaxRange ( displayedRange ) ) {
NSUInteger location = ll2l ( index - displayedRange . location ) ;
result = [ [ self view ] originForCharacterAtByteIndex : location ] ;
}
else if ( index < displayedRange . location ) {
result = NSMakePoint ( - CGFLOAT_MAX , - CGFLOAT_MAX ) ;
}
else {
result = NSMakePoint ( CGFLOAT_MAX , CGFLOAT_MAX ) ;
}
return result ;
}
- ( HFTextVisualStyleRun * ) styleForAttributes : ( NSSet * ) attributes range : ( NSRange ) range {
HFTextVisualStyleRun * run = [ [ [ HFTextVisualStyleRun alloc ] init ] autorelease ] ;
[ run setRange : range ] ;
[ run setForegroundColor : [ NSColor blackColor ] ] ;
return run ;
}
- ( NSArray * ) stylesForRange : ( HFRange ) range {
return nil ;
}
- ( void ) updateText {
HFController * controller = [ self controller ] ;
HFRepresenterTextView * view = [ self view ] ;
HFRange entireDisplayedRange = [ self entireDisplayedRange ] ;
[ view setData : [ controller dataForRange : entireDisplayedRange ] ] ;
[ view setStyles : [ self stylesForRange : entireDisplayedRange ] ] ;
HFFPRange lineRange = [ controller displayedLineRange ] ;
long double offsetLongDouble = lineRange . location - floorl ( lineRange . location ) ;
CGFloat offset = ld2f ( offsetLongDouble ) ;
[ view setVerticalOffset : offset ] ;
[ view setStartingLineBackgroundColorIndex : ll2l ( HFFPToUL ( floorl ( lineRange . location ) ) % NSUIntegerMax ) ] ;
}
- ( void ) initializeView {
[ super initializeView ] ;
HFRepresenterTextView * view = [ self view ] ;
HFController * controller = [ self controller ] ;
if ( controller ) {
[ view setFont : [ controller font ] ] ;
[ view setEditable : [ controller editable ] ] ;
[ self updateText ] ;
}
else {
[ view setFont : [ NSFont fontWithName : HFDEFAULT_FONT size : HFDEFAULT_FONTSIZE ] ] ;
}
}
- ( void ) scrollWheel : ( NSEvent * ) event {
[ [ self controller ] scrollWithScrollEvent : event ] ;
}
- ( void ) selectAll : ( id ) sender {
[ [ self controller ] selectAll : sender ] ;
}
- ( double ) selectionPulseAmount {
return [ [ self controller ] selectionPulseAmount ] ;
}
- ( void ) controllerDidChange : ( HFControllerPropertyBits ) bits {
if ( bits & ( HFControllerFont | HFControllerLineHeight ) ) {
[ [ self view ] setFont : [ [ self controller ] font ] ] ;
}
if ( bits & ( HFControllerContentValue | HFControllerDisplayedLineRange | HFControllerByteRangeAttributes ) ) {
[ self updateText ] ;
}
if ( bits & ( HFControllerSelectedRanges | HFControllerDisplayedLineRange ) ) {
[ [ self view ] updateSelectedRanges ] ;
}
if ( bits & ( HFControllerEditable ) ) {
[ [ self view ] setEditable : [ [ self controller ] editable ] ] ;
}
if ( bits & ( HFControllerAntialias ) ) {
[ [ self view ] setShouldAntialias : [ [ self controller ] shouldAntialias ] ] ;
}
if ( bits & ( HFControllerShowCallouts ) ) {
[ [ self view ] setShouldDrawCallouts : [ [ self controller ] shouldShowCallouts ] ] ;
}
if ( bits & ( HFControllerColorBytes ) ) {
if ( [ [ self controller ] shouldColorBytes ] ) {
[ [ self view ] setByteColoring : ^ ( uint8_t byte , uint8_t * r , uint8_t * g , uint8_t * b , uint8_t * a ) {
* r = * g = * b = ( uint8_t ) ( 255 * ( ( 255 - byte ) / 255.0 * 0.6 + 0.4 ) ) ;
* a = ( uint8_t ) ( 255 * 0.7 ) ;
} ] ;
} else {
[ [ self view ] setByteColoring : NULL ] ;
}
}
[ super controllerDidChange : bits ] ;
}
- ( double ) maximumAvailableLinesForViewHeight : ( CGFloat ) viewHeight {
return [ [ self view ] maximumAvailableLinesForViewHeight : viewHeight ] ;
}
- ( NSUInteger ) maximumBytesPerLineForViewWidth : ( CGFloat ) viewWidth {
return [ [ self view ] maximumBytesPerLineForViewWidth : viewWidth ] ;
}
- ( CGFloat ) minimumViewWidthForBytesPerLine : ( NSUInteger ) bytesPerLine {
return [ [ self view ] minimumViewWidthForBytesPerLine : bytesPerLine ] ;
}
- ( NSUInteger ) byteGranularity {
HFRepresenterTextView * view = [ self view ] ;
NSUInteger bytesPerColumn = MAX ( [ view bytesPerColumn ] , 1 u ) , bytesPerCharacter = [ view bytesPerCharacter ] ;
return HFLeastCommonMultiple ( bytesPerColumn , bytesPerCharacter ) ;
}
- ( NSArray * ) displayedSelectedContentsRanges {
HFController * controller = [ self controller ] ;
NSArray * result ;
NSArray * selectedRanges = [ controller selectedContentsRanges ] ;
HFRange displayedRange = [ self entireDisplayedRange ] ;
HFASSERT ( displayedRange . length <= NSUIntegerMax ) ;
NEW_ARRAY ( NSValue * , clippedSelectedRanges , [ selectedRanges count ] ) ;
NSUInteger clippedRangeIndex = 0 ;
FOREACH ( HFRangeWrapper * , wrapper , selectedRanges ) {
HFRange selectedRange = [ wrapper HFRange ] ;
BOOL clippedRangeIsVisible ;
NSRange clippedSelectedRange ;
/ * Necessary because zero length ranges do not intersect anything * /
if ( selectedRange . length = = 0 ) {
/ * Remember that { 6 , 0 } is considered a subrange of { 3 , 3 } * /
clippedRangeIsVisible = HFRangeIsSubrangeOfRange ( selectedRange , displayedRange ) ;
if ( clippedRangeIsVisible ) {
HFASSERT ( selectedRange . location >= displayedRange . location ) ;
clippedSelectedRange . location = ll2l ( selectedRange . location - displayedRange . location ) ;
clippedSelectedRange . length = 0 ;
}
}
else {
// selectedRange . length > 0
clippedRangeIsVisible = HFIntersectsRange ( selectedRange , displayedRange ) ;
if ( clippedRangeIsVisible ) {
HFRange intersectionRange = HFIntersectionRange ( selectedRange , displayedRange ) ;
HFASSERT ( intersectionRange . location >= displayedRange . location ) ;
clippedSelectedRange . location = ll2l ( intersectionRange . location - displayedRange . location ) ;
clippedSelectedRange . length = ll2l ( intersectionRange . length ) ;
}
}
if ( clippedRangeIsVisible ) clippedSelectedRanges [ clippedRangeIndex + + ] = [ NSValue valueWithRange : clippedSelectedRange ] ;
}
result = [ NSArray arrayWithObjects : clippedSelectedRanges count : clippedRangeIndex ] ;
FREE_ARRAY ( clippedSelectedRanges ) ;
return result ;
}
// maps bookmark keys as NSNumber to byte locations as NSNumbers . Because bookmark callouts may extend beyond the lines containing them , allow a larger range by 10 lines .
- ( NSDictionary * ) displayedBookmarkLocations {
NSMutableDictionary * result = nil ;
HFController * controller = [ self controller ] ;
NSUInteger rangeExtension = 10 * [ controller bytesPerLine ] ;
HFRange displayedRange = [ self entireDisplayedRange ] ;
HFRange includedRange = displayedRange ;
/ * Extend the bottom * /
unsigned long long bottomExtension = MIN ( includedRange . location , rangeExtension ) ;
includedRange . location - = bottomExtension ;
includedRange . length + = bottomExtension ;
/ * Extend the top * /
unsigned long long topExtension = MIN ( [ controller contentsLength ] - HFMaxRange ( includedRange ) , rangeExtension ) ;
includedRange . length = HFSum ( includedRange . length , topExtension ) ;
return result ;
}
- ( unsigned long long ) byteIndexForCharacterIndex : ( NSUInteger ) characterIndex {
HFController * controller = [ self controller ] ;
HFFPRange lineRange = [ controller displayedLineRange ] ;
unsigned long long scrollAmount = HFFPToUL ( floorl ( lineRange . location ) ) ;
unsigned long long byteIndex = HFProductULL ( scrollAmount , [ controller bytesPerLine ] ) + characterIndex * [ [ self view ] bytesPerCharacter ] ;
return byteIndex ;
}
- ( void ) beginSelectionWithEvent : ( NSEvent * ) event forCharacterIndex : ( NSUInteger ) characterIndex {
[ [ self controller ] beginSelectionWithEvent : event forByteIndex : [ self byteIndexForCharacterIndex : characterIndex ] ] ;
}
- ( void ) continueSelectionWithEvent : ( NSEvent * ) event forCharacterIndex : ( NSUInteger ) characterIndex {
[ [ self controller ] continueSelectionWithEvent : event forByteIndex : [ self byteIndexForCharacterIndex : characterIndex ] ] ;
}
- ( void ) endSelectionWithEvent : ( NSEvent * ) event forCharacterIndex : ( NSUInteger ) characterIndex {
[ [ self controller ] endSelectionWithEvent : event forByteIndex : [ self byteIndexForCharacterIndex : characterIndex ] ] ;
}
- ( void ) insertText : ( NSString * ) text {
USE ( text ) ;
UNIMPLEMENTED_VOID ( ) ;
}
- ( void ) copySelectedBytesToPasteboard : ( NSPasteboard * ) pb {
USE ( pb ) ;
UNIMPLEMENTED_VOID ( ) ;
}
- ( void ) cutSelectedBytesToPasteboard : ( NSPasteboard * ) pb {
[ self copySelectedBytesToPasteboard : pb ] ;
[ [ self controller ] deleteSelection ] ;
}
- ( NSData * ) dataFromPasteboardString : ( NSString * ) string {
USE ( string ) ;
UNIMPLEMENTED ( ) ;
}
- ( BOOL ) canPasteFromPasteboard : ( NSPasteboard * ) pb {
REQUIRE_NOT _NULL ( pb ) ;
if ( [ [ self controller ] editable ] ) {
// we can paste if the pboard contains text or contains an HFByteArray
return [ HFPasteboardOwner unpackByteArrayFromPasteboard : pb ] || [ pb availableTypeFromArray : @ [ NSStringPboardType ] ] ;
}
return NO ;
}
- ( BOOL ) canCut {
/ * We can cut if we are editable , we have at least one byte selected , and we are not in overwrite mode * /
HFController * controller = [ self controller ] ;
if ( [ controller editMode ] ! = HFInsertMode ) return NO ;
if ( ! [ controller editable ] ) return NO ;
FOREACH ( HFRangeWrapper * , rangeWrapper , [ controller selectedContentsRanges ] ) {
if ( [ rangeWrapper HFRange ] . length > 0 ) return YES ; // we have something selected
}
return NO ; // we did not find anything selected
}
- ( BOOL ) pasteBytesFromPasteboard : ( NSPasteboard * ) pb {
REQUIRE_NOT _NULL ( pb ) ;
BOOL result = NO ;
HFByteArray * byteArray = [ HFPasteboardOwner unpackByteArrayFromPasteboard : pb ] ;
if ( byteArray ) {
[ [ self controller ] insertByteArray : byteArray replacingPreviousBytes : 0 allowUndoCoalescing : NO ] ;
result = YES ;
}
else {
NSString * stringType = [ pb availableTypeFromArray : @ [ NSStringPboardType ] ] ;
if ( stringType ) {
NSString * stringValue = [ pb stringForType : stringType ] ;
if ( stringValue ) {
NSData * data = [ self dataFromPasteboardString : stringValue ] ;
if ( data ) {
[ [ self controller ] insertData : data replacingPreviousBytes : 0 allowUndoCoalescing : NO ] ;
}
}
}
}
return result ;
}
@ end