Repo // Add NSAttributedTextView.
This commit is contained in:
parent
87ac82f242
commit
599c576fc9
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@
|
||||||
5B54E743283A7D89001ECBDC /* lmCoreNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B54E742283A7D89001ECBDC /* lmCoreNS.swift */; };
|
5B54E743283A7D89001ECBDC /* lmCoreNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B54E742283A7D89001ECBDC /* lmCoreNS.swift */; };
|
||||||
5B5948CE289CC04500C85824 /* LMInstantiator_DateTimeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5948CD289CC04500C85824 /* LMInstantiator_DateTimeExtension.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 */; };
|
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 */; };
|
5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */; };
|
||||||
5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* mgrPrefs.swift */; };
|
5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* mgrPrefs.swift */; };
|
||||||
5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.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>"; };
|
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>"; };
|
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; };
|
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; };
|
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; };
|
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; };
|
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;
|
path = SubLMs;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
5B5F8AEC28C86AB3007C11F1 /* NSAttributedTextView */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5B5F8AEA28C86AAD007C11F1 /* NSAttributedTextView.swift */,
|
||||||
|
);
|
||||||
|
path = NSAttributedTextView;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
5B62A30127AE732800A19448 /* 3rdParty */ = {
|
5B62A30127AE732800A19448 /* 3rdParty */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5B84579B2871AD2200C93B01 /* HotenkaChineseConverter */,
|
5B84579B2871AD2200C93B01 /* HotenkaChineseConverter */,
|
||||||
5B949BD72816DC4400D87B5D /* LineReader */,
|
5B949BD72816DC4400D87B5D /* LineReader */,
|
||||||
|
5B5F8AEC28C86AB3007C11F1 /* NSAttributedTextView */,
|
||||||
5BA58644289BCFAC0077D02F /* Qwertyyb */,
|
5BA58644289BCFAC0077D02F /* Qwertyyb */,
|
||||||
5B20430528BEE2F300BFC6FD /* Sandbox */,
|
5B20430528BEE2F300BFC6FD /* Sandbox */,
|
||||||
5BA9FCEA27FED652002DE248 /* SindreSorhus */,
|
5BA9FCEA27FED652002DE248 /* SindreSorhus */,
|
||||||
|
@ -1211,6 +1222,7 @@
|
||||||
5B887F302826AEA400B6651E /* lmCoreEX.swift in Sources */,
|
5B887F302826AEA400B6651E /* lmCoreEX.swift in Sources */,
|
||||||
5BA9FD4627FEF3C9002DE248 /* Container.swift in Sources */,
|
5BA9FD4627FEF3C9002DE248 /* Container.swift in Sources */,
|
||||||
5B2170E5289FACAD00BE7304 /* 6_Node.swift in Sources */,
|
5B2170E5289FACAD00BE7304 /* 6_Node.swift in Sources */,
|
||||||
|
5B5F8AEB28C86AAD007C11F1 /* NSAttributedTextView.swift in Sources */,
|
||||||
5B949BD92816DC5400D87B5D /* LineReader.swift in Sources */,
|
5B949BD92816DC5400D87B5D /* LineReader.swift in Sources */,
|
||||||
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */,
|
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */,
|
||||||
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */,
|
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */,
|
||||||
|
|
Loading…
Reference in New Issue