Skip to content

Commit 22c7142

Browse files
committed
Fixing dragging
1 parent 46ac74b commit 22c7142

File tree

2 files changed

+116
-50
lines changed

2 files changed

+116
-50
lines changed

CodeCombat/EditorTextView.swift

Lines changed: 112 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
183183

184184

185185
func dimLineUnderLocation(location:CGPoint) {
186-
let currentLine = Int(location.y / (font.lineHeight + lineSpacing))
186+
let currentLine = lineNumberUnderPoint(location)
187187
slightlyDimLineWhileDraggingOver(lineNumber: currentLine)
188188
}
189189

@@ -407,6 +407,13 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
407407
}
408408
}
409409

410+
func paragraphRangeUnderLocation(loc:CGPoint) -> NSRange {
411+
/*let storage = textStorage as EditorTextStorage
412+
let nearestCharacterIndex = layoutManager.characterIndexForPoint(loc, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
413+
return storage.string()!.paragraphRangeForRange(<#range: NSRange#>)*/
414+
return NSRange(location:0, length: 0)
415+
}
416+
410417
func lineNumberUnderPoint(var point:CGPoint) -> Int {
411418
//point.y += lineSpacing
412419
let storage = textStorage as EditorTextStorage
@@ -444,6 +451,51 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
444451
return lineNumberToReturn
445452
}
446453

454+
func boundingRectForLineNumber(lineNumber:Int) -> CGRect {
455+
//point.y += lineSpacing
456+
let storage = textStorage as EditorTextStorage
457+
let Context = UIGraphicsGetCurrentContext()
458+
let Bounds = bounds
459+
460+
let textRange = layoutManager.glyphRangeForTextContainer(textContainer)
461+
let glyphsToShow = layoutManager.glyphRangeForCharacterRange(textRange,
462+
actualCharacterRange: nil)
463+
464+
var currentLineNumber = 0
465+
var boundingRect:CGRect?
466+
var numberOfExtraLines = 0
467+
func lineFragmentClosure(aRect:CGRect, aUsedRect:CGRect,
468+
textContainer:NSTextContainer!, glyphRange:NSRange,
469+
stop:UnsafeMutablePointer<ObjCBool>) -> Void {
470+
let charRange = layoutManager.characterRangeForGlyphRange(glyphRange, actualGlyphRange: nil)
471+
let paraRange = storage.string()!.paragraphRangeForRange(charRange)
472+
if charRange.location == paraRange.location {
473+
currentLineNumber++
474+
if currentLineNumber == lineNumber {
475+
boundingRect = layoutManager.boundingRectForGlyphRange(layoutManager.glyphRangeForCharacterRange(paraRange, actualCharacterRange: nil), inTextContainer: textContainer)
476+
boundingRect!.origin.x = 0
477+
boundingRect!.size.width = frame.width
478+
stop.initialize(true)
479+
}
480+
} else {
481+
numberOfExtraLines++
482+
}
483+
}
484+
layoutManager.enumerateLineFragmentsForGlyphRange(glyphsToShow,
485+
usingBlock: lineFragmentClosure)
486+
if boundingRect == nil {
487+
let LineHeight = font.lineHeight + lineSpacing
488+
let LineNumberRect = CGRect(
489+
x: 0,
490+
y: LineHeight * CGFloat(lineNumber - numberOfExtraLines + 1),
491+
width: frame.width,
492+
height: LineHeight)
493+
boundingRect = LineNumberRect
494+
}
495+
496+
return boundingRect!
497+
}
498+
447499
private func drawLineNumbers(rect:CGRect) {
448500
let storage = textStorage as EditorTextStorage
449501
let Context = UIGraphicsGetCurrentContext()
@@ -535,7 +587,8 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
535587
func fragmentEnumerator(aRect:CGRect, aUsedRect:CGRect, textContainer:NSTextContainer!, glyphRange:NSRange, stop:UnsafeMutablePointer<ObjCBool>) -> Void {
536588
let fragmentCharacterRange = layoutManager.characterRangeForGlyphRange(glyphRange, actualGlyphRange: nil)
537589
let fragmentParagraphRange = editorTextStorage.string()!.paragraphRangeForRange(fragmentCharacterRange)
538-
if NSEqualRanges(draggedCharacterRange,fragmentCharacterRange) {
590+
let draggedParagraphRange = editorTextStorage.string()!.paragraphRangeForRange(draggedCharacterRange)
591+
if NSEqualRanges(draggedParagraphRange, fragmentParagraphRange) {
539592
//This means we've found the dragged line
540593
currentLineNumber++
541594
return
@@ -567,10 +620,22 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
567620
if fragmentCharacterRange.length == fragmentParagraphRange.length {
568621
label.attributedText = parentTextViewController.getAttributedStringForCharacterRange(fragmentParagraphRange)
569622
} else {
570-
let attributedStringBeforeLineBreak = NSMutableAttributedString(attributedString: parentTextViewController.getAttributedStringForCharacterRange(fragmentCharacterRange))
571-
attributedStringBeforeLineBreak.appendAttributedString(NSAttributedString(string: "\n"))
572-
let attributedStringAfterLineBreak = parentTextViewController.getAttributedStringForCharacterRange(NSRange(location: NSMaxRange(fragmentCharacterRange), length: (fragmentParagraphRange.length - fragmentCharacterRange.length)))
573-
attributedStringBeforeLineBreak.appendAttributedString(attributedStringAfterLineBreak)
623+
var attributedStringBeforeLineBreak:NSMutableAttributedString!
624+
var attributedStringAfterLineBreak:NSMutableAttributedString!
625+
if fragmentCharacterRange.location == fragmentParagraphRange.location {
626+
//Dragging first line
627+
attributedStringBeforeLineBreak = NSMutableAttributedString(attributedString: parentTextViewController.getAttributedStringForCharacterRange(fragmentCharacterRange))
628+
attributedStringBeforeLineBreak.appendAttributedString(NSAttributedString(string: "\n"))
629+
attributedStringAfterLineBreak = NSMutableAttributedString(attributedString: parentTextViewController.getAttributedStringForCharacterRange(NSRange(location: NSMaxRange(fragmentCharacterRange), length: (fragmentParagraphRange.length - fragmentCharacterRange.length))))
630+
attributedStringBeforeLineBreak.appendAttributedString(attributedStringAfterLineBreak)
631+
} else {
632+
//Dragging second line, character range is smaller than paragraph range
633+
attributedStringBeforeLineBreak = NSMutableAttributedString(attributedString: parentTextViewController.getAttributedStringForCharacterRange(NSRange(location: fragmentParagraphRange.location, length: fragmentParagraphRange.length - fragmentCharacterRange.length)))
634+
attributedStringBeforeLineBreak.appendAttributedString(NSAttributedString(string: "\n"))
635+
attributedStringAfterLineBreak = NSMutableAttributedString(attributedString: parentTextViewController.getAttributedStringForCharacterRange(fragmentCharacterRange))
636+
attributedStringBeforeLineBreak.appendAttributedString(attributedStringAfterLineBreak)
637+
}
638+
574639
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
575640
label.numberOfLines = 0
576641
var paragraphStyle = NSMutableParagraphStyle()
@@ -619,49 +684,54 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
619684
if max(1,lineNumber) < draggedLineNumber {
620685
//Move the ones between the current drag location and dragged line
621686
for lineToMove in max(lineNumber,1)...(draggedLineNumber - 1) {
622-
let labelToMove = dragOverlayLabels[lineToMove]!
623-
//check if offset is supposed to move
624-
if labelToMove.frame.origin.y == originalDragOverlayLabelOffsets[lineToMove]! {
625-
//shift down
626-
var oldFrame = labelToMove.frame
627-
oldFrame.origin.y += lineSpacing + font.lineHeight
628-
labelToMove.frame = oldFrame
629-
labelToMove.setNeedsLayout()
687+
if let labelToMove = dragOverlayLabels[lineToMove] {
688+
//check if offset is supposed to move
689+
if labelToMove.frame.origin.y == originalDragOverlayLabelOffsets[lineToMove]! {
690+
//shift down
691+
var oldFrame = labelToMove.frame
692+
oldFrame.origin.y += lineSpacing + font.lineHeight
693+
labelToMove.frame = oldFrame
694+
labelToMove.setNeedsLayout()
695+
}
630696
}
697+
631698
}
632699
//Reset the ones above that
633700
if lineNumber != 1 && draggedLineNumber != 1 {
634701
for lineToReset in 1...max(1,lineNumber - 1) {
635-
let labelToReset = dragOverlayLabels[lineToReset]!
636-
if labelToReset.frame.origin.y != originalDragOverlayLabelOffsets[lineToReset]! {
637-
var oldFrame = labelToReset.frame
638-
oldFrame.origin.y = originalDragOverlayLabelOffsets[lineToReset]!
639-
labelToReset.frame = oldFrame
640-
labelToReset.setNeedsLayout()
702+
if let labelToReset = dragOverlayLabels[lineToReset] {
703+
if labelToReset.frame.origin.y != originalDragOverlayLabelOffsets[lineToReset]! {
704+
var oldFrame = labelToReset.frame
705+
oldFrame.origin.y = originalDragOverlayLabelOffsets[lineToReset]!
706+
labelToReset.frame = oldFrame
707+
labelToReset.setNeedsLayout()
708+
}
641709
}
642710
}
643711
}
644712

645713
} else if min(lineNumber,maxLine) > draggedLineNumber {
646714
//Move the lines between the dragged line and the current drag
647715
for lineToMove in (draggedLineNumber + 1)...min(lineNumber,maxLine) {
648-
let labelToMove = dragOverlayLabels[lineToMove]!
649-
if labelToMove.frame.origin.y == originalDragOverlayLabelOffsets[lineToMove]! {
650-
var oldFrame = labelToMove.frame
651-
oldFrame.origin.y -= lineSpacing + font.lineHeight
652-
labelToMove.frame = oldFrame
653-
labelToMove.setNeedsLayout()
716+
if let labelToMove = dragOverlayLabels[lineToMove] {
717+
if labelToMove.frame.origin.y == originalDragOverlayLabelOffsets[lineToMove]! {
718+
var oldFrame = labelToMove.frame
719+
oldFrame.origin.y -= lineSpacing + font.lineHeight
720+
labelToMove.frame = oldFrame
721+
labelToMove.setNeedsLayout()
722+
}
654723
}
655724
}
656725
//Reset the ones below that
657726
if lineNumber != maxLine {
658727
for lineToReset in min(maxLine,lineNumber + 1)...maxLine {
659-
let labelToReset = dragOverlayLabels[lineToReset]!
660-
if labelToReset.frame.origin.y != originalDragOverlayLabelOffsets[lineToReset]! {
661-
var oldFrame = labelToReset.frame
662-
oldFrame.origin.y = originalDragOverlayLabelOffsets[lineToReset]!
663-
labelToReset.frame = oldFrame
664-
labelToReset.setNeedsLayout()
728+
if let labelToReset = dragOverlayLabels[lineToReset] {
729+
if labelToReset.frame.origin.y != originalDragOverlayLabelOffsets[lineToReset]! {
730+
var oldFrame = labelToReset.frame
731+
oldFrame.origin.y = originalDragOverlayLabelOffsets[lineToReset]!
732+
labelToReset.frame = oldFrame
733+
labelToReset.setNeedsLayout()
734+
}
665735
}
666736
}
667737
}
@@ -679,13 +749,15 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
679749
linesToReset.append(draggedLineNumber + 1)
680750
}
681751
for lineToReset in linesToReset {
682-
let labelToReset = dragOverlayLabels[lineToReset]!
683-
if labelToReset.frame.origin.y != originalDragOverlayLabelOffsets[lineToReset]! {
684-
var oldFrame = labelToReset.frame
685-
oldFrame.origin.y = originalDragOverlayLabelOffsets[lineToReset]!
686-
labelToReset.frame = oldFrame
687-
labelToReset.setNeedsLayout()
752+
if let labelToReset = dragOverlayLabels[lineToReset] {
753+
if labelToReset.frame.origin.y != originalDragOverlayLabelOffsets[lineToReset]! {
754+
var oldFrame = labelToReset.frame
755+
oldFrame.origin.y = originalDragOverlayLabelOffsets[lineToReset]!
756+
labelToReset.frame = oldFrame
757+
labelToReset.setNeedsLayout()
758+
}
688759
}
760+
689761
}
690762
}
691763
}
@@ -699,17 +771,11 @@ class EditorTextView: UITextView, NSLayoutManagerDelegate {
699771

700772
//Note, this won't take doubled lines into account
701773
private func lineNumberOfLocationInTextView(loc:CGPoint) -> Int {
702-
return Int((loc.y - lineSpacing) / (lineSpacing + font.lineHeight) + 1)
774+
return lineNumberUnderPoint(loc)
703775
}
704776

705777
func getLineNumberRect(lineNumber:Int) -> CGRect{
706-
let LineHeight = font.lineHeight + lineSpacing
707-
let LineNumberRect = CGRect(
708-
x: 0,
709-
y: LineHeight * CGFloat(lineNumber) + lineSpacing,
710-
width: frame.width,
711-
height: LineHeight)
712-
return LineNumberRect
778+
return boundingRectForLineNumber(lineNumber)
713779
}
714780

715781

CodeCombat/EditorTextViewController.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,12 @@ class EditorTextViewController: UIViewController, UITextViewDelegate, UIGestureR
452452

453453
private func shiftAroundLines(dragEndLocation:CGPoint) {
454454
//get the text underneath the drag end
455-
let lineFragmentRect = getLineFragmentRectForDrag(dragEndLocation);
456-
let characterRange = getCharacterRangeForLineFragmentRect(lineFragmentRect)
455+
let characterIndexUnderDrag = textView.layoutManager.characterIndexForPoint(dragEndLocation, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
456+
let replacedCharacterRange = textStorage.string()!.paragraphRangeForRange(NSRange(location: characterIndexUnderDrag, length: 1))
457+
let characterRange = replacedCharacterRange
457458
var replacedString = textStorage.string()!.substringWithRange(characterRange)
458459
var replacingString = textStorage.string()!.substringWithRange(draggedCharacterRange)
459-
if !NSEqualRanges(draggedCharacterRange, characterRange) {
460+
if !(draggedCharacterRange.location == characterRange.location) {
460461
var replacedLineIndentation = indentationLevelOfLine(lineNumberForDraggedCharacterRange(characterRange))
461462
let draggedLineIndentation = indentationLevelOfLine(lineNumberForDraggedCharacterRange(draggedCharacterRange))
462463
let trimmedString = replacedString.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
@@ -473,7 +474,6 @@ class EditorTextViewController: UIViewController, UITextViewDelegate, UIGestureR
473474
} else {
474475
textStorage.replaceCharactersInRange(characterRange, withString: replacedString + replacingString)
475476
textStorage.replaceCharactersInRange(draggedCharacterRange, withString: "")
476-
//textStorage.replaceCharactersInRange(draggedCharacterRange, withString: "")
477477
}
478478
textStorage.endEditing()
479479
textView.setNeedsDisplay()

0 commit comments

Comments
 (0)