diff --git a/ModuleKit/Widgets/BarChart.swift b/ModuleKit/Widgets/BarChart.swift index 718d39e2..0f014ddd 100644 --- a/ModuleKit/Widgets/BarChart.swift +++ b/ModuleKit/Widgets/BarChart.swift @@ -88,7 +88,7 @@ public class BarChart: Widget { style.alignment = .center let stringAttributes = [ NSAttributedString.Key.font: NSFont.systemFont(ofSize: 7, weight: .regular), - NSAttributedString.Key.foregroundColor: NSColor.labelColor, + NSAttributedString.Key.foregroundColor: NSColor.textColor, NSAttributedString.Key.paragraphStyle: style ] diff --git a/ModuleKit/Widgets/LineChart.swift b/ModuleKit/Widgets/LineChart.swift index 8070f085..ff7e3e11 100644 --- a/ModuleKit/Widgets/LineChart.swift +++ b/ModuleKit/Widgets/LineChart.swift @@ -85,7 +85,7 @@ public class LineChart: Widget { style.alignment = .center let stringAttributes = [ NSAttributedString.Key.font: NSFont.systemFont(ofSize: 7, weight: .regular), - NSAttributedString.Key.foregroundColor: NSColor.labelColor, + NSAttributedString.Key.foregroundColor: NSColor.textColor, NSAttributedString.Key.paragraphStyle: style ] diff --git a/ModuleKit/Widgets/Network.swift b/ModuleKit/Widgets/Network.swift index 018d4618..7b19e365 100644 --- a/ModuleKit/Widgets/Network.swift +++ b/ModuleKit/Widgets/Network.swift @@ -115,7 +115,7 @@ public class NetworkWidget: Widget { if self.downloadValue >= 1_024 { NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).setFill() } else { - NSColor.labelColor.setFill() + NSColor.textColor.setFill() } downloadCircle.fill() @@ -124,7 +124,7 @@ public class NetworkWidget: Widget { if self.uploadValue >= 1_024 { NSColor.red.setFill() } else { - NSColor.labelColor.setFill() + NSColor.textColor.setFill() } uploadCircle.fill() } @@ -143,7 +143,7 @@ public class NetworkWidget: Widget { if self.downloadValue >= 1_024 { NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).set() } else { - NSColor.labelColor.set() + NSColor.textColor.set() } downloadArrow.lineWidth = 1 downloadArrow.stroke() @@ -157,7 +157,7 @@ public class NetworkWidget: Widget { if self.uploadValue >= 1_024 { NSColor.red.set() } else { - NSColor.labelColor.set() + NSColor.textColor.set() } uploadArrow.lineWidth = 1 uploadArrow.stroke() @@ -169,7 +169,7 @@ public class NetworkWidget: Widget { let downloadAttributes = [ NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9, weight: .regular), - NSAttributedString.Key.foregroundColor: downloadValue >= 1_024 ? NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8) : NSColor.labelColor, + NSAttributedString.Key.foregroundColor: downloadValue >= 1_024 ? NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8) : NSColor.textColor, NSAttributedString.Key.paragraphStyle: NSMutableParagraphStyle() ] var rect = CGRect(x: Constants.Widget.margin, y: 1, width: 8, height: rowHeight) @@ -178,7 +178,7 @@ public class NetworkWidget: Widget { let uploadAttributes = [ NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9, weight: .regular), - NSAttributedString.Key.foregroundColor: uploadValue >= 1_024 ? NSColor.red : NSColor.labelColor, + NSAttributedString.Key.foregroundColor: uploadValue >= 1_024 ? NSColor.red : NSColor.textColor, NSAttributedString.Key.paragraphStyle: NSMutableParagraphStyle() ] rect = CGRect(x: Constants.Widget.margin, y: rect.height+1, width: 8, height: rowHeight) diff --git a/ModuleKit/Widgets/Sensors.swift b/ModuleKit/Widgets/Sensors.swift index 33af1c2c..fdee0cb3 100644 --- a/ModuleKit/Widgets/Sensors.swift +++ b/ModuleKit/Widgets/Sensors.swift @@ -79,13 +79,13 @@ public class SensorsWidget: Widget { var x: CGFloat = Constants.Widget.margin for i in 0.. + private var button: NSPopUpButton? + private let list: UnsafeMutablePointer<[Sensor_t]> + public var callback: (() -> Void) = {} + + public init(_ title: String, store: UnsafePointer, list: UnsafeMutablePointer<[Sensor_t]>) { + self.title = title + self.store = store + self.list = list + super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0)) + self.wantsLayer = true + self.canDrawConcurrently = true + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func load(widget: widget_t) { + guard !self.list.pointee.isEmpty else { + return + } + self.subviews.forEach{ $0.removeFromSuperview() } + + var types: [SensorType_t: Int] = [:] + self.list.pointee.forEach { (s: Sensor_t) in + types[s.type] = (types[s.type] ?? 0) + 1 + } + + let rowHeight: CGFloat = 30 + let height: CGFloat = ((rowHeight+Constants.Settings.margin) * CGFloat(self.list.pointee.count)) + ((rowHeight+Constants.Settings.margin) * CGFloat(types.count)) + let x: CGFloat = height < 360 ? 0 : Constants.Settings.margin + let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: self.frame.width - (Constants.Settings.margin*2) - x, height: height)) + + var y: CGFloat = 0 + types.sorted{ $0.1 < $1.1 }.forEach { (t: (key: SensorType_t, value: Int)) in + let filtered = self.list.pointee.filter{ $0.type == t.key } + var groups: [SensorGroup_t: Int] = [:] + filtered.forEach { (s: Sensor_t) in + groups[s.group] = (groups[s.group] ?? 0) + 1 + } + + groups.sorted{ $0.1 < $1.1 }.forEach { (g: (key: SensorGroup_t, value: Int)) in + filtered.reversed().filter{ $0.group == g.key }.forEach { (s: Sensor_t) in + let row: NSView = ToggleTitleRow( + frame: NSRect(x: 0, y: y, width: view.frame.width, height: rowHeight), + title: s.name, + action: #selector(self.handleSelection), + state: s.state + ) + row.subviews.filter{ $0 is NSControl }.forEach { (control: NSView) in + control.identifier = NSUserInterfaceItemIdentifier(rawValue: s.key) + } + view.addSubview(row) + y += rowHeight + Constants.Settings.margin + } + } + + let rowTitleView: NSView = NSView(frame: NSRect(x: 0, y: y, width: view.frame.width, height: rowHeight)) + let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (rowHeight-19)/2, width: view.frame.width, height: 19), t.key) + rowTitle.font = NSFont.systemFont(ofSize: 14, weight: .regular) + rowTitle.textColor = .secondaryLabelColor + rowTitle.alignment = .center + rowTitleView.addSubview(rowTitle) + + view.addSubview(rowTitleView) + y += rowHeight + Constants.Settings.margin + } + + self.addSubview(view) + self.setFrameSize(NSSize(width: self.frame.width, height: height + (Constants.Settings.margin*1))) + } + + @objc func handleSelection(_ sender: NSControl) { + guard let id = sender.identifier else { return } + + var state: NSControl.StateValue? = nil + if #available(OSX 10.15, *) { + state = sender is NSSwitch ? (sender as! NSSwitch).state: nil + } else { + state = sender is NSButton ? (sender as! NSButton).state: nil + } + + self.store.pointee.set(key: "sensor_\(id.rawValue)", value: state! == NSControl.StateValue.on) + self.callback() + } +} diff --git a/ModuleKit/module.swift b/ModuleKit/module.swift index 85114264..2682f5f6 100644 --- a/ModuleKit/module.swift +++ b/ModuleKit/module.swift @@ -103,13 +103,7 @@ open class Module: Module_p { os_log(.debug, log: log, "Module started without widget") } - self.settings = Settings(config: &self.config, enabled: self.enabled, activeWidget: self.widget, moduleSettings: { [weak self] (_ superview: NSView) in - if self != nil && self?.settingsView != nil { - self!.settingsView!.load(rect: superview.frame, widget: self!.activeWidget) - superview.setFrameSize(NSSize(width: superview.frame.width, height: self!.settingsView!.frame.height)) - superview.addSubview(self!.settingsView!) - } - }) + self.settings = Settings(config: &self.config, enabled: self.enabled, activeWidget: self.widget, moduleSettings: self.settingsView) self.settings?.toggleCallback = { [weak self] in self?.toggleEnabled() } diff --git a/ModuleKit/popup.swift b/ModuleKit/popup.swift index 3c1c2714..b83e742d 100644 --- a/ModuleKit/popup.swift +++ b/ModuleKit/popup.swift @@ -161,11 +161,11 @@ internal class HeaderView: NSView { titleView.isSelectable = false titleView.isBezeled = false titleView.wantsLayer = true - titleView.textColor = .labelColor + titleView.textColor = .textColor titleView.backgroundColor = .clear titleView.canDrawSubviewsIntoLayer = true titleView.alignment = .center - titleView.font = NSFont.systemFont(ofSize: 16, weight: .medium) + titleView.font = NSFont.systemFont(ofSize: 16, weight: .regular) titleView.stringValue = "" self.titleView = titleView diff --git a/ModuleKit/settings.swift b/ModuleKit/settings.swift index 0ea1eec7..06c19f6d 100644 --- a/ModuleKit/settings.swift +++ b/ModuleKit/settings.swift @@ -17,7 +17,8 @@ public protocol Settings_p: NSView { } public protocol Settings_v: NSView { - func load(rect: NSRect, widget: widget_t) + var callback: (() -> Void) { get set } + func load(widget: widget_t) } open class Settings: NSView, Settings_p { @@ -33,38 +34,57 @@ open class Settings: NSView, Settings_p { private var config: UnsafePointer private var activeWidget: Widget_p? - private var moduleSettings: (_ superview: NSView) -> () + private var moduleSettings: Settings_v? - init(config: UnsafePointer, enabled: Bool, activeWidget: Widget_p?, moduleSettings: @escaping (_ superview: NSView) -> ()) { + init(config: UnsafePointer, enabled: Bool, activeWidget: Widget_p?, moduleSettings: Settings_v?) { self.config = config self.activeWidget = activeWidget self.moduleSettings = moduleSettings super.init(frame: NSRect(x: 0, y: 0, width: Constants.Settings.width, height: Constants.Settings.height)) self.wantsLayer = true + self.appearance = NSAppearance(named: .aqua) self.layer?.backgroundColor = NSColor(hexString: "#ececec").cgColor addHeader(state: enabled) addWidgetSelector() addWidgetSettings() - addModuleSettings() + if self.moduleSettings != nil { + self.moduleSettings?.load(widget: self.activeWidget?.type ?? .unknown) + addModuleSettings() + } } private func addModuleSettings() { - let y: CGFloat = self.frame.height - headerHeight - widgetSelectorHeight - (self.widgetSettingsView?.frame.height ?? 0) - let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: y - (Constants.Settings.margin*3), width: self.frame.width - (Constants.Settings.margin*2), height: 0)) + guard self.moduleSettings?.frame.height != 0 else { + return + } + + let maxHeight: CGFloat = Constants.Settings.height - self.headerHeight - self.widgetSelectorHeight - (self.widgetSettingsView?.frame.height ?? 0) - (Constants.Settings.margin*3) + let h: CGFloat = self.moduleSettings!.frame.height > maxHeight ? maxHeight : self.moduleSettings!.frame.height + var y: CGFloat = Constants.Settings.height - self.headerHeight - self.widgetSelectorHeight - (self.widgetSettingsView?.frame.height ?? 0) - (Constants.Settings.margin*3) - h + if y == 0 { + y = Constants.Settings.margin + } + + let view: NSScrollView = NSScrollView(frame: NSRect( + x: Constants.Settings.margin, + y: y, + width: self.frame.width - (Constants.Settings.margin*2), + height: h + )) view.wantsLayer = true view.layer?.backgroundColor = .white view.layer!.cornerRadius = 3 + view.translatesAutoresizingMaskIntoConstraints = true + view.borderType = .noBorder + view.hasVerticalScroller = true + view.autohidesScrollers = true - self.appearance = NSAppearance(named: .aqua) + view.documentView = self.moduleSettings + view.documentView?.scroll(NSPoint(x: 0, y: view.documentView!.bounds.size.height)) - self.moduleSettings(view) - - if view.frame.height != 0 { - view.setFrameOrigin(NSPoint(x: view.frame.origin.x, y: view.frame.origin.y - view.frame.height)) - self.addSubview(view) - self.moduleSettingsView = view - } + self.addSubview(view) + self.moduleSettingsView = view } private func addWidgetSettings() { @@ -184,7 +204,10 @@ open class Settings: NSView, Settings_p { self.subviews.filter{ $0 == self.widgetSettingsView || $0 == self.moduleSettingsView }.forEach{ $0.removeFromSuperview() } self.addWidgetSettings() - self.addModuleSettings() + if self.moduleSettings != nil { + self.moduleSettings?.load(widget: self.activeWidget?.type ?? .unknown) + addModuleSettings() + } } required public init?(coder: NSCoder) { diff --git a/Modules/CPU/main.swift b/Modules/CPU/main.swift index c0a852ab..b3f58e61 100644 --- a/Modules/CPU/main.swift +++ b/Modules/CPU/main.swift @@ -49,6 +49,10 @@ public class CPU: Module { settings: self.settingsView ) + self.settingsView.callback = { [unowned self] in + self.loadReader.read() + } + self.loadReader.readyCallback = { [unowned self] in self.readyHandler() } diff --git a/Modules/CPU/settings.swift b/Modules/CPU/settings.swift index d4c0d0ab..dc68d149 100644 --- a/Modules/CPU/settings.swift +++ b/Modules/CPU/settings.swift @@ -19,10 +19,12 @@ internal class Settings: NSView, Settings_v { private let title: String private let store: UnsafePointer? + public var callback: (() -> Void) = {} + public init(_ title: String, store: UnsafePointer?) { self.title = title self.store = store - super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: 0, height: 0)) + super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0)) self.wantsLayer = true self.canDrawConcurrently = true @@ -35,15 +37,15 @@ internal class Settings: NSView, Settings_v { fatalError("init(coder:) has not been implemented") } - public func load(rect: NSRect, widget: widget_t) { + public func load(widget: widget_t) { self.subviews.forEach{ $0.removeFromSuperview() } - let rowHeight: CGFloat = 30 + let rowHeight: CGFloat = 29 var height: CGFloat = 0 if widget == .barChart { self.addSubview(ToggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 0, width: rect.width - (Constants.Settings.margin*2), height: rowHeight), + frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0, width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight), title: "Show hyper-threading cores", action: #selector(toggleMultithreading), state: self.hyperthreadState @@ -54,7 +56,7 @@ internal class Settings: NSView, Settings_v { if height != 0 { height += (Constants.Settings.margin*2) } - self.setFrameSize(NSSize(width: rect.width - (Constants.Settings.margin*2), height: height)) + self.setFrameSize(NSSize(width: self.frame.width, height: height)) } @objc func toggleMultithreading(_ sender: NSControl) { @@ -67,5 +69,6 @@ internal class Settings: NSView, Settings_v { self.hyperthreadState = state! == .on ? true : false self.store?.pointee.set(key: "\(self.title)_hyperhreading", value: self.hyperthreadState) + self.callback() } } diff --git a/Modules/Disk/settings.swift b/Modules/Disk/settings.swift index 3bd7ee57..6e473dff 100644 --- a/Modules/Disk/settings.swift +++ b/Modules/Disk/settings.swift @@ -15,6 +15,7 @@ import ModuleKit internal class Settings: NSView, Settings_v { public var selectedDiskHandler: (String) -> Void = {_ in } + public var callback: (() -> Void) = {} private let title: String private let store: UnsafePointer @@ -25,7 +26,7 @@ internal class Settings: NSView, Settings_v { self.title = title self.store = store self.selectedDisk = store.pointee.string(key: "\(self.title)_disk", defaultValue: "") - super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: 0, height: 0)) + super.init(frame: CGRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0)) self.wantsLayer = true self.canDrawConcurrently = true } @@ -34,22 +35,22 @@ internal class Settings: NSView, Settings_v { fatalError("init(coder:) has not been implemented") } - public func load(rect: NSRect, widget: widget_t) { + public func load(widget: widget_t) { self.subviews.forEach{ $0.removeFromSuperview() } - self.addDiskSelector(rect: rect) + self.addDiskSelector() - self.setFrameSize(NSSize(width: rect.width - (Constants.Settings.margin*2), height: 30 + (Constants.Settings.margin*2))) + self.setFrameSize(NSSize(width: self.frame.width, height: 30 + (Constants.Settings.margin*2))) } - private func addDiskSelector(rect: NSRect) { - let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: rect.width, height: 30)) + private func addDiskSelector() { + let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: self.frame.width, height: 29)) let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (view.frame.height - 16)/2, width: view.frame.width - 52, height: 17), "Disk to show") rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light) - rowTitle.textColor = .labelColor + rowTitle.textColor = .textColor - self.button = NSPopUpButton(frame: NSRect(x: view.frame.width - 164, y: 0, width: 140, height: 30)) + self.button = NSPopUpButton(frame: NSRect(x: view.frame.width - 164, y: -1, width: 140, height: 30)) self.button!.target = self self.button?.action = #selector(self.handleSelection) @@ -70,7 +71,7 @@ internal class Settings: NSView, Settings_v { } }) } - + @objc func handleSelection(_ sender: NSPopUpButton) { guard let item = sender.selectedItem else { return } self.selectedDisk = item.title diff --git a/Modules/Net/popup.swift b/Modules/Net/popup.swift index 424121d5..4f8666dc 100644 --- a/Modules/Net/popup.swift +++ b/Modules/Net/popup.swift @@ -80,7 +80,7 @@ internal class Popup: NSView { let valueField = LabelField(frame: NSRect(x: 0, y: 0, width: valueWidth, height: 30), "0") valueField.font = NSFont.systemFont(ofSize: 26, weight: .light) - valueField.textColor = .labelColor + valueField.textColor = .textColor valueField.alignment = .right let unitField = LabelField(frame: NSRect(x: valueField.frame.width, y: 4, width: unitWidth, height: 15), "KB/s") diff --git a/Modules/Sensors/main.swift b/Modules/Sensors/main.swift index df004fac..c59656a2 100644 --- a/Modules/Sensors/main.swift +++ b/Modules/Sensors/main.swift @@ -16,17 +16,24 @@ import StatsKit public class Sensors: Module { private var sensorsReader: SensorsReader private let popupView: Popup = Popup() + private var settingsView: Settings public init(_ store: UnsafePointer?, _ smc: UnsafePointer) { self.sensorsReader = SensorsReader(smc) + self.settingsView = Settings("Disk", store: store!, list: &self.sensorsReader.list) + super.init( store: store, popup: self.popupView, - settings: nil + settings: self.settingsView ) self.popupView.setup(self.sensorsReader.list) + self.settingsView.callback = { [unowned self] in + self.sensorsReader.read() + } + self.sensorsReader.readyCallback = { [unowned self] in self.readyHandler() } @@ -43,12 +50,8 @@ public class Sensors: Module { } self.popupView.usageCallback(value!) - - let value_1 = value?.first{ $0.key == "TC0F" } - let value_2 = value?.first{ $0.key == "TC0P" } - if let widget = self.widget as? SensorsWidget { - widget.setValues([value_1!.formattedMiniValue, value_2!.formattedMiniValue]) + widget.setValues(value?.filter{ $0.state }.map{ $0.formattedMiniValue } ?? []) } } } diff --git a/Modules/Sensors/readers.swift b/Modules/Sensors/readers.swift index cdaa569f..382c6539 100644 --- a/Modules/Sensors/readers.swift +++ b/Modules/Sensors/readers.swift @@ -19,10 +19,9 @@ internal class SensorsReader: Reader<[Sensor_t]> { init(_ smc: UnsafePointer) { self.smc = smc - } - - public override func setup() { + var available: [String] = self.smc.pointee.getAllKeys() + var list: [Sensor_t] = [] available = available.filter({ (key: String) -> Bool in switch key.prefix(1) { @@ -33,19 +32,20 @@ internal class SensorsReader: Reader<[Sensor_t]> { available.forEach { (key: String) in if var sensor = SensorsDict[key] { - sensor.value = self.smc.pointee.getValue(key) + sensor.value = smc.pointee.getValue(key) if sensor.value != nil { sensor.key = key - self.list.append(sensor) + list.append(sensor) } } } + + self.list = list } public override func read() { for i in 0..