Skip to content

Commit

Permalink
text fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
sh-khashimov committed Jul 27, 2020
1 parent 80113ae commit d382fc6
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 39 deletions.
7 changes: 7 additions & 0 deletions Documentation/Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
## CHANGELOG

### 1.1.3

- `characterWrap` type added to the `TextPreferences.LineBreakMode`;
- `maxWidth` added to the `TextPreferences`. With `maxWdith` possible to set maximum width that will be available for text;
- Fixed text margins;
- Fixed when `numberOfLines = 0` may not work properly;

### 1.1.2

- SPM macOS support added;
Expand Down
3 changes: 1 addition & 2 deletions Playgrounds/MyPlayground.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ class MyViewController : UIViewController {
for index in 1...4 {
let headerContent = Slice.ContentType.text(text: "\(index)", preferences: .amountTextPreferences)
let descriptionContent = Slice.ContentType.text(text: "1qwewew 2qwewe 3qwewewew", preferences: .descriptionTextPreferences)
let slice = Slice(contents: [headerContent,
descriptionContent, headerContent])
let slice = Slice(contents: [descriptionContent])
slices.append(slice)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import UIKit
import SwiftFortuneWheel

private let circleStrokeWidth: CGFloat = 50
private let circleStrokeWidth: CGFloat = 10
private let blackColor = UIColor(white: 51.0 / 255.0, alpha: 1.0)
private let cyanColor = UIColor.cyan

Expand Down Expand Up @@ -91,8 +91,9 @@ public extension TextPreferences {
var preferences = TextPreferences(textColorType: textColorType,
font: font,
verticalOffset: 10)
preferences.maxWidth = 12
preferences.orientation = .horizontal
preferences.lineBreakMode = .truncateTail
preferences.lineBreakMode = .characterWrap
preferences.alignment = .center
preferences.numberOfLines = 0
preferences.spacing = 5
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftFortuneWheel/Configuration/TextPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public struct TextPreferences {
/// The technique to use for aligning the text, default value is `.left`
public var alignment: NSTextAlignment = .center

/// Maximum width that will be available for text
public var maxWidth: CGFloat = .greatestFiniteMagnitude

/// Initiates a text preferences
/// - Parameters:
/// - textColorType: Text color type
Expand Down Expand Up @@ -78,6 +81,7 @@ public extension TextPreferences {
case clip
case truncateTail
case wordWrap
case characterWrap

/// NSLineBreakMode
var systemLineBreakMode: NSLineBreakMode {
Expand All @@ -88,6 +92,8 @@ public extension TextPreferences {
return .byTruncatingTail
case .wordWrap:
return .byWordWrapping
case .characterWrap:
return .byCharWrapping
}
}
}
Expand Down
68 changes: 45 additions & 23 deletions Sources/SwiftFortuneWheel/Extensions/String/String+Split.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extension String {
let splitCharacterWidth = splitCharacter.width(by: font)

/// Available words for String
let words = self.split(separator: splitCharacter.first!)
var words = self.split(separator: splitCharacter.first!)

/// The minimum size of the last word
var lastWordMinimumSize = CGFloat.greatestFiniteMagnitude
Expand All @@ -45,7 +45,7 @@ extension String {
var latestAddedWord = 0

/// Splits String to lines, up to last word
for index in 0..<lineWidths.count {
for index in stride(from: 0, to: lineWidths.count, by: 1) {

/// String at the line
var linedString = ""
Expand Down Expand Up @@ -79,33 +79,55 @@ extension String {
} else {
/// Сhecks if lineBreak == .wordWrap then the current word should not be added to the line
guard lineBreak != .wordWrap else { continue }
/// if word first in the line, crops the word and adds it to the line
if isFirstWordInLine {

/// Split by character
if lineBreak == .characterWrap {
/// Cropped word
var croppedWord = word.crop(by: availableWidthInLine, font: font)
if lineBreak == .truncateTail {
croppedWord.replaceLastCharactersWithDots()
let croppedWord = word.crop(by: isFirstWordInLine ? availableWidthInLine : availableWidthInLine - splitCharacterWidth, font: font)

/// Second part of cropped word
let wordSecondPart = word.dropFirst(croppedWord.count)

// if word first in the line, crops the word and adds it to the line
if isFirstWordInLine {
linedString = linedString + croppedWord
} else {
linedString = linedString + splitCharacter + croppedWord
}
linedString += croppedWord
/// Insert second word part to iteration
words.insert(wordSecondPart, at: wordIndex+1)

availableWidthInLine = 0
latestAddedWord = wordIndex + 1
} else {
/// Is the latest line
let isLatestLine = lineWidths.count - 1 == index
/// If the line is not latest, the current word most likely will be added to the next line
guard isLatestLine else { continue }
/// Checks available width in the line for the cropped word, the word won't be added if available width is less then for 5 character
guard availableWidthInLine >= splitCharacterWidth + lastWordMinimumSize else { continue }
/// Cropped word
var croppedWord = word.crop(by: availableWidthInLine, font: font)
/// Checks are cropped word more than 3 character
guard croppedWord.count > 3 else { continue }
if lineBreak == .truncateTail {
croppedWord.replaceLastCharactersWithDots()
/// if word first in the line, crops the word and adds it to the line
if isFirstWordInLine {
/// Cropped word
var croppedWord = word.crop(by: availableWidthInLine, font: font)
if lineBreak == .truncateTail {
croppedWord.replaceLastCharactersWithDots()
}
linedString += croppedWord
availableWidthInLine = 0
latestAddedWord = wordIndex + 1
} else {
/// Is the latest line
let isLatestLine = lineWidths.count - 1 == index
/// If the line is not latest, the current word most likely will be added to the next line
guard isLatestLine else { continue }
/// Checks available width in the line for the cropped word, the word won't be added if available width is less then for 5 character
guard availableWidthInLine >= splitCharacterWidth + lastWordMinimumSize else { continue }
/// Cropped word
var croppedWord = word.crop(by: availableWidthInLine, font: font)
/// Checks are cropped word more than 3 character
guard croppedWord.count > 3 else { continue }
if lineBreak == .truncateTail {
croppedWord.replaceLastCharactersWithDots()
}
linedString += splitCharacter + croppedWord
availableWidthInLine = 0
latestAddedWord = wordIndex + 1
}
linedString += splitCharacter + croppedWord
availableWidthInLine = 0
latestAddedWord = wordIndex + 1
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftFortuneWheel/Utils/Drawing/SliceDrawing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ extension SliceDrawing {
var margins: SFWConfiguration.Margins {
var margins = self.preferences?.contentMargins ?? SFWConfiguration.Margins()
margins.top = margins.top + (self.preferences?.circlePreferences.strokeWidth ?? 0) / 2
margins.left = margins.left + (self.preferences?.circlePreferences.strokeWidth ?? 0)
margins.right = margins.right + (self.preferences?.circlePreferences.strokeWidth ?? 0)
margins.bottom = margins.bottom + (self.preferences?.circlePreferences.strokeWidth ?? 0) / 2
return margins
}

Expand Down
24 changes: 12 additions & 12 deletions Sources/SwiftFortuneWheel/Utils/Drawing/TextDrawing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ extension TextDrawing {
private func availableTextRect(yPosition: CGFloat, preferences: TextPreferences, topOffset: CGFloat, radius: CGFloat, sliceDegree: CGFloat, margins: SFWConfiguration.Margins) -> [CGRect] {

/// Max. available height from Y position
let maxHeight = radius - abs(yPosition) - margins.bottom
let maxHeight = abs(yPosition) - margins.bottom

/// Max. available lines for String
let maxLines = preferences.numberOfLines == 0 ? Int((maxHeight / preferences.font.pointSize).rounded(.towardZero)) : preferences.numberOfLines
let maxLines = preferences.numberOfLines == 0 ? Int((maxHeight / (preferences.font.pointSize + preferences.spacing)).rounded(.up)) : preferences.numberOfLines

/// Text rectangles
var textRects: [CGRect] = []
Expand All @@ -47,10 +47,10 @@ extension TextDrawing {
/// Y position of the rectangle bottoms
let bottomYPosition = -(radius - preferences.verticalOffset - topOffset - heightOffset - spacing)
/// Width
let width = self.width(forYPosition: bottomYPosition,
let width = min(preferences.maxWidth, self.width(forYPosition: bottomYPosition,
sliceDegree: sliceDegree,
leftMargin: margins.left,
rightMargin: margins.right)
rightMargin: margins.right))
/// Text rectangle
let textRect = CGRect(x: 0, y: 0, width: width, height: preferences.font.pointSize)
textRects.append(textRect)
Expand Down Expand Up @@ -239,7 +239,7 @@ extension TextDrawing {
let maxWidth = Calc.circularSegmentHeight(radius: radius - preferences.verticalOffset - topOffset, from: sliceDegree)

/// Maximum available lines in slice
let maxLinesInSlice = (maxWidth / (preferences.font.pointSize + preferences.spacing)).rounded(.down)
let maxLinesInSlice = (maxWidth / (preferences.font.pointSize + preferences.spacing)).rounded(.up)

/// Available text rectangles
var availableTextRects: [CGRect] = []
Expand All @@ -252,7 +252,7 @@ extension TextDrawing {
/// Height of text rectangle
let _height = preferences.font.pointSize * CGFloat(line) + preferences.spacing * (CGFloat(line) - 1)
/// Maximum circular segment height (chord) for current line (rectangle)
let _maxCircularSegmentHeight = margins.left + margins.right + _height
let _maxCircularSegmentHeight = _height - margins.top - margins.bottom
/// Bottom radius offset
let _bottomRadiusOffset = max(margins.bottom, Calc.radius(circularSegmentHeight: _maxCircularSegmentHeight, from: sliceDegree))
/// Available width in slice
Expand All @@ -263,7 +263,7 @@ extension TextDrawing {
/// Height of the next text rectangle
let _nextHeight = preferences.font.pointSize * CGFloat(line + 1) + preferences.spacing * (CGFloat(line))
/// Maximum circular segment height (chord) for current line (rectangle)
let _nextMaxCircularSegmentHeight = margins.left + margins.right + _nextHeight + spacing
let _nextMaxCircularSegmentHeight = _nextHeight + spacing - margins.top - margins.bottom
/// Bottom radius offset for next line
let _nextBottomRadiusOffset = max(margins.bottom, Calc.radius(circularSegmentHeight: _nextMaxCircularSegmentHeight, from: sliceDegree))
/// Available width in slice for next line
Expand Down Expand Up @@ -296,13 +296,13 @@ extension TextDrawing {

/// split the availableTextRect to the text rectangles
textRects = Array(repeating: CGRect(x: 0, y: 0, width: textRect.width, height: preferences.font.pointSize), count: line)
multilineString = text.split(font: preferences.font, lineWidths: textRects.map({ $0.width }), lineBreak: preferences.lineBreakMode)
multilineString = text.split(font: preferences.font, lineWidths: textRects.map({ min(preferences.maxWidth, $0.width) }), lineBreak: preferences.lineBreakMode)

/// Word count for text in the current line
let _wordCount = max(multilineString.joined().split(separator: " ".first!).count, line)

if wordsCount == _wordCount {
break
// break
}
}

Expand Down Expand Up @@ -352,9 +352,9 @@ extension TextDrawing {
}

// For Debugging purposes
// context.addRect(textRect)
// UIColor.red.setStroke()
// context.drawPath(using: .fillStroke)
// context.addRect(textRect)
// UIColor.red.setStroke()
// context.drawPath(using: .fillStroke)

string.draw(in: CGRect(x: 0, y: 0, width: textRect.width, height: CGFloat.infinity), withAttributes: textAttributes)

Expand Down

0 comments on commit d382fc6

Please sign in to comment.