Repo // Add NSAttributedTextView.

This commit is contained in:
ShikiSuen 2022-09-07 14:34:19 +08:00
parent 87ac82f242
commit 599c576fc9
2 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,116 @@
// (c) 2021 and onwards Fuziki (MIT License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// Ref: https://qiita.com/fuziki/items/b31055a69330a3ce55a5
// Modified by The vChewing Project in order to use it with AppKit.
import Cocoa
import SwiftUI
@available(macOS 10.15, *)
public struct VText: NSViewRepresentable {
public var text: String?
public func makeNSView(context _: Context) -> NSAttributedTextView {
let nsView = NSAttributedTextView()
nsView.direction = .vertical
nsView.text = text
return nsView
}
public func updateNSView(_ nsView: NSAttributedTextView, context _: Context) {
nsView.text = text
}
}
@available(macOS 10.15, *)
public struct HText: NSViewRepresentable {
public var text: String?
public func makeNSView(context _: Context) -> NSAttributedTextView {
let nsView = NSAttributedTextView()
nsView.direction = .horizontal
nsView.text = text
return nsView
}
public func updateNSView(_ nsView: NSAttributedTextView, context _: Context) {
nsView.text = text
}
}
public class NSAttributedTextView: NSView {
public enum writingDirection: String {
case horizontal
case vertical
case verticalReversed
}
public var direction: writingDirection = .horizontal
public var fontSize: CGFloat = NSFont.systemFontSize {
didSet {
attributes[.font] = NSFont.systemFont(ofSize: fontSize)
}
}
public var textColor: NSColor = .textColor {
didSet {
attributes[.foregroundColor] = textColor
}
}
public var attributedStringValue: NSAttributedString {
var newAttributes = attributes
let isVertical: Bool = !(direction == .horizontal)
newAttributes[.verticalGlyphForm] = isVertical
let lineHeight: CGFloat = isVertical ? fontSize * 0.8 : fontSize * 1.3
let newStyle: NSMutableParagraphStyle = newAttributes[.paragraphStyle] as! NSMutableParagraphStyle
newStyle.maximumLineHeight = lineHeight
newStyle.minimumLineHeight = lineHeight
newAttributes[.paragraphStyle] = newStyle
let attributedText = NSMutableAttributedString(string: text ?? "", attributes: newAttributes)
return attributedText
}
public var backgroundColor: NSColor = .controlBackgroundColor
public var attributes: [NSAttributedString.Key: Any] = [
.verticalGlyphForm: true,
.font: NSFont.systemFont(ofSize: NSFont.systemFontSize),
.foregroundColor: NSColor.textColor,
.paragraphStyle: {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .left
return paragraphStyle
}(),
]
public var text: String? { didSet { ctFrame = nil } }
private var ctFrame: CTFrame?
private(set) var currentRect: NSRect?
override public func draw(_ rect: CGRect) {
let context = NSGraphicsContext.current?.cgContext
guard let context = context else { return }
let setter = CTFramesetterCreateWithAttributedString(attributedStringValue)
let path = CGPath(rect: rect, transform: nil)
let theCTFrameProgression: CTFrameProgression = {
switch direction {
case .horizontal: return CTFrameProgression.topToBottom
case .vertical: return CTFrameProgression.rightToLeft
case .verticalReversed: return CTFrameProgression.leftToRight
}
}()
let frameAttrs: CFDictionary =
[
kCTFrameProgressionAttributeName: theCTFrameProgression.rawValue
] as CFDictionary
let newFrame = CTFramesetterCreateFrame(setter, CFRangeMake(0, 0), path, frameAttrs)
ctFrame = newFrame
backgroundColor.setFill()
let bgPath: NSBezierPath = .init(roundedRect: rect, xRadius: 0, yRadius: 0)
bgPath.fill()
currentRect = rect
CTFrameDraw(newFrame, context)
}
}

View File

@ -32,6 +32,7 @@
5B54E743283A7D89001ECBDC /* lmCoreNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B54E742283A7D89001ECBDC /* lmCoreNS.swift */; };
5B5948CE289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */; };
5B5E535227EF261400C6AA1E /* IME.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5E535127EF261400C6AA1E /* IME.swift */; };
5B5F8AEB28C86AAD007C11F1 /* NSAttributedTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F8AEA28C86AAD007C11F1 /* NSAttributedTextView.swift */; };
5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */; };
5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* mgrPrefs.swift */; };
5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */; };
@ -246,6 +247,7 @@
5B54E742283A7D89001ECBDC /* lmCoreNS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = lmCoreNS.swift; sourceTree = "<group>"; };
5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LMInstantiator_DateTimeExtension.swift; sourceTree = "<group>"; };
5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B5F8AEA28C86AAD007C11F1 /* NSAttributedTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedTextView.swift; sourceTree = "<group>"; };
5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
@ -463,11 +465,20 @@
path = SubLMs;
sourceTree = "<group>";
};
5B5F8AEC28C86AB3007C11F1 /* NSAttributedTextView */ = {
isa = PBXGroup;
children = (
5B5F8AEA28C86AAD007C11F1 /* NSAttributedTextView.swift */,
);
path = NSAttributedTextView;
sourceTree = "<group>";
};
5B62A30127AE732800A19448 /* 3rdParty */ = {
isa = PBXGroup;
children = (
5B84579B2871AD2200C93B01 /* HotenkaChineseConverter */,
5B949BD72816DC4400D87B5D /* LineReader */,
5B5F8AEC28C86AB3007C11F1 /* NSAttributedTextView */,
5BA58644289BCFAC0077D02F /* Qwertyyb */,
5B20430528BEE2F300BFC6FD /* Sandbox */,
5BA9FCEA27FED652002DE248 /* SindreSorhus */,
@ -1211,6 +1222,7 @@
5B887F302826AEA400B6651E /* lmCoreEX.swift in Sources */,
5BA9FD4627FEF3C9002DE248 /* Container.swift in Sources */,
5B2170E5289FACAD00BE7304 /* 6_Node.swift in Sources */,
5B5F8AEB28C86AAD007C11F1 /* NSAttributedTextView.swift in Sources */,
5B949BD92816DC5400D87B5D /* LineReader.swift in Sources */,
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */,
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */,