mirror of
https://github.com/coteditor/CotEditor.git
synced 2024-09-11 11:25:57 +03:00
Place characters vertically in the middle of line (close #373)
This commit is contained in:
parent
57bf293878
commit
3c7123cf66
@ -7,10 +7,16 @@ Change Log
|
||||
|
||||
### Improvements
|
||||
|
||||
- Adjust the text baseline to draw characters vertically center in lines.
|
||||
- Adjust invisible characters position in the vertical text orientation.
|
||||
- Improve drawing performance.
|
||||
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix an issue where the line numbers could be shifted when printing vertical text orientation document.
|
||||
|
||||
|
||||
|
||||
3.8.12 (400)
|
||||
--------------------------
|
||||
|
@ -79,7 +79,6 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
|
||||
|
||||
private(set) var spaceWidth: CGFloat = 0
|
||||
private(set) var replacementGlyphWidth: CGFloat = 0
|
||||
private(set) var defaultBaselineOffset: CGFloat = 0 // defaultBaselineOffset for textFont
|
||||
private(set) var showsOtherInvisibles = false
|
||||
|
||||
|
||||
@ -88,6 +87,7 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
|
||||
private var defaultsObservers: [UserDefaultsObservation] = []
|
||||
|
||||
private var defaultLineHeight: CGFloat = 1.0
|
||||
private var defaultBaselineOffset: CGFloat = 0
|
||||
|
||||
private var showsSpace = false
|
||||
private var showsTab = false
|
||||
@ -202,6 +202,8 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
|
||||
context.textMatrix = CGAffineTransform(scaleX: 1.0, y: -1.0)
|
||||
}
|
||||
|
||||
let baselineOffset = self.baselineOffset(for: layoutOrientation ?? .horizontal)
|
||||
|
||||
// draw invisibles glyph by glyph
|
||||
let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
|
||||
for charIndex in characterRange.lowerBound..<characterRange.upperBound {
|
||||
@ -238,8 +240,7 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
|
||||
let glyphIndex = self.glyphIndexForCharacter(at: charIndex)
|
||||
let lineOrigin = self.lineFragmentRect(forGlyphAt: glyphIndex, effectiveRange: nil, withoutAdditionalLayout: true).origin
|
||||
let glyphLocation = self.location(forGlyphAt: glyphIndex)
|
||||
var point = lineOrigin.offset(by: origin).offsetBy(dx: glyphLocation.x,
|
||||
dy: self.defaultBaselineOffset)
|
||||
var point = lineOrigin.offset(by: origin).offsetBy(dx: glyphLocation.x, dy: baselineOffset)
|
||||
if layoutOrientation == .vertical {
|
||||
let bounds = line.bounds()
|
||||
point.y += bounds.minY + bounds.height / 2
|
||||
@ -310,6 +311,21 @@ final class LayoutManager: NSLayoutManager, ValidationIgnorable, LineRangeCachea
|
||||
}
|
||||
|
||||
|
||||
/// Fixed baseline offset to place glyphs vertically in the middle of a line.
|
||||
///
|
||||
/// - Parameter layoutOrientation: The text layout orientation.
|
||||
/// - Returns: The baseline offset.
|
||||
func baselineOffset(for layoutOrientation: TextLayoutOrientation) -> CGFloat {
|
||||
|
||||
switch layoutOrientation {
|
||||
case .vertical:
|
||||
return self.lineHeight / 2
|
||||
default:
|
||||
return (self.lineHeight + self.defaultBaselineOffset) / 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: Private Methods
|
||||
|
||||
|
@ -33,7 +33,6 @@ final class LineNumberView: NSView {
|
||||
|
||||
let fontSize: CGFloat
|
||||
let charWidth: CGFloat
|
||||
let ascent: CGFloat
|
||||
let wrappedMarkGlyph: CGGlyph
|
||||
let digitGlyphs: [CGGlyph]
|
||||
let padding: CGFloat
|
||||
@ -50,7 +49,6 @@ final class LineNumberView: NSView {
|
||||
|
||||
// calculate font size for number
|
||||
self.fontSize = (scale * LineNumberView.fontSizeFactor * textFont.pointSize).rounded(interval: 0.5)
|
||||
self.ascent = scale * textFont.ascender
|
||||
|
||||
// prepare glyphs
|
||||
let font = CTFontCreateWithGraphicsFont(LineNumberView.lineNumberFont, self.fontSize, nil, nil)
|
||||
@ -291,6 +289,7 @@ final class LineNumberView: NSView {
|
||||
guard
|
||||
let drawingInfo = self.drawingInfo,
|
||||
let textView = self.textView,
|
||||
let layoutManager = textView.layoutManager as? LayoutManager,
|
||||
let context = NSGraphicsContext.current?.cgContext
|
||||
else { return assertionFailure() }
|
||||
|
||||
@ -306,7 +305,8 @@ final class LineNumberView: NSView {
|
||||
|
||||
// adjust drawing coordinate
|
||||
let relativePoint = self.convert(NSPoint.zero, from: textView)
|
||||
let lineBase = (scale * textView.textContainerOrigin.y) + drawingInfo.ascent
|
||||
let baselineOffset = layoutManager.baselineOffset(for: textView.layoutOrientation)
|
||||
let lineBase = scale * (textView.textContainerOrigin.y + baselineOffset)
|
||||
switch textView.layoutOrientation {
|
||||
case .horizontal:
|
||||
context.translateBy(x: self.thickness, y: relativePoint.y - lineBase)
|
||||
|
@ -244,12 +244,13 @@ final class PrintTextView: NSTextView, NSLayoutManagerDelegate, Themable, URLDet
|
||||
|
||||
// adjust position to draw
|
||||
let width = CGFloat(numberString.count) * charSize.width
|
||||
var point = NSPoint(x: horizontalOrigin, y: lineRect.maxY - charSize.height)
|
||||
var point = NSPoint(x: horizontalOrigin, y: lineRect.midY)
|
||||
if isVerticalText {
|
||||
point = NSPoint(x: -point.y - (width + charSize.height) / 2,
|
||||
point = NSPoint(x: -point.y - width / 2,
|
||||
y: point.x - charSize.height)
|
||||
} else {
|
||||
point.x -= width // align right
|
||||
point.y -= charSize.height / 2
|
||||
}
|
||||
|
||||
// draw number
|
||||
|
@ -43,8 +43,8 @@ final class Typesetter: NSATSTypesetter {
|
||||
lineRect.pointee.size.height = manager.lineHeight
|
||||
usedRect.pointee.size.height = manager.lineHeight
|
||||
|
||||
// avoid baseline shifting when the glyph height is higher than the fixed line height, such as 𓆏.
|
||||
baselineOffset.pointee = manager.defaultBaselineOffset
|
||||
// vertically center the glyphs in the line fragment
|
||||
baselineOffset.pointee = manager.baselineOffset(for: self.currentTextContainer?.layoutOrientation ?? .horizontal)
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user