Switch to using NSTextField for timeline date and feed name views.
This commit is contained in:
parent
01b5292e3d
commit
f11604df48
|
@ -140,6 +140,7 @@
|
|||
84D5BA20201E8FB6009092BD /* SidebarGearMenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D5BA1F201E8FB6009092BD /* SidebarGearMenuDelegate.swift */; };
|
||||
84DAEE301F86CAFE0058304B /* OPMLImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DAEE2F1F86CAFE0058304B /* OPMLImporter.swift */; };
|
||||
84DAEE321F870B390058304B /* DockBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DAEE311F870B390058304B /* DockBadge.swift */; };
|
||||
84E185B3203B74E500F69BFA /* SingleLineTextFieldSizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E185B2203B74E500F69BFA /* SingleLineTextFieldSizer.swift */; };
|
||||
84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */; };
|
||||
84E850861FCB60CE0072EA88 /* AuthorAvatarDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E850851FCB60CE0072EA88 /* AuthorAvatarDownloader.swift */; };
|
||||
84E8E0DB202EC49300562D8F /* TimelineViewController+ContextualMenus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */; };
|
||||
|
@ -661,6 +662,7 @@
|
|||
84D5BA1F201E8FB6009092BD /* SidebarGearMenuDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarGearMenuDelegate.swift; sourceTree = "<group>"; };
|
||||
84DAEE2F1F86CAFE0058304B /* OPMLImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLImporter.swift; sourceTree = "<group>"; };
|
||||
84DAEE311F870B390058304B /* DockBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DockBadge.swift; path = Evergreen/DockBadge.swift; sourceTree = "<group>"; };
|
||||
84E185B2203B74E500F69BFA /* SingleLineTextFieldSizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleLineTextFieldSizer.swift; sourceTree = "<group>"; };
|
||||
84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDefaults.swift; path = Evergreen/AppDefaults.swift; sourceTree = "<group>"; };
|
||||
84E850851FCB60CE0072EA88 /* AuthorAvatarDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorAvatarDownloader.swift; sourceTree = "<group>"; };
|
||||
84E8E0DA202EC49300562D8F /* TimelineViewController+ContextualMenus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TimelineViewController+ContextualMenus.swift"; sourceTree = "<group>"; };
|
||||
|
@ -1008,6 +1010,7 @@
|
|||
849A97741ED9EC04007D329B /* TimelineTableCellView.swift */,
|
||||
849A97701ED9EC04007D329B /* TimelineCellAppearance.swift */,
|
||||
849A97721ED9EC04007D329B /* TimelineCellLayout.swift */,
|
||||
84E185B2203B74E500F69BFA /* SingleLineTextFieldSizer.swift */,
|
||||
849A97711ED9EC04007D329B /* TimelineCellData.swift */,
|
||||
849A97731ED9EC04007D329B /* TimelineStringUtilities.swift */,
|
||||
849A97751ED9EC04007D329B /* UnreadIndicatorView.swift */,
|
||||
|
@ -2001,6 +2004,7 @@
|
|||
849A97851ED9ECCD007D329B /* PreferencesWindowController.swift in Sources */,
|
||||
D5F4EDB720074D6500B9E363 /* Feed+Scriptability.swift in Sources */,
|
||||
84E850861FCB60CE0072EA88 /* AuthorAvatarDownloader.swift in Sources */,
|
||||
84E185B3203B74E500F69BFA /* SingleLineTextFieldSizer.swift in Sources */,
|
||||
8414AD251FCF5A1E00955102 /* TimelineHeaderView.swift in Sources */,
|
||||
849EE71F20391DF20082A1EA /* MainWindowToolbarDelegate.swift in Sources */,
|
||||
849A977A1ED9EC04007D329B /* TimelineTableCellView.swift in Sources */,
|
||||
|
|
|
@ -28,8 +28,10 @@ struct SidebarCellLayout {
|
|||
}
|
||||
self.faviconRect = rFavicon
|
||||
|
||||
textField.sizeToFit()
|
||||
let textFieldSize = textField.frame.size
|
||||
// textField.sizeToFit()
|
||||
// let textFieldSize = textField.fittingSize//frame.size
|
||||
let textFieldSize = SingleLineTextFieldSizer.size(for: textField.stringValue, font: textField.font!)
|
||||
|
||||
var rTextField = NSRect(x: 0.0, y: 0.0, width: textFieldSize.width, height: textFieldSize.height)
|
||||
if shouldShowImage {
|
||||
rTextField.origin.x = NSMaxX(rFavicon) + appearance.imageMarginRight
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// SingleLineTextFieldSizer.swift
|
||||
// Evergreen
|
||||
//
|
||||
// Created by Brent Simmons on 2/19/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
// Get the size of an NSTextField configured with a specific font with a specific size.
|
||||
// Uses a cache.
|
||||
|
||||
final class SingleLineTextFieldSizer {
|
||||
|
||||
let font: NSFont
|
||||
private let textField: NSTextField
|
||||
private var cache = [String: NSSize]()
|
||||
|
||||
init(font: NSFont) {
|
||||
|
||||
self.textField = NSTextField(labelWithString: "")
|
||||
self.textField.font = font
|
||||
self.font = font
|
||||
}
|
||||
|
||||
func size(for text: String) -> NSSize {
|
||||
|
||||
if let cachedSize = cache[text] {
|
||||
return cachedSize
|
||||
}
|
||||
|
||||
textField.stringValue = text
|
||||
var calculatedSize = textField.fittingSize
|
||||
calculatedSize.height = ceil(calculatedSize.height)
|
||||
calculatedSize.width = ceil(calculatedSize.width)
|
||||
|
||||
cache[text] = calculatedSize
|
||||
return calculatedSize
|
||||
}
|
||||
|
||||
static private var sizers = [NSFont: SingleLineTextFieldSizer]()
|
||||
|
||||
static func sizer(for font: NSFont) -> SingleLineTextFieldSizer {
|
||||
|
||||
if let cachedSizer = sizers[font] {
|
||||
return cachedSizer
|
||||
}
|
||||
|
||||
let newSizer = SingleLineTextFieldSizer(font: font)
|
||||
sizers[font] = newSizer
|
||||
|
||||
return newSizer
|
||||
}
|
||||
|
||||
static func size(for text: String, font: NSFont) -> NSSize {
|
||||
|
||||
return sizer(for: font).size(for: text)
|
||||
}
|
||||
}
|
|
@ -107,13 +107,15 @@ private extension TimelineCellLayout {
|
|||
|
||||
static func rectOfLineBelow(_ textBoxRect: NSRect, _ rectAbove: NSRect, _ topMargin: CGFloat, _ attributedString: NSAttributedString) -> NSRect {
|
||||
|
||||
let renderer = RSSingleLineRenderer(attributedTitle: attributedString)
|
||||
let font = attributedString.attribute(NSAttributedStringKey.font, at: 0, effectiveRange: nil) as! NSFont
|
||||
let textFieldSize = SingleLineTextFieldSizer.size(for: attributedString.string, font: font)
|
||||
// let renderer = RSSingleLineRenderer(attributedTitle: attributedString)
|
||||
var r = NSZeroRect
|
||||
r.size = renderer.size
|
||||
r.size = textFieldSize
|
||||
r.origin.y = NSMaxY(rectAbove) + topMargin
|
||||
r.origin.x = textBoxRect.origin.x
|
||||
|
||||
var width = renderer.size.width
|
||||
var width = textFieldSize.width
|
||||
width = min(width, textBoxRect.size.width)
|
||||
width = max(width, 0.0)
|
||||
r.size.width = width
|
||||
|
|
|
@ -13,29 +13,18 @@ class TimelineTableCellView: NSTableCellView {
|
|||
|
||||
private let titleView = RSMultiLineView(frame: NSZeroRect)
|
||||
private let unreadIndicatorView = UnreadIndicatorView(frame: NSZeroRect)
|
||||
private let dateView = RSSingleLineView(frame: NSZeroRect)
|
||||
private let feedNameView = RSSingleLineView(frame: NSZeroRect)
|
||||
private let dateView = TimelineTableCellView.singleLineTextField()
|
||||
private let feedNameView = TimelineTableCellView.singleLineTextField()
|
||||
private let avatarImageView = TimelineTableCellView.imageView(with: AppImages.genericFeedImage, scaling: .scaleProportionallyDown)
|
||||
private let starView = TimelineTableCellView.imageView(with: AppImages.timelineStar, scaling: .scaleNone)
|
||||
|
||||
private let avatarImageView: NSImageView = {
|
||||
let imageView = NSImageView(frame: NSRect.zero)
|
||||
imageView.imageScaling = .scaleProportionallyDown
|
||||
imageView.animates = false
|
||||
imageView.imageAlignment = .alignCenter
|
||||
imageView.image = AppImages.genericFeedImage
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private let starView: NSImageView = {
|
||||
let imageView = NSImageView(frame: NSRect.zero)
|
||||
imageView.imageScaling = .scaleNone
|
||||
imageView.animates = false
|
||||
imageView.imageAlignment = .alignCenter
|
||||
imageView.image = AppImages.timelineStar
|
||||
return imageView
|
||||
private lazy var textFields = {
|
||||
return [self.dateView, self.feedNameView]
|
||||
}()
|
||||
|
||||
var cellAppearance: TimelineCellAppearance! {
|
||||
didSet {
|
||||
updateTextFields()
|
||||
needsLayout = true
|
||||
}
|
||||
}
|
||||
|
@ -60,20 +49,18 @@ class TimelineTableCellView: NSTableCellView {
|
|||
|
||||
var isEmphasized = false {
|
||||
didSet {
|
||||
dateView.emphasized = isEmphasized
|
||||
feedNameView.emphasized = isEmphasized
|
||||
titleView.emphasized = isEmphasized
|
||||
unreadIndicatorView.isEmphasized = isEmphasized
|
||||
updateTextFieldColors()
|
||||
needsDisplay = true
|
||||
}
|
||||
}
|
||||
|
||||
var isSelected = false {
|
||||
didSet {
|
||||
dateView.selected = isSelected
|
||||
feedNameView.selected = isSelected
|
||||
titleView.selected = isSelected
|
||||
unreadIndicatorView.isSelected = isSelected
|
||||
updateTextFieldColors()
|
||||
needsDisplay = true
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +129,48 @@ class TimelineTableCellView: NSTableCellView {
|
|||
|
||||
private extension TimelineTableCellView {
|
||||
|
||||
static func singleLineTextField() -> NSTextField {
|
||||
|
||||
let textField = NSTextField(labelWithString: "")
|
||||
textField.usesSingleLineMode = true
|
||||
textField.maximumNumberOfLines = 1
|
||||
textField.isEditable = false
|
||||
textField.lineBreakMode = .byTruncatingTail
|
||||
return textField
|
||||
}
|
||||
|
||||
static func imageView(with image: NSImage?, scaling: NSImageScaling) -> NSImageView {
|
||||
|
||||
let imageView = image != nil ? NSImageView(image: image!) : NSImageView(frame: NSRect.zero)
|
||||
imageView.animates = false
|
||||
imageView.imageAlignment = .alignCenter
|
||||
imageView.imageScaling = scaling
|
||||
return imageView
|
||||
}
|
||||
|
||||
func updateTextFieldColors() {
|
||||
|
||||
if isEmphasized && isSelected {
|
||||
textFields.forEach { $0.textColor = NSColor.white }
|
||||
}
|
||||
else {
|
||||
feedNameView.textColor = cellAppearance.feedNameColor
|
||||
dateView.textColor = cellAppearance.dateColor
|
||||
}
|
||||
}
|
||||
|
||||
func updateTextFieldFonts() {
|
||||
|
||||
feedNameView.font = cellAppearance.feedNameFont
|
||||
dateView.font = cellAppearance.dateFont
|
||||
}
|
||||
|
||||
func updateTextFields() {
|
||||
|
||||
updateTextFieldColors()
|
||||
updateTextFieldFonts()
|
||||
}
|
||||
|
||||
func addSubviewAtInit(_ view: NSView, hidden: Bool) {
|
||||
|
||||
addSubview(view)
|
||||
|
@ -184,7 +213,7 @@ private extension TimelineTableCellView {
|
|||
|
||||
func updateDateView() {
|
||||
|
||||
dateView.attributedStringValue = cellData.attributedDateString
|
||||
dateView.stringValue = cellData.attributedDateString.string
|
||||
needsLayout = true
|
||||
}
|
||||
|
||||
|
@ -194,7 +223,7 @@ private extension TimelineTableCellView {
|
|||
if feedNameView.isHidden {
|
||||
feedNameView.isHidden = false
|
||||
}
|
||||
feedNameView.attributedStringValue = cellData.attributedFeedName
|
||||
feedNameView.stringValue = cellData.attributedFeedName.string
|
||||
}
|
||||
else {
|
||||
if !feedNameView.isHidden {
|
||||
|
|
|
@ -64,17 +64,17 @@ class TimelineTableRowView : NSTableRowView {
|
|||
path.stroke()
|
||||
}
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
|
||||
super.draw(dirtyRect)
|
||||
|
||||
if cellAppearance.drawsGrid && !isSelected && !isNextRowSelected {
|
||||
drawSeparator(in: dirtyRect)
|
||||
}
|
||||
}
|
||||
// override func draw(_ dirtyRect: NSRect) {
|
||||
//
|
||||
// super.draw(dirtyRect)
|
||||
//
|
||||
// if cellAppearance.drawsGrid && !isSelected && !isNextRowSelected {
|
||||
// drawSeparator(in: dirtyRect)
|
||||
// }
|
||||
// }
|
||||
|
||||
func invalidateGridRect() {
|
||||
|
||||
setNeedsDisplay(gridRect)
|
||||
// setNeedsDisplay(gridRect)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue