- rewrite Popup view

- improve popup view updates and resizes
- add scrollView to popup view (need to display a lot of sensors)
This commit is contained in:
Serhiy Mytrovtsiy
2020-10-31 19:34:28 +01:00
parent 9d2010ad6b
commit e5808b8556
13 changed files with 181 additions and 143 deletions

View File

@@ -78,7 +78,7 @@ open class Module: Module_p {
private var settingsView: Settings_v? = nil
private var popup: NSWindow = NSWindow()
private var popupView: NSView? = nil
private var popupView: Popup_p? = nil
private let log: OSLog
private var store: UnsafePointer<Store>
@@ -94,7 +94,7 @@ open class Module: Module_p {
private var ready: Bool = false
private var widgetLoaded: Bool = false
public init(store: UnsafePointer<Store>, popup: NSView?, settings: Settings_v?) {
public init(store: UnsafePointer<Store>, popup: Popup_p?, settings: Settings_v?) {
self.config = module_c(in: Bundle(for: type(of: self)).path(forResource: "config", ofType: "plist")!)
self.log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: self.config.name)
@@ -122,7 +122,6 @@ open class Module: Module_p {
NotificationCenter.default.addObserver(self, selector: #selector(listenForWidgetSwitch), name: .switchWidget, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenForMouseDownInSettings), name: .clickInSettings, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenForModuleToggle), name: .toggleModule, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenChangingPopupSize), name: .updatePopupSize, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenResignActive), name: NSApplication.willResignActiveNotification, object: nil)
if self.config.widgetsConfig.count != 0 {
@@ -242,7 +241,7 @@ open class Module: Module_p {
}
// replace a popup view
public func replacePopup(_ view: NSView) {
public func replacePopup(_ view: Popup_p) {
self.popup.setIsVisible(false)
self.popupView = view
self.popup = PopupWindow(title: self.config.name, view: self.popupView, visibilityCallback: self.visibilityCallback)
@@ -373,14 +372,6 @@ open class Module: Module_p {
}
}
@objc private func listenChangingPopupSize(_ notification: Notification) {
if let moduleName = notification.userInfo?["module"] as? String, moduleName == self.config.name {
if self.popup.isVisible {
self.popup.setIsVisible(false)
}
}
}
@objc private func listenResignActive(_ notification: Notification) {
self.visibilityCallback(false)
}

View File

@@ -12,10 +12,14 @@
import Cocoa
import StatsKit
public protocol Popup_p: NSView {
var sizeCallback: ((NSSize) -> Void)? { get set }
}
internal class PopupWindow: NSPanel {
private let viewController: PopupViewController = PopupViewController()
init(title: String, view: NSView?, visibilityCallback: @escaping (_ state: Bool) -> Void) {
init(title: String, view: Popup_p?, visibilityCallback: @escaping (_ state: Bool) -> Void) {
self.viewController.setup(title: title, view: view)
self.viewController.visibilityCallback = visibilityCallback
@@ -45,7 +49,12 @@ internal class PopupViewController: NSViewController {
private var popup: PopupView
public init() {
self.popup = PopupView(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width + (Constants.Popup.margins * 2), height: Constants.Popup.height+Constants.Popup.headerHeight))
self.popup = PopupView(frame: NSRect(
x: 0,
y: 0,
width: Constants.Popup.width + (Constants.Popup.margins * 2),
height: Constants.Popup.height+Constants.Popup.headerHeight
))
super.init(nibName: nil, bundle: nil)
}
@@ -75,42 +84,51 @@ internal class PopupViewController: NSViewController {
self.visibilityCallback(false)
}
public func setup(title: String, view: NSView?) {
public func setup(title: String, view: Popup_p?) {
self.title = title
self.popup.title = title
self.popup.headerView?.titleView?.stringValue = title
self.popup.setTitle(title)
self.popup.setView(view)
}
}
internal class PopupView: NSView {
public var headerView: HeaderView? = nil
public var title: String? = nil
private var mainView: NSView? = nil
private var title: String? = nil
private let header: HeaderView
private let body: NSScrollView
override var intrinsicContentSize: CGSize {
var h: CGFloat = self.mainView?.subviews.first?.frame.height ?? 0
if h != 0 {
h += Constants.Popup.margins*2
}
return CGSize(width: self.frame.size.width, height: h + Constants.Popup.headerHeight)
return CGSize(width: self.frame.width, height: self.frame.height)
}
override init(frame: NSRect) {
self.header = HeaderView(frame: NSRect(
x: 0,
y: frame.height - Constants.Popup.headerHeight,
width: frame.width,
height: Constants.Popup.headerHeight
))
self.body = NSScrollView(frame: NSRect(
x: Constants.Popup.margins,
y: Constants.Popup.margins,
width: frame.width,
height: frame.height - self.header.frame.height - Constants.Popup.margins*2
))
super.init(frame: CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.width, height: frame.height))
self.wantsLayer = true
self.canDrawConcurrently = true
self.layer!.cornerRadius = 3
self.layer?.cornerRadius = 3
NotificationCenter.default.addObserver(self, selector: #selector(listenChangingPopupSize), name: .updatePopupSize, object: nil)
self.headerView = HeaderView(frame: NSRect(x: 0, y: frame.height - Constants.Popup.headerHeight, width: frame.width, height: Constants.Popup.headerHeight))
self.body.translatesAutoresizingMaskIntoConstraints = true
self.body.borderType = .noBorder
self.body.hasVerticalScroller = true
self.body.hasHorizontalScroller = false
self.body.autohidesScrollers = true
self.body.horizontalScrollElasticity = .none
let mainView: NSView = NSView(frame: NSRect(x: Constants.Popup.margins, y: Constants.Popup.margins, width: frame.width - (Constants.Popup.margins*2), height: 0))
self.addSubview(self.headerView!)
self.addSubview(mainView)
self.mainView = mainView
self.addSubview(self.header)
self.addSubview(self.body)
}
required init?(coder: NSCoder) {
@@ -118,53 +136,62 @@ internal class PopupView: NSView {
}
override func updateLayer() {
if self.mainView!.subviews.count != 0 {
if self.mainView?.frame.height != self.mainView!.subviews.first!.frame.size.height {
self.setHeight(self.mainView!.subviews.first!.frame.size)
}
}
self.layer!.backgroundColor = self.isDarkMode ? NSColor.windowBackgroundColor.cgColor : NSColor.white.cgColor
}
public func setView(_ view: NSView?) {
if view == nil {
self.setFrameSize(NSSize(width: Constants.Popup.width+(Constants.Popup.margins*2), height: Constants.Popup.headerHeight))
self.headerView?.setFrameOrigin(NSPoint(x: 0, y: 0))
return
}
public func setView(_ view: Popup_p?) {
let width: CGFloat = (view?.frame.width ?? Constants.Popup.width) + (Constants.Popup.margins*2)
let height: CGFloat = (view?.frame.height ?? 0) + Constants.Popup.headerHeight + (Constants.Popup.margins*2)
self.mainView?.addSubview(view!)
self.setHeight(view!.frame.size)
self.setFrameSize(NSSize(width: width, height: height))
self.header.setFrameOrigin(NSPoint(x: 0, y: height - Constants.Popup.headerHeight))
self.body.setFrameSize(NSSize(width: (view?.frame.width ?? Constants.Popup.width), height: (view?.frame.height ?? 0)))
if let view = view {
self.body.documentView = view
view.sizeCallback = { [weak self] size in
var isScrollVisible: Bool = false
var windowSize: NSSize = NSSize(
width: size.width + (Constants.Popup.margins*2),
height: size.height + Constants.Popup.headerHeight + (Constants.Popup.margins*2)
)
if let screenHeight = NSScreen.main?.frame.height, windowSize.height > screenHeight {
windowSize.height = screenHeight - Constants.Widget.height - 6
isScrollVisible = true
}
if let screenWidth = NSScreen.main?.frame.width, windowSize.width > screenWidth {
windowSize.width = screenWidth
}
self?.window?.setContentSize(windowSize)
self?.body.setFrameSize(NSSize(
width: windowSize.width - (Constants.Popup.margins*2) + (isScrollVisible ? 20 : 0),
height: windowSize.height - Constants.Popup.headerHeight - (Constants.Popup.margins*2)
))
self?.header.setFrameOrigin(NSPoint(
x: self?.header.frame.origin.x ?? 0,
y: (self?.body.frame.height ?? 0) + (Constants.Popup.margins*2)
))
}
}
}
private func setHeight(_ size: CGSize) {
DispatchQueue.main.async(execute: {
self.mainView?.setFrameSize(NSSize(width: self.mainView!.frame.width, height: size.height))
self.setFrameSize(NSSize(width: size.width + (Constants.Popup.margins*2), height: size.height + Constants.Popup.headerHeight + Constants.Popup.margins*2))
self.headerView?.setFrameOrigin(NSPoint(x: 0, y: self.frame.height - Constants.Popup.headerHeight))
var frame = self.window?.frame
frame?.size = self.frame.size
self.window?.setFrame(frame!, display: true)
})
public func setTitle(_ newTitle: String) {
self.title = newTitle
self.header.setTitle(newTitle)
}
internal func appear() {
self.display()
self.mainView?.subviews.first{ !($0 is HeaderView) }?.display()
self.body.subviews.first?.display()
}
internal func disappear() {}
@objc private func listenChangingPopupSize(_ notification: Notification) {
if let moduleName = notification.userInfo?["module"] as? String, moduleName == self.title {
self.updateLayer()
}
}
}
internal class HeaderView: NSView {
public var titleView: NSTextField? = nil
private var titleView: NSTextField? = nil
private var activityButton: NSButton?
private var settingsButton: NSButton?
@@ -237,6 +264,10 @@ internal class HeaderView: NSView {
))
}
public func setTitle(_ newTitle: String) {
self.titleView?.stringValue = newTitle
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
@@ -290,59 +321,3 @@ internal class HeaderView: NSView {
)
}
}
public class ProcessView: NSView {
public var width: CGFloat {
get { return 0 }
set {
self.setFrameSize(NSSize(width: newValue, height: self.frame.height))
}
}
public var icon: NSImage? {
get { return NSImage() }
set {
self.imageView?.image = newValue
}
}
public var label: String {
get { return "" }
set {
self.labelView?.stringValue = newValue
}
}
public var value: String {
get { return "" }
set {
self.valueView?.stringValue = newValue
}
}
private var imageView: NSImageView? = nil
private var labelView: LabelField? = nil
private var valueView: ValueField? = nil
public init(_ n: CGFloat) {
super.init(frame: NSRect(x: 0, y: n*22, width: Constants.Popup.width, height: 16))
let rowView: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 16))
let imageView: NSImageView = NSImageView(frame: NSRect(x: 2, y: 2, width: 12, height: 12))
let labelView: LabelField = LabelField(frame: NSRect(x: 18, y: 0.5, width: rowView.frame.width - 70 - 18, height: 15), "")
let valueView: ValueField = ValueField(frame: NSRect(x: 18 + labelView.frame.width, y: 0, width: 70, height: 16), "")
rowView.addSubview(imageView)
rowView.addSubview(labelView)
rowView.addSubview(valueView)
self.imageView = imageView
self.labelView = labelView
self.valueView = valueView
self.addSubview(rowView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@@ -13,7 +13,7 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var store: UnsafePointer<Store>
private var title: String
@@ -58,6 +58,8 @@ internal class Popup: NSView {
}
}
public var sizeCallback: ((NSSize) -> Void)? = nil
public init(_ title: String, store: UnsafePointer<Store>) {
self.store = store
self.title = title
@@ -104,14 +106,14 @@ internal class Popup: NSView {
let h: CGFloat = self.dashboardHeight + self.detailsHeight + self.batteryHeight + self.adapterHeight + self.processesHeight
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": self.title])
self.grid?.setFrameSize(NSSize(width: self.frame.width, height: h))
self.grid?.row(at: 4).cell(at: 0).contentView?.removeFromSuperview()
self.grid?.removeRow(at: 4)
self.grid?.addRow(with: [self.initProcesses()])
self.processesInitialized = false
self.sizeCallback?(self.frame.size)
})
}

View File

@@ -13,7 +13,7 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var store: UnsafePointer<Store>
private var title: String
@@ -41,6 +41,8 @@ internal class Popup: NSView {
private var processes: [ProcessView] = []
private var maxFreq: Double = 0
public var sizeCallback: ((NSSize) -> Void)? = nil
private var numberOfProcesses: Int {
get {
return self.store.pointee.int(key: "\(self.title)_processes", defaultValue: 8)
@@ -100,14 +102,14 @@ internal class Popup: NSView {
let h: CGFloat = self.dashboardHeight + self.chartHeight + self.detailsHeight + self.processesHeight
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": self.title])
self.grid?.setFrameSize(NSSize(width: self.frame.width, height: h))
self.grid?.row(at: 3).cell(at: 0).contentView?.removeFromSuperview()
self.grid?.removeRow(at: 3)
self.grid?.addRow(with: [self.initProcesses()])
self.processesInitialized = false
self.sizeCallback?(self.frame.size)
})
}

View File

@@ -13,10 +13,12 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
let diskFullHeight: CGFloat = 60
var list: [String: DiskView] = [:]
public var sizeCallback: ((NSSize) -> Void)? = nil
public init() {
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
}
@@ -54,7 +56,7 @@ internal class Popup: NSView {
let h: CGFloat = ((self.diskFullHeight + Constants.Popup.margins) * CGFloat(self.list.count)) - Constants.Popup.margins
if self.frame.size.height != h {
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": "Disk"])
self.sizeCallback?(self.frame.size)
}
})
}

View File

@@ -13,9 +13,11 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var list: [Int: FanView] = [:]
public var sizeCallback: ((NSSize) -> Void)? = nil
public init() {
super.init(frame: NSRect( x: 0, y: 0, width: Constants.Popup.width, height: 0))
}

View File

@@ -13,10 +13,12 @@ import Cocoa
import StatsKit
import ModuleKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var list: [String: GPUView] = [:]
private let gpuViewHeight: CGFloat = 162
public var sizeCallback: ((NSSize) -> Void)? = nil
public init() {
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
}
@@ -51,7 +53,7 @@ internal class Popup: NSView {
let h: CGFloat = ((self.gpuViewHeight + Constants.Popup.margins) * CGFloat(self.list.count)) - Constants.Popup.margins
if self.frame.size.height != h {
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": "GPU"])
self.sizeCallback?(self.frame.size)
}
})
}

View File

@@ -13,7 +13,7 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var store: UnsafePointer<Store>
private var title: String
@@ -52,6 +52,8 @@ internal class Popup: NSView {
}
}
public var sizeCallback: ((NSSize) -> Void)? = nil
public init(_ title: String, store: UnsafePointer<Store>) {
self.store = store
self.title = title
@@ -100,14 +102,14 @@ internal class Popup: NSView {
let h: CGFloat = self.dashboardHeight + self.chartHeight + self.detailsHeight + self.processesHeight
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": self.title])
self.grid?.setFrameSize(NSSize(width: self.frame.width, height: h))
self.grid?.row(at: 3).cell(at: 0).contentView?.removeFromSuperview()
self.grid?.removeRow(at: 3)
self.grid?.addRow(with: [self.initProcesses()])
self.processesInitialized = false
self.sizeCallback?(self.frame.size)
})
}

View File

@@ -13,7 +13,7 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var store: UnsafePointer<Store>
private var title: String
@@ -66,6 +66,8 @@ internal class Popup: NSView {
}
}
public var sizeCallback: ((NSSize) -> Void)? = nil
public init(_ title: String, store: UnsafePointer<Store>) {
self.store = store
self.title = title
@@ -110,14 +112,14 @@ internal class Popup: NSView {
let h: CGFloat = self.dashboardHeight + self.chartHeight + self.detailsHeight + self.processesHeight
self.setFrameSize(NSSize(width: self.frame.width, height: h))
NotificationCenter.default.post(name: .updatePopupSize, object: nil, userInfo: ["module": self.title])
self.grid?.setFrameSize(NSSize(width: self.frame.width, height: h))
self.grid?.row(at: 3).cell(at: 0).contentView?.removeFromSuperview()
self.grid?.removeRow(at: 3)
self.grid?.addRow(with: [self.initProcesses()])
self.processesInitialized = false
self.sizeCallback?(self.frame.size)
})
}

View File

@@ -13,9 +13,11 @@ import Cocoa
import ModuleKit
import StatsKit
internal class Popup: NSView {
internal class Popup: NSView, Popup_p {
private var list: [String: NSTextField] = [:]
public var sizeCallback: ((NSSize) -> Void)? = nil
public init() {
super.init(frame: NSRect( x: 0, y: 0, width: Constants.Popup.width, height: 0))
}
@@ -68,6 +70,7 @@ internal class Popup: NSView {
}
self.setFrameSize(NSSize(width: self.frame.width, height: y - Constants.Popup.margins))
self.sizeCallback?(self.frame.size)
}
internal func usageCallback(_ values: [Sensor_t]) {

View File

@@ -140,7 +140,7 @@
"Battery" = "Bateria";
"Amperage" = "Natężenie";
"Voltage" = "Napięcie";
"Temperature" = "Termaratura";
"Temperature" = "Temperatura";
"Power adapter" = "Zasilacz";
"Power" = "Moc";
"Is charging" = "Ładuje";

View File

@@ -390,7 +390,6 @@ public extension Notification.Name {
static let checkForUpdates = Notification.Name("checkForUpdates")
static let changeCronInterval = Notification.Name("changeCronInterval")
static let clickInSettings = Notification.Name("clickInSettings")
static let updatePopupSize = Notification.Name("updatePopupSize")
}
public class NSButtonWithPadding: NSButton {

View File

@@ -645,3 +645,59 @@ public func SysctlByName(_ name: String) -> Int64 {
return num
}
public class ProcessView: NSView {
public var width: CGFloat {
get { return 0 }
set {
self.setFrameSize(NSSize(width: newValue, height: self.frame.height))
}
}
public var icon: NSImage? {
get { return NSImage() }
set {
self.imageView?.image = newValue
}
}
public var label: String {
get { return "" }
set {
self.labelView?.stringValue = newValue
}
}
public var value: String {
get { return "" }
set {
self.valueView?.stringValue = newValue
}
}
private var imageView: NSImageView? = nil
private var labelView: LabelField? = nil
private var valueView: ValueField? = nil
public init(_ n: CGFloat) {
super.init(frame: NSRect(x: 0, y: n*22, width: 264, height: 16))
let rowView: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 16))
let imageView: NSImageView = NSImageView(frame: NSRect(x: 2, y: 2, width: 12, height: 12))
let labelView: LabelField = LabelField(frame: NSRect(x: 18, y: 0.5, width: rowView.frame.width - 70 - 18, height: 15), "")
let valueView: ValueField = ValueField(frame: NSRect(x: 18 + labelView.frame.width, y: 0, width: 70, height: 16), "")
rowView.addSubview(imageView)
rowView.addSubview(labelView)
rowView.addSubview(valueView)
self.imageView = imageView
self.labelView = labelView
self.valueView = valueView
self.addSubview(rowView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}