NetNewsWire/Evergreen/MainWindow/Timeline/Cell/TimelineCellLayout.swift
2017-11-27 13:16:08 -08:00

166 lines
5.1 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 avatarImageRect: NSRect
let paddingBottom: CGFloat
init(width: CGFloat, faviconRect: NSRect, feedNameRect: NSRect, dateRect: NSRect, titleRect: NSRect, unreadIndicatorRect: NSRect, avatarImageRect: NSRect, paddingBottom: CGFloat) {
self.width = width
self.faviconRect = faviconRect
self.feedNameRect = feedNameRect
self.dateRect = dateRect
self.titleRect = titleRect
self.unreadIndicatorRect = unreadIndicatorRect
self.avatarImageRect = avatarImageRect
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
}
private func rectForAvatar(_ cellData: TimelineCellData, _ appearance: TimelineCellAppearance, _ unreadIndictarRect: NSRect) -> NSRect {
// TODO
return NSRect.zero
}
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)
let avatarImageRect = rectForAvatar(cellData, appearance, unreadIndicatorRect)
return TimelineCellLayout(width: width, faviconRect: faviconRect, feedNameRect: feedNameRect, dateRect: dateRect, titleRect: titleRect, unreadIndicatorRect: unreadIndicatorRect, avatarImageRect: avatarImageRect, paddingBottom: appearance.cellPadding.bottom)
}
func timelineCellHeight(_ width: CGFloat, cellData: TimelineCellData, appearance: TimelineCellAppearance) -> CGFloat {
let layout = timelineCellLayout(width, cellData: cellData, appearance: appearance)
return layout.height
}