mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-12 01:17:29 +01:00
157 lines
4.7 KiB
Swift
157 lines
4.7 KiB
Swift
|
//
|
||
|
// TimelineCellLayout.swift
|
||
|
// Evergreen
|
||
|
//
|
||
|
// Created by Brent Simmons on 2/6/16.
|
||
|
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
||
|
//
|
||
|
|
||
|
import Cocoa
|
||
|
import RSTextDrawing
|
||
|
import RSCore
|
||
|
|
||
|
// title/text 1 date
|
||
|
// title/text 2
|
||
|
// title/text 3
|
||
|
// favicon feedname (optional line)
|
||
|
|
||
|
struct TimelineCellLayout {
|
||
|
|
||
|
let width: CGFloat
|
||
|
let height: CGFloat
|
||
|
let faviconRect: NSRect
|
||
|
let feedNameRect: NSRect
|
||
|
let dateRect: NSRect
|
||
|
let titleRect: NSRect
|
||
|
let unreadIndicatorRect: NSRect
|
||
|
let paddingBottom: CGFloat
|
||
|
|
||
|
init(width: CGFloat, faviconRect: NSRect, feedNameRect: NSRect, dateRect: NSRect, titleRect: NSRect, unreadIndicatorRect: NSRect, paddingBottom: CGFloat) {
|
||
|
|
||
|
self.width = width
|
||
|
self.faviconRect = faviconRect
|
||
|
self.feedNameRect = feedNameRect
|
||
|
self.dateRect = dateRect
|
||
|
self.titleRect = titleRect
|
||
|
self.unreadIndicatorRect = unreadIndicatorRect
|
||
|
self.paddingBottom = paddingBottom
|
||
|
|
||
|
var height = NSMaxY(dateRect)
|
||
|
if feedNameRect != NSZeroRect {
|
||
|
height = NSMaxY(feedNameRect)
|
||
|
}
|
||
|
height = height + paddingBottom
|
||
|
|
||
|
self.height = height
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private func rectForDate(_ cellData: TimelineCellData, _ width: CGFloat, _ appearance: TimelineCellAppearance, _ titleRect: NSRect) -> NSRect {
|
||
|
|
||
|
let renderer = RSSingleLineRenderer(attributedTitle: cellData.attributedDateString)
|
||
|
var r = NSZeroRect
|
||
|
r.size = renderer.size
|
||
|
// r.origin.y = appearance.cellPadding.top
|
||
|
// r.origin.x = width - (appearance.cellPadding.right + r.size.width)
|
||
|
|
||
|
r.origin.y = NSMaxY(titleRect) + appearance.titleBottomMargin
|
||
|
r.origin.x = appearance.boxLeftMargin
|
||
|
|
||
|
r.size.width = width - (r.origin.x + appearance.cellPadding.right)
|
||
|
if r.size.width < 15 {
|
||
|
return NSZeroRect
|
||
|
}
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
private func rectForFeedName(_ cellData: TimelineCellData, _ width: CGFloat, _ appearance: TimelineCellAppearance, _ titleRect: NSRect) -> NSRect {
|
||
|
|
||
|
if !cellData.showFeedName {
|
||
|
return NSZeroRect
|
||
|
}
|
||
|
|
||
|
let renderer = RSSingleLineRenderer(attributedTitle: cellData.attributedFeedName)
|
||
|
var r = NSZeroRect
|
||
|
r.size = renderer.size
|
||
|
r.origin.y = NSMaxY(titleRect) + appearance.titleBottomMargin
|
||
|
r.origin.x = appearance.boxLeftMargin
|
||
|
|
||
|
if let _ = cellData.favicon {
|
||
|
r.origin.x += appearance.faviconSize.width + appearance.faviconFeedNameSpacing
|
||
|
}
|
||
|
|
||
|
r.size.width = width - (r.origin.x + appearance.cellPadding.right)
|
||
|
|
||
|
if r.size.width < 15 {
|
||
|
return NSZeroRect
|
||
|
}
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
private func rectForFavicon(_ cellData: TimelineCellData, _ appearance: TimelineCellAppearance, _ feedNameRect: NSRect) -> NSRect {
|
||
|
|
||
|
guard let _ = cellData.favicon, cellData.showFeedName else {
|
||
|
return NSZeroRect
|
||
|
}
|
||
|
|
||
|
var r = NSZeroRect
|
||
|
r.size = appearance.faviconSize
|
||
|
r.origin.x = appearance.boxLeftMargin
|
||
|
|
||
|
r = RSRectCenteredVerticallyInRect(r, feedNameRect)
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
private func rectsForTitle(_ cellData: TimelineCellData, _ width: CGFloat, _ appearance: TimelineCellAppearance) -> (NSRect, NSRect) {
|
||
|
|
||
|
var r = NSZeroRect
|
||
|
r.origin.x = appearance.boxLeftMargin
|
||
|
r.origin.y = appearance.cellPadding.top
|
||
|
|
||
|
let textWidth = width - (r.origin.x + appearance.cellPadding.right)
|
||
|
let renderer = RSMultiLineRenderer(attributedTitle: cellData.attributedTitle)
|
||
|
|
||
|
let measurements = renderer.measurements(forWidth: textWidth)
|
||
|
r.size = NSSize(width: textWidth, height: CGFloat(measurements.height))
|
||
|
|
||
|
var rline1 = r
|
||
|
rline1.size.height = CGFloat(measurements.heightOfFirstLine)
|
||
|
|
||
|
return (r, rline1)
|
||
|
}
|
||
|
|
||
|
private func rectForUnreadIndicator(_ cellData: TimelineCellData, _ appearance: TimelineCellAppearance, _ titleLine1Rect: NSRect) -> NSRect {
|
||
|
|
||
|
if cellData.read {
|
||
|
return NSZeroRect
|
||
|
}
|
||
|
|
||
|
var r = NSZeroRect
|
||
|
r.size = NSSize(width: appearance.unreadCircleDimension, height: appearance.unreadCircleDimension)
|
||
|
r.origin.x = appearance.cellPadding.left
|
||
|
r = RSRectCenteredVerticallyInRect(r, titleLine1Rect)
|
||
|
|
||
|
return r
|
||
|
}
|
||
|
|
||
|
func timelineCellLayout(_ width: CGFloat, cellData: TimelineCellData, appearance: TimelineCellAppearance) -> TimelineCellLayout {
|
||
|
|
||
|
// let dateRect = rectForDate(cellData, width, appearance)
|
||
|
let (titleRect, titleLine1Rect) = rectsForTitle(cellData, width, appearance)
|
||
|
let dateRect = rectForDate(cellData, width, appearance, titleRect)
|
||
|
let feedNameRect = rectForFeedName(cellData, width, appearance, titleRect)
|
||
|
let faviconRect = rectForFavicon(cellData, appearance, feedNameRect)
|
||
|
let unreadIndicatorRect = rectForUnreadIndicator(cellData, appearance, titleLine1Rect)
|
||
|
|
||
|
return TimelineCellLayout(width: width, faviconRect: faviconRect, feedNameRect: feedNameRect, dateRect: dateRect, titleRect: titleRect, unreadIndicatorRect: unreadIndicatorRect, paddingBottom: appearance.cellPadding.bottom)
|
||
|
}
|
||
|
|
||
|
func timelineCellHeight(_ width: CGFloat, cellData: TimelineCellData, appearance: TimelineCellAppearance) -> CGFloat {
|
||
|
|
||
|
let layout = timelineCellLayout(width, cellData: cellData, appearance: appearance)
|
||
|
return layout.height
|
||
|
}
|