feat: now few widgets can be enabled for one module

This commit is contained in:
Serhiy Mytrovtsiy
2021-02-13 16:39:11 +01:00
parent 1761d9cc59
commit 7b2b786b86
35 changed files with 718 additions and 602 deletions

View File

@@ -0,0 +1,26 @@
{
"images" : [
{
"filename" : "baseline_settings_white_18pt_1x.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "baseline_settings_white_18pt_2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "baseline_settings_white_18pt_3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class BarChart: Widget {
public class BarChart: WidgetWrapper {
private var labelState: Bool = true
private var boxState: Bool = true
private var frameState: Bool = false
@@ -26,7 +26,7 @@ public class BarChart: Widget {
private var boxSettingsView: NSView? = nil
private var frameSettingsView: NSView? = nil
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
var widgetTitle: String = title
self.store = store
@@ -68,7 +68,7 @@ public class BarChart: Widget {
y: Constants.Widget.margin.y,
width: Constants.Widget.width + (2*Constants.Widget.margin.x),
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.canDrawConcurrently = true
@@ -228,13 +228,17 @@ public class BarChart: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let settingsNumber: CGFloat = 4
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * settingsNumber) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(ToggleTitleRow(
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 3, width: view.frame.width, height: rowHeight),
@@ -267,7 +271,7 @@ public class BarChart: Widget {
selected: self.colorState.rawValue
))
superview.addSubview(view)
return view
}
@objc private func toggleLabel(_ sender: NSControl) {

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class BatterykWidget: Widget {
public class BatterykWidget: WidgetWrapper {
private var additional: String = "none"
private var timeFormat: String = "short"
private var iconState: Bool = true
@@ -26,7 +26,7 @@ public class BatterykWidget: Widget {
private var charging: Bool = false
private var ACStatus: Bool = false
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
let widgetTitle: String = title
self.store = store
@@ -35,11 +35,11 @@ public class BatterykWidget: Widget {
y: Constants.Widget.margin.y,
width: 30 + (2*Constants.Widget.margin.x),
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.canDrawConcurrently = true
if self.store != nil {
if self.store != nil && !preview {
self.additional = store!.pointee.string(key: "\(self.title)_\(self.type.rawValue)_additional", defaultValue: self.additional)
self.timeFormat = store!.pointee.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat)
self.iconState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_icon", defaultValue: self.iconState)
@@ -265,16 +265,15 @@ public class BatterykWidget: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 3) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: superview.frame.width - (Constants.Settings.margin*2),
height: superview.frame.height - (Constants.Settings.margin*2)
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(SelectRow(
@@ -299,7 +298,7 @@ public class BatterykWidget: Widget {
state: self.colorState
))
superview.addSubview(view)
return view
}
@objc private func toggleAdditional(_ sender: NSMenuItem) {

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class LineChart: Widget {
public class LineChart: WidgetWrapper {
private var labelState: Bool = true
private var boxState: Bool = true
private var frameState: Bool = false
@@ -36,7 +36,7 @@ public class LineChart: Widget {
private var boxSettingsView: NSView? = nil
private var frameSettingsView: NSView? = nil
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
var widgetTitle: String = title
self.store = store
if config != nil {
@@ -69,7 +69,7 @@ public class LineChart: Widget {
y: Constants.Widget.margin.y,
width: self.width + (2*Constants.Widget.margin.x),
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.canDrawConcurrently = true
@@ -247,13 +247,17 @@ public class LineChart: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let settingsNumber: CGFloat = 6
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * settingsNumber) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(ToggleTitleRow(
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 5, width: view.frame.width, height: rowHeight),
@@ -300,7 +304,7 @@ public class LineChart: Widget {
state: self.valueColorState
))
superview.addSubview(view)
return view
}
@objc private func toggleLabel(_ sender: NSControl) {

View File

@@ -12,13 +12,13 @@
import Cocoa
import StatsKit
public class MemoryWidget: Widget {
public class MemoryWidget: WidgetWrapper {
private var orderReversedState: Bool = false
private var value: (String, String) = ("0", "0")
private let store: UnsafePointer<Store>?
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
self.store = store
if config != nil {
var configuration = config!
@@ -42,11 +42,11 @@ public class MemoryWidget: Widget {
y: Constants.Widget.margin.y,
width: 62,
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.canDrawConcurrently = true
if self.store != nil {
if self.store != nil && !preview {
self.orderReversedState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_orderReversed", defaultValue: self.orderReversedState)
}
@@ -102,12 +102,16 @@ public class MemoryWidget: Widget {
})
}
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 1) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(ToggleTitleRow(
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 0, width: view.frame.width, height: rowHeight),
@@ -116,7 +120,7 @@ public class MemoryWidget: Widget {
state: self.orderReversedState
))
superview.addSubview(view)
return view
}
@objc private func toggleOrder(_ sender: NSControl) {

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class Mini: Widget {
public class Mini: WidgetWrapper {
private let store: UnsafePointer<Store>?
private let defaultTitle: String
@@ -34,7 +34,7 @@ public class Mini: Widget {
}
}
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
self.store = store
var widgetTitle: String = title
if config != nil {
@@ -73,11 +73,11 @@ public class Mini: Widget {
y: Constants.Widget.margin.y,
width: Constants.Widget.width + (2*Constants.Widget.margin.x),
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.wantsLayer = true
if let store = self.store {
if let store = self.store, !preview {
self.colorState = widget_c(rawValue: store.pointee.string(key: "\(self.title)_\(self.type.rawValue)_color", defaultValue: self.colorState.rawValue)) ?? self.colorState
self.labelState = store.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_label", defaultValue: self.labelState)
}
@@ -169,12 +169,16 @@ public class Mini: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let height: CGFloat = 60 + (Constants.Settings.margin*3)
let rowHeight: CGFloat = 30
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(ToggleTitleRow(
frame: NSRect(x: 0, y: rowHeight + Constants.Settings.margin, width: view.frame.width, height: rowHeight),
@@ -191,7 +195,7 @@ public class Mini: Widget {
selected: self.colorState.rawValue
))
superview.addSubview(view)
return view
}
@objc private func toggleColor(_ sender: NSMenuItem) {

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class NetworkChart: Widget {
public class NetworkChart: WidgetWrapper {
private var boxState: Bool = false
private var frameState: Bool = false
@@ -31,7 +31,7 @@ public class NetworkChart: Widget {
private var boxSettingsView: NSView? = nil
private var frameSettingsView: NSView? = nil
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
var widgetTitle: String = title
self.store = store
if config != nil {
@@ -45,7 +45,7 @@ public class NetworkChart: Widget {
y: Constants.Widget.margin.y,
width: self.width + (2*Constants.Widget.margin.x),
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.wantsLayer = true
self.canDrawConcurrently = true
@@ -119,13 +119,17 @@ public class NetworkChart: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let settingsNumber: CGFloat = 2
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * settingsNumber) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin, width: superview.frame.width - (Constants.Settings.margin*2), height: superview.frame.height - (Constants.Settings.margin*2)))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: width - (Constants.Settings.margin*2),
height: height
))
self.boxSettingsView = ToggleTitleRow(
frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 1, width: view.frame.width, height: rowHeight),
@@ -143,7 +147,7 @@ public class NetworkChart: Widget {
)
view.addSubview(self.frameSettingsView!)
superview.addSubview(view)
return view
}
@objc private func toggleBox(_ sender: NSControl) {

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class PieChart: Widget {
public class PieChart: WidgetWrapper {
private var labelState: Bool = true
private let store: UnsafePointer<Store>?
@@ -29,7 +29,7 @@ public class PieChart: Widget {
private let size: CGFloat = Constants.Widget.height - (Constants.Widget.margin.y*2) + (Constants.Widget.margin.x*2)
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
var widgetTitle: String = title
self.store = store
if config != nil {
@@ -43,12 +43,12 @@ public class PieChart: Widget {
y: Constants.Widget.margin.y,
width: self.size,
height: Constants.Widget.height - (Constants.Widget.margin.y*2)
), preview: preview)
))
self.wantsLayer = true
self.canDrawConcurrently = true
if let store = self.store {
if let store = self.store, !preview {
self.labelState = store.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_label", defaultValue: self.labelState)
}
@@ -87,7 +87,7 @@ public class PieChart: Widget {
frame = NSRect(x: x, y: 0, width: self.frame.size.height, height: self.frame.size.height)
self.chart.frame = frame
self.setFrameSize(NSSize(width: self.size + x, height: self.frame.size.height))
self.setWidth(self.size + x)
}
public func setValue(_ segments: [circle_segment]) {
@@ -98,16 +98,15 @@ public class PieChart: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 1) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: superview.frame.width - (Constants.Settings.margin*2),
height: superview.frame.height - (Constants.Settings.margin*2)
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(ToggleTitleRow(
@@ -117,7 +116,7 @@ public class PieChart: Widget {
state: self.labelState
))
superview.addSubview(view)
return view
}
@objc private func toggleLabel(_ sender: NSControl) {

View File

@@ -12,14 +12,14 @@
import Cocoa
import StatsKit
public class SensorsWidget: Widget {
public class SensorsWidget: WidgetWrapper {
private var modeState: String = "automatic"
private let store: UnsafePointer<Store>?
private var body: CALayer = CALayer()
private var values: [KeyValue_t] = []
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
self.store = store
if config != nil {
var configuration = config!
@@ -41,7 +41,7 @@ public class SensorsWidget: Widget {
y: Constants.Widget.margin.y,
width: Constants.Widget.width,
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.modeState = store?.pointee.string(key: "\(self.title)_\(self.type.rawValue)_mode", defaultValue: self.modeState) ?? self.modeState
@@ -212,16 +212,15 @@ public class SensorsWidget: Widget {
// MARK: - Settings
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let rowHeight: CGFloat = 30
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 1) + Constants.Settings.margin
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: superview.frame.width - (Constants.Settings.margin*2),
height: superview.frame.height - (Constants.Settings.margin*2)
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(SelectRow(
@@ -232,7 +231,7 @@ public class SensorsWidget: Widget {
selected: self.modeState
))
superview.addSubview(view)
return view
}
@objc private func changeMode(_ sender: NSMenuItem) {

View File

@@ -12,7 +12,7 @@
import Cocoa
import StatsKit
public class SpeedWidget: Widget {
public class SpeedWidget: WidgetWrapper {
private var icon: String = "dots"
private var state: Bool = false
private var valueState: Bool = true
@@ -29,7 +29,7 @@ public class SpeedWidget: Widget {
private let store: UnsafePointer<Store>?
private var width: CGFloat = 58
public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer<Store>?) {
public init(title: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) {
let widgetTitle: String = title
self.store = store
if config != nil {
@@ -46,11 +46,11 @@ public class SpeedWidget: Widget {
y: Constants.Widget.margin.y,
width: width,
height: Constants.Widget.height - (2*Constants.Widget.margin.y)
), preview: preview)
))
self.canDrawConcurrently = true
if self.store != nil {
if self.store != nil && !preview {
self.valueState = store!.pointee.bool(key: "\(self.title)_\(self.type.rawValue)_value", defaultValue: self.valueState)
self.icon = store!.pointee.string(key: "\(self.title)_\(self.type.rawValue)_icon", defaultValue: self.baseValue)
self.baseValue = store!.pointee.string(key: "\(self.title)_base", defaultValue: self.baseValue)
@@ -211,16 +211,15 @@ public class SpeedWidget: Widget {
}
}
public override func settings(superview: NSView) {
public override func settings(width: CGFloat) -> NSView {
let height: CGFloat = 90 + (Constants.Settings.margin*4)
let rowHeight: CGFloat = 30
superview.setFrameSize(NSSize(width: superview.frame.width, height: height))
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: Constants.Settings.margin,
width: superview.frame.width - (Constants.Settings.margin*2),
height: superview.frame.height - (Constants.Settings.margin*2)
width: width - (Constants.Settings.margin*2),
height: height
))
view.addSubview(SelectRow(
@@ -246,7 +245,7 @@ public class SpeedWidget: Widget {
state: self.valueState
))
superview.addSubview(view)
return view
}
@objc private func toggleValue(_ sender: NSControl) {

View File

@@ -14,7 +14,6 @@ public protocol Module_p {
var available: Bool { get }
var enabled: Bool { get }
var widget: Widget_p? { get }
var settings: Settings_p? { get }
func mount()
@@ -73,7 +72,7 @@ open class Module: Module_p {
public var available: Bool = false
public var enabled: Bool = false
public var widget: Widget_p? = nil
public var widgets: [Widget] = []
public var settings: Settings_p? = nil
private var settingsView: Settings_v? = nil
@@ -83,16 +82,6 @@ open class Module: Module_p {
private let log: OSLog
private var store: UnsafePointer<Store>
private var readers: [Reader_p] = []
private var menuBarItem: NSStatusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
private var activeWidget: widget_t {
get {
let widgetStr = self.store.pointee.string(key: "\(self.config.name)_widget", defaultValue: self.config.defaultWidget.rawValue)
return widget_t.allCases.first{ $0.rawValue == widgetStr } ?? widget_t.unknown
}
set {}
}
private var ready: Bool = false
private var widgetLoaded: Bool = false
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")!)
@@ -103,14 +92,10 @@ open class Module: Module_p {
self.popupView = popup
self.available = self.isAvailable()
self.enabled = self.store.pointee.bool(key: "\(self.config.name)_state", defaultValue: self.config.defaultState)
self.menuBarItem.autosaveName = self.config.name
self.menuBarItem.isVisible = self.enabled
if !self.available {
os_log(.debug, log: log, "Module is not available")
self.menuBarItem.length = 0
self.menuBarItem.isVisible = false
if self.enabled {
self.enabled = false
self.store.pointee.set(key: "\(self.config.name)_state", value: false)
@@ -119,26 +104,23 @@ open class Module: Module_p {
return
}
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(listenForPopupToggle), name: .togglePopup, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(listenForToggleWidget), name: .toggleWidget, object: nil)
if self.config.widgetsConfig.count != 0 {
self.initWidget()
self.initWidgets()
} else {
os_log(.debug, log: log, "Module started without widget")
}
self.settings = Settings(config: &self.config, enabled: self.enabled, activeWidget: self.widget, moduleSettings: self.settingsView)
self.settings = Settings(store: store, config: &self.config, widgets: &self.widgets, enabled: self.enabled, moduleSettings: self.settingsView)
self.settings?.toggleCallback = { [weak self] in
self?.toggleEnabled()
}
self.popup = PopupWindow(title: self.config.name, view: self.popupView, visibilityCallback: self.visibilityCallback)
self.menuBarItem.button?.target = self
self.menuBarItem.button?.action = #selector(self.togglePopup)
self.menuBarItem.button?.sendAction(on: [.leftMouseDown, .rightMouseDown])
}
deinit {
@@ -155,6 +137,7 @@ open class Module: Module_p {
reader.initStoreValues(title: self.config.name, store: self.store)
reader.start()
}
self.widgets.forEach{ $0.enable() }
}
// disable module
@@ -170,7 +153,7 @@ open class Module: Module_p {
$0.stop()
$0.terminate()
}
NSStatusBar.system.removeStatusItem(self.menuBarItem)
self.widgets.forEach{ $0.disable() }
os_log(.debug, log: log, "Module terminated")
}
@@ -187,12 +170,7 @@ open class Module: Module_p {
reader.initStoreValues(title: self.config.name, store: self.store)
reader.start()
}
self.menuBarItem.isVisible = true
if self.widget != nil {
self.loadWidget()
} else {
self.initWidget()
}
self.widgets.forEach{ $0.enable() }
os_log(.debug, log: log, "Module enabled")
}
@@ -203,7 +181,7 @@ open class Module: Module_p {
self.enabled = false
self.store.pointee.set(key: "\(self.config.name)_state", value: false)
self.readers.forEach{ $0.stop() }
self.menuBarItem.isVisible = false
self.widgets.forEach{ $0.disable() }
self.popup?.setIsVisible(false)
os_log(.debug, log: log, "Module disabled")
}
@@ -223,22 +201,6 @@ open class Module: Module_p {
os_log(.debug, log: log, "Reader %s was added", "\(reader.self)")
}
// handler for reader, calls when main reader is ready, and return first value
public func readyHandler() {
os_log(.debug, log: log, "Reader report readiness")
self.ready = true
if !self.widgetLoaded {
self.loadWidget()
}
}
// change menu item width
public func widgetWidthHandler(_ width: CGFloat) {
os_log(.debug, log: log, "Widget %s change width to %.2f", "\(type(of: self.widget!))", width)
self.menuBarItem.length = width
}
// replace a popup view
public func replacePopup(_ view: Popup_p) {
self.popup?.setIsVisible(false)
@@ -249,51 +211,15 @@ open class Module: Module_p {
// determine if module is available (can be overrided in module)
open func isAvailable() -> Bool { return true }
// setup menu ber item
private func loadWidget() {
guard self.available && self.enabled && self.ready && self.widget != nil else { return }
DispatchQueue.main.async {
self.menuBarItem.length = self.widget!.frame.width
self.menuBarItem.button?.subviews.forEach{ $0.removeFromSuperview() }
self.menuBarItem.button?.addSubview(self.widget!)
self.widgetLoaded = true
self.widgetDidSet(self.widget?.type ?? .unknown)
}
}
// load the widget and set up. Calls when module init or widget change
private func initWidget() {
// load the widget and set up. Calls when module init
private func initWidgets() {
guard self.available else { return }
self.widget = self.activeWidget.new(module: self.config.name, config: self.config.widgetsConfig, store: self.store)
if self.widget == nil {
self.enabled = false
os_log(.error, log: log, "widget with type %s not found", "\(self.activeWidget)")
return
self.config.availableWidgets.forEach { (widgetType: widget_t) in
if let widget = widgetType.new(module: self.config.name, config: self.config.widgetsConfig, store: self.store) {
self.widgets.append(widget)
}
}
os_log(.debug, log: log, "Successfully initialize widget: %s", "\(String(describing: self.widget!))")
self.widget?.widthHandler = { [weak self] value in
self?.widgetWidthHandler(value)
}
DispatchQueue.global(qos: .background).async {
self.readers.forEach{ $0.read() }
}
if let mainReader = self.readers.first(where: { !$0.optional }) {
self.widget?.setValues(mainReader.getHistory())
}
if self.ready && self.enabled {
self.menuBarItem.length = self.widget!.frame.width
self.menuBarItem.button?.subviews.forEach{ $0.removeFromSuperview() }
self.menuBarItem.button?.addSubview(self.widget!)
self.widgetLoaded = true
}
self.settings?.setActiveWidget(self.widget)
}
// call after widget set up
@@ -312,25 +238,26 @@ open class Module: Module_p {
}
}
@objc private func togglePopup(_ sender: Any) {
let openedWindows = NSApplication.shared.windows.filter{ $0 is NSPanel }
openedWindows.forEach{ $0.setIsVisible(false) }
guard let popup = self.popup else {
@objc private func listenForPopupToggle(_ notification: Notification) {
guard let popup = self.popup,
let name = notification.userInfo?["module"] as? String,
let buttonOrigin = notification.userInfo?["origin"] as? CGPoint,
let buttonCenter = notification.userInfo?["center"] as? CGFloat,
self.config.name == name else {
return
}
let openedWindows = NSApplication.shared.windows.filter{ $0 is NSPanel }
openedWindows.forEach{ $0.setIsVisible(false) }
if popup.occlusionState.rawValue == 8192 {
NSApplication.shared.activate(ignoringOtherApps: true)
popup.contentView?.invalidateIntrinsicContentSize()
let buttonOrigin = self.menuBarItem.button?.window?.frame.origin
let buttonCenter = (self.menuBarItem.button?.window?.frame.width)! / 2
let windowCenter = popup.contentView!.intrinsicContentSize.width / 2
var x = buttonOrigin!.x - windowCenter + buttonCenter
let y = buttonOrigin!.y - popup.contentView!.intrinsicContentSize.height - 3
var x = buttonOrigin.x - windowCenter + buttonCenter
let y = buttonOrigin.y - popup.contentView!.intrinsicContentSize.height - 3
let maxWidth = NSScreen.screens.map{ $0.frame.width }.reduce(0, +)
if x + popup.contentView!.intrinsicContentSize.width > maxWidth {
@@ -359,25 +286,25 @@ open class Module: Module_p {
}
}
@objc private func listenForWidgetSwitch(_ notification: Notification) {
if let moduleName = notification.userInfo?["module"] as? String {
if let widgetName = notification.userInfo?["widget"] as? String {
if moduleName == self.config.name {
if let widgetType = widget_t.allCases.first(where: { $0.rawValue == widgetName }) {
self.activeWidget = widgetType
self.store.pointee.set(key: "\(self.config.name)_widget", value: widgetType.rawValue)
self.initWidget()
self.widgetDidSet(widgetType)
os_log(.debug, log: log, "Widget is changed to: %s", "\(widgetName)")
}
}
}
}
}
@objc private func listenForMouseDownInSettings(_ notification: Notification) {
if let popup = self.popup, popup.isVisible {
self.popup?.setIsVisible(false)
}
}
@objc private func listenForToggleWidget(_ notification: Notification) {
guard let name = notification.userInfo?["module"] as? String, name == self.config.name else {
return
}
let count = self.widgets.filter({ $0.isActive }).count
var state = self.enabled
if count == 0 && self.enabled {
state = false
} else if count != 0 && !self.enabled {
state = true
}
NotificationCenter.default.post(name: .toggleModule, object: nil, userInfo: ["module": self.config.name, "state": state])
}
}

View File

@@ -14,53 +14,50 @@ import StatsKit
public protocol Settings_p: NSView {
var toggleCallback: () -> () { get set }
func setActiveWidget(_ widget: Widget_p?)
}
public protocol Settings_v: NSView {
var callback: (() -> Void) { get set }
func load(widget: widget_t)
func load(widgets: [widget_t])
}
open class Settings: NSView, Settings_p {
public var toggleCallback: () -> () = {}
private let headerHeight: CGFloat = 42
private var widgetSelectorHeight: CGFloat = Constants.Widget.height + (Constants.Settings.margin*2)
private var settingsView: NSView = NSView()
private var widgetSelectorView: NSView? = nil
private var widgetSettingsView: NSView? = nil
private var moduleSettingsView: NSView? = nil
private var config: UnsafePointer<module_c>
private var activeWidget: Widget_p?
private var store: UnsafePointer<Store>
private var widgets: UnsafeMutablePointer<[Widget]>
private var activeWidget: Widget? {
get {
return self.widgets.pointee.first{ $0.isActive }
}
}
private var moduleSettings: Settings_v?
private var enableControl: NSControl?
private var container: ScrollableStackView?
private var widgetSettings: widget_t?
private var moduleSettingsContainer: NSView?
init(config: UnsafePointer<module_c>, enabled: Bool, activeWidget: Widget_p?, moduleSettings: Settings_v?) {
init(store: UnsafePointer<Store>, config: UnsafePointer<module_c>, widgets: UnsafeMutablePointer<[Widget]>, enabled: Bool, moduleSettings: Settings_v?) {
self.store = store
self.config = config
self.activeWidget = activeWidget
self.widgets = widgets
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
NotificationCenter.default.addObserver(self, selector: #selector(externalModuleToggle), name: .toggleModule, object: nil)
self.addHeader(state: enabled)
self.addSettings()
self.addWidgetSelector()
self.addWidgetSettings()
if self.moduleSettings != nil {
self.moduleSettings?.load(widget: self.activeWidget?.type ?? .unknown)
self.addModuleSettings()
}
self.addSubview(self.header(state: enabled))
self.addSubview(self.body())
}
deinit {
@@ -71,157 +68,9 @@ open class Settings: NSView, Settings_p {
fatalError("init(coder:) has not been implemented")
}
private func addSettings() {
let view: NSScrollView = NSScrollView(frame: NSRect(
x: 0,
y: 0,
width: self.frame.width,
height: Constants.Settings.height - self.headerHeight
))
view.wantsLayer = true
view.backgroundColor = NSColor(hexString: "#ececec")
view.translatesAutoresizingMaskIntoConstraints = true
view.borderType = .noBorder
view.hasVerticalScroller = true
view.hasHorizontalScroller = false
view.autohidesScrollers = true
view.horizontalScrollElasticity = .none
let settings: NSView = FlippedView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: 0))
settings.wantsLayer = true
settings.layer?.backgroundColor = NSColor(hexString: "#ececec").cgColor
view.documentView = settings
self.addSubview(view)
self.settingsView = settings
}
// MARK: - Views
private func addWidgetSelector() {
if self.config.pointee.availableWidgets.count == 0 {
self.widgetSelectorHeight = 0
return
}
let view: NSView = NSView(frame: NSRect(
x : Constants.Settings.margin,
y: Constants.Settings.margin,
width: self.settingsView.frame.width - (Constants.Settings.margin*2),
height: self.widgetSelectorHeight
))
view.wantsLayer = true
view.layer?.backgroundColor = .white
view.layer!.cornerRadius = 3
var x: CGFloat = Constants.Settings.margin
for i in 0...self.config.pointee.availableWidgets.count - 1 {
let widgetType = self.config.pointee.availableWidgets[i]
if let widget = widgetType.new(module: self.config.pointee.name, config: self.config.pointee.widgetsConfig, store: nil, preview: true) {
let preview = WidgetPreview(
frame: NSRect(
x: x,
y: Constants.Settings.margin,
width: widget.frame.width + (Constants.Widget.spacing*2),
height: self.widgetSelectorHeight - (Constants.Settings.margin*2)
),
title: self.config.pointee.name,
widget: widget,
state: self.activeWidget?.type == widgetType
)
preview.widthCallback = { [weak self] in
self?.recalculateWidgetSelectorOptionsWidth()
}
view.addSubview(preview)
x += preview.frame.width + Constants.Settings.margin
}
}
self.settingsView.addSubview(view)
self.widgetSelectorView = view
self.resize()
}
private func addWidgetSettings() {
if self.activeWidget == nil {
return
}
var y: CGFloat = Constants.Settings.margin
if self.widgetSelectorView != nil {
y += self.widgetSelectorView!.frame.height + Constants.Settings.margin
}
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: y,
width: self.settingsView.frame.width - (Constants.Settings.margin*2),
height: 0
))
view.wantsLayer = true
view.layer?.backgroundColor = .white
view.layer!.cornerRadius = 3
self.activeWidget?.settings(superview: view)
if view.frame.height != 0 {
self.settingsView.addSubview(view)
self.widgetSettingsView = view
self.resize()
}
}
private func addModuleSettings() {
if self.moduleSettings == nil || self.moduleSettings?.frame.height == 0 {
return
}
var y: CGFloat = Constants.Settings.margin
if self.widgetSelectorView != nil {
y += self.widgetSelectorView!.frame.height + Constants.Settings.margin
}
if self.widgetSettingsView != nil {
y += self.widgetSettingsView!.frame.height + Constants.Settings.margin
}
let view: NSView = NSView(frame: NSRect(
x: Constants.Settings.margin,
y: y,
width: self.settingsView.frame.width - (Constants.Settings.margin*2),
height: self.moduleSettings?.frame.height ?? 0
))
view.wantsLayer = true
view.layer?.backgroundColor = .white
view.layer!.cornerRadius = 3
view.addSubview(self.moduleSettings!)
self.settingsView.addSubview(view)
self.moduleSettingsView = view
self.resize()
}
private func resize() {
var height: CGFloat = Constants.Settings.margin
self.settingsView.subviews.forEach({ (v: NSView) in
height += v.frame.height + Constants.Settings.margin
})
if self.settingsView.frame.height != height {
self.settingsView.setFrameSize(NSSize(width: self.settingsView.frame.width, height: height))
}
}
private func recalculateWidgetSelectorOptionsWidth() {
var x: CGFloat = Constants.Settings.margin
self.widgetSelectorView?.subviews.forEach({ (v: NSView) in
v.setFrameOrigin(NSPoint(x: x, y: v.frame.origin.y))
x += v.frame.width + Constants.Settings.margin
})
}
private func addHeader(state: Bool) {
private func header(state: Bool) -> NSView {
let view: NSView = NSView(frame: NSRect(x: 0, y: self.frame.height - self.headerHeight, width: self.frame.width, height: self.headerHeight))
view.wantsLayer = true
@@ -265,16 +114,134 @@ open class Settings: NSView, Settings_p {
view.addSubview(titleView)
view.addSubview(toggle)
view.addSubview(line)
self.enableControl = toggle
self.addSubview(view)
return view
}
@objc func toggleEnable(_ sender: Any) {
private func body() -> NSView {
let view = ScrollableStackView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: Constants.Settings.height - self.headerHeight))
view.stackView.edgeInsets = NSEdgeInsets(
top: Constants.Settings.margin,
left: Constants.Settings.margin,
bottom: Constants.Settings.margin,
right: Constants.Settings.margin
)
view.stackView.spacing = Constants.Settings.margin
view.wantsLayer = true
view.layer?.backgroundColor = NSColor(hexString: "#ececec").cgColor
self.container = view
self.initWidgetSelector()
self.initModuleSettings()
return view
}
private func initWidgetSelector() {
let container: NSView = NSView(frame: NSRect(x: 0, y: 0, width: 0, height: Constants.Widget.height + (Constants.Settings.margin*2)))
container.wantsLayer = true
container.layer?.backgroundColor = .white
container.layer?.cornerRadius = 3
let view: NSStackView = NSStackView()
view.orientation = .horizontal
view.translatesAutoresizingMaskIntoConstraints = false
view.edgeInsets = NSEdgeInsets(
top: Constants.Settings.margin,
left: Constants.Settings.margin,
bottom: Constants.Settings.margin,
right: Constants.Settings.margin
)
view.spacing = Constants.Settings.margin
for i in 0...self.widgets.pointee.count - 1 {
let preview = WidgetPreview(&self.widgets.pointee[i])
preview.settingsCallback = { [weak self] value in
self?.toggleSettings(value)
}
preview.stateCallback = { [weak self] in
self?.widgetStateCallback()
}
view.addArrangedSubview(preview)
}
container.addSubview(view)
if let view = self.container {
view.stackView.addArrangedSubview(container)
}
NSLayoutConstraint.activate([
container.heightAnchor.constraint(equalToConstant: container.frame.height),
view.heightAnchor.constraint(equalTo: container.heightAnchor),
])
}
private func initModuleSettings() {
guard let settingsView = self.moduleSettings else {
return
}
let container: NSView = NSView(frame: NSRect(x: 0, y: 0, width: 0, height: 0))
container.wantsLayer = true
container.layer?.backgroundColor = .white
container.layer?.cornerRadius = 3
self.moduleSettingsContainer = container
self.moduleSettings?.load(widgets: self.widgets.pointee.filter{ $0.isActive }.map{ $0.type })
container.addSubview(settingsView)
if let view = self.container {
view.stackView.addArrangedSubview(container)
}
NSLayoutConstraint.activate([
container.heightAnchor.constraint(equalTo: settingsView.heightAnchor),
])
}
// MARK: - helpers
private func toggleSettings(_ type: widget_t) {
guard let widget = self.widgets.pointee.first(where: { $0.type == type }) else {
return
}
let container: NSView = NSView()
container.wantsLayer = true
container.layer?.backgroundColor = .white
container.layer?.cornerRadius = 3
let width: CGFloat = (self.container?.clipView.bounds.width ?? self.frame.width) - (Constants.Settings.margin*2)
let settingsView = widget.item.settings(width: width)
container.addSubview(settingsView)
if let view = self.container {
if self.widgetSettings == nil {
view.stackView.insertArrangedSubview(container, at: 1)
self.widgetSettings = type
} else if self.widgetSettings != nil && self.widgetSettings == type {
view.stackView.arrangedSubviews[1].removeFromSuperview()
self.widgetSettings = nil
} else {
view.stackView.arrangedSubviews[1].removeFromSuperview()
self.widgetSettings = type
view.stackView.insertArrangedSubview(container, at: 1)
}
}
NSLayoutConstraint.activate([
container.heightAnchor.constraint(equalTo: settingsView.heightAnchor),
])
}
@objc private func toggleEnable(_ sender: Any) {
self.toggleCallback()
}
@objc func externalModuleToggle(_ notification: Notification) {
@objc private func externalModuleToggle(_ notification: Notification) {
if let name = notification.userInfo?["module"] as? String {
if name == self.config.pointee.name {
if let state = notification.userInfo?["state"] as? Bool {
@@ -284,113 +251,140 @@ open class Settings: NSView, Settings_p {
}
}
public func setActiveWidget(_ widget: Widget_p?) {
self.activeWidget = widget
self.widgetSettingsView?.removeFromSuperview()
self.moduleSettingsView?.removeFromSuperview()
self.widgetSettingsView = nil
self.addWidgetSettings()
if self.moduleSettings != nil {
self.moduleSettings?.load(widget: self.activeWidget?.type ?? .unknown)
self.addModuleSettings()
@objc private func widgetStateCallback() {
guard let container = self.moduleSettingsContainer, let settingsView = self.moduleSettings else {
return
}
container.subviews.forEach{ $0.removeFromSuperview() }
settingsView.load(widgets: self.widgets.pointee.filter{ $0.isActive }.map{ $0.type })
self.moduleSettingsContainer?.addSubview(settingsView)
NSLayoutConstraint.activate([
container.heightAnchor.constraint(equalTo: settingsView.heightAnchor),
])
}
}
open class FlippedView: NSView {
open override var isFlipped: Bool { true }
}
class WidgetPreview: NSView {
private let type: widget_t
private var state: Bool
private let title: String
internal class WidgetPreview: NSStackView {
public var settingsCallback: (widget_t) -> Void = {_ in }
public var stateCallback: () -> Void = {}
public var widthCallback: () -> Void = {}
private var widget: UnsafeMutablePointer<Widget>
private var size: CGFloat = Constants.Widget.height
public init(frame: NSRect, title: String, widget: Widget_p, state: Bool) {
self.type = widget.type
self.state = state
self.title = title
public init(_ widget: UnsafeMutablePointer<Widget>) {
self.widget = widget
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(maybeActivate), name: .switchWidget, object: nil)
super.init(frame: NSRect(
x: 0,
y: 0,
width: widget.pointee.preview.frame.width + self.size + (Constants.Widget.spacing*2),
height: self.size
))
self.wantsLayer = true
self.layer?.cornerRadius = 2
self.layer?.borderColor = self.state ? NSColor.systemBlue.cgColor : NSColor(hexString: "#dddddd").cgColor
self.layer?.borderColor = self.widget.pointee.isActive ? NSColor.systemBlue.cgColor : NSColor(hexString: "#dddddd").cgColor
self.layer?.borderWidth = 1
self.toolTip = LocalizedString("Select widget", widget.pointee.type.name())
self.toolTip = LocalizedString("Select widget", widget.type.name())
self.orientation = .horizontal
self.distribution = .fillProportionally
self.spacing = 0
let container: NSView = NSView(frame: NSRect(
x: Constants.Widget.spacing,
y: 0,
width: frame.width - (Constants.Widget.spacing*2),
height: frame.height
width: widget.pointee.preview.frame.width,
height: self.frame.height
))
container.wantsLayer = true
container.addSubview(widget)
container.addSubview(widget.pointee.preview)
self.addSubview(container)
self.addArrangedSubview(container)
self.addArrangedSubview(self.separator())
self.addArrangedSubview(self.button())
widget.widthHandler = { [weak self] value in
self?.removeTrackingArea((self?.trackingAreas.first)!)
let newWidth = value + (Constants.Widget.spacing*2)
let rect = NSRect(x: 0, y: 0, width: newWidth, height: self!.frame.height)
let trackingArea = NSTrackingArea(rect: rect, options: [NSTrackingArea.Options.activeAlways, NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeInActiveApp], owner: self, userInfo: ["menu": self!.type])
self?.addTrackingArea(trackingArea)
DispatchQueue.main.async(execute: {
container.setFrameSize(NSSize(width: value, height: container.frame.height))
self?.setFrameSize(NSSize(width: newWidth, height: self?.frame.height ?? Constants.Widget.height))
self?.widthCallback()
widget.pointee.preview.widthHandler = { [weak self] value in
self?.trackingAreas.forEach({ (area: NSTrackingArea) in
self?.removeTrackingArea(area)
})
let rect = NSRect(x: Constants.Widget.spacing, y: 0, width: value, height: self!.frame.height)
let trackingArea = NSTrackingArea(rect: rect, options: [NSTrackingArea.Options.activeAlways, NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeInActiveApp], owner: self, userInfo: nil)
self?.addTrackingArea(trackingArea)
}
let rect = NSRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
let trackingArea = NSTrackingArea(rect: rect, options: [NSTrackingArea.Options.activeAlways, NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeInActiveApp], owner: self, userInfo: ["menu": self.type])
self.addTrackingArea(trackingArea)
let rect = NSRect(x: Constants.Widget.spacing, y: 0, width: container.frame.width, height: self.frame.height)
self.addTrackingArea(NSTrackingArea(
rect: rect,
options: [NSTrackingArea.Options.activeAlways, NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeInActiveApp],
owner: self,
userInfo: nil
))
NSLayoutConstraint.activate([
self.widthAnchor.constraint(equalTo: self.widget.pointee.preview.widthAnchor, constant: self.size),
self.heightAnchor.constraint(equalToConstant: self.size)
])
}
private func button() -> NSView {
let button = NSButton(frame: NSRect(x: 0, y: 0, width: self.size, height: self.size))
button.title = LocalizedString("Open widget settings")
button.toolTip = LocalizedString("Open widget settings")
button.bezelStyle = .regularSquare
if let image = Bundle(for: type(of: self)).image(forResource: "widget_settings") {
button.image = image
}
button.imageScaling = .scaleProportionallyDown
button.contentTintColor = .lightGray
button.isBordered = false
button.action = #selector(self.toggleSettings)
button.target = self
button.focusRingType = .none
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalToConstant: button.frame.width),
])
return button
}
private func separator() -> NSView {
let separator = NSView()
separator.widthAnchor.constraint(equalToConstant: 1).isActive = true
separator.wantsLayer = true
separator.layer?.backgroundColor = NSColor(hexString: "#dddddd").cgColor
NSLayoutConstraint.activate([
separator.heightAnchor.constraint(equalToConstant: self.size),
])
return separator
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func toggleSettings() {
self.settingsCallback(self.widget.pointee.type)
}
override func mouseEntered(with: NSEvent) {
self.layer?.borderColor = NSColor.systemBlue.cgColor
NSCursor.pointingHand.set()
}
override func mouseExited(with: NSEvent) {
self.layer?.borderColor = self.state ? NSColor.systemBlue.cgColor : NSColor.tertiaryLabelColor.cgColor
self.layer?.borderColor = self.widget.pointee.isActive ? NSColor.systemBlue.cgColor : NSColor.tertiaryLabelColor.cgColor
NSCursor.arrow.set()
}
override func mouseDown(with: NSEvent) {
if !self.state {
NotificationCenter.default.post(name: .switchWidget, object: nil, userInfo: ["module": self.title, "widget": self.type.rawValue])
}
}
@objc private func maybeActivate(_ notification: Notification) {
if let moduleName = notification.userInfo?["module"] as? String {
if moduleName == self.title {
if let widgetName = notification.userInfo?["widget"] as? String {
if widgetName == self.type.rawValue {
self.layer?.borderColor = NSColor.systemBlue.cgColor
self.state = true
} else {
self.layer?.borderColor = NSColor.tertiaryLabelColor.cgColor
self.state = false
}
}
}
}
self.widget.pointee.toggle()
self.stateCallback()
}
}

View File

@@ -10,6 +10,7 @@
//
import Cocoa
import os.log
import StatsKit
public enum widget_t: String {
@@ -24,37 +25,64 @@ public enum widget_t: String {
case sensors = "sensors"
case memory = "memory"
public func new(module: String, config: NSDictionary?, store: UnsafePointer<Store>?, preview: Bool = false) -> Widget_p? {
var widget: Widget_p? = nil
public func new(module: String, config: NSDictionary?, store: UnsafePointer<Store>?) -> Widget? {
var widget: Widget? = nil
let widgetConfig: NSDictionary? = config?[self.rawValue] as? NSDictionary
switch self {
case .mini:
widget = Mini(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: Mini(title: module, config: widgetConfig, store: store, preview: true),
item: Mini(title: module, config: widgetConfig, store: store)
)
break
case .lineChart:
widget = LineChart(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: LineChart(title: module, config: widgetConfig, store: store, preview: true),
item: LineChart(title: module, config: widgetConfig, store: store)
)
break
case .barChart:
widget = BarChart(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: BarChart(title: module, config: widgetConfig, store: store, preview: true),
item: BarChart(title: module, config: widgetConfig, store: store)
)
break
case .pieChart:
widget = PieChart(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: PieChart(title: module, config: widgetConfig, store: store, preview: true),
item: PieChart(title: module, config: widgetConfig, store: store)
)
break
case .networkChart:
widget = NetworkChart(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: NetworkChart(title: module, config: widgetConfig, store: store, preview: true),
item: NetworkChart(title: module, config: widgetConfig, store: store)
)
break
case .speed:
widget = SpeedWidget(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: SpeedWidget(title: module, config: widgetConfig, store: store, preview: true),
item: SpeedWidget(title: module, config: widgetConfig, store: store)
)
break
case .battery:
widget = BatterykWidget(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: BatterykWidget(title: module, config: widgetConfig, store: store, preview: true),
item: BatterykWidget(title: module, config: widgetConfig, store: store)
)
break
case .sensors:
widget = SensorsWidget(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: SensorsWidget(title: module, config: widgetConfig, store: store, preview: true),
item: SensorsWidget(title: module, config: widgetConfig, store: store)
)
break
case .memory:
widget = MemoryWidget(preview: preview, title: module, config: widgetConfig, store: store)
widget = Widget(self, module: module,
preview: MemoryWidget(title: module, config: widgetConfig, store: store, preview: true),
item: MemoryWidget(title: module, config: widgetConfig, store: store)
)
break
default: break
}
@@ -79,27 +107,25 @@ public enum widget_t: String {
}
extension widget_t: CaseIterable {}
public protocol Widget_p: NSView {
public protocol widget_p: NSView {
var type: widget_t { get }
var title: String { get }
var widthHandler: ((CGFloat) -> Void)? { get set }
func setValues(_ values: [value_t])
func settings(superview: NSView)
func settings(width: CGFloat) -> NSView
}
open class Widget: NSView, Widget_p {
open class WidgetWrapper: NSView, widget_p {
public var type: widget_t
public var title: String
public var widthHandler: ((CGFloat) -> Void)? = nil
private var widthHandlerRetry: Int8 = 0
open override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
}
public init(_ type: widget_t, title: String, frame: NSRect, preview: Bool) {
private var widthHandlerRetry: Int8 = 0
public init(_ type: widget_t, title: String, frame: NSRect) {
self.type = type
self.title = title
@@ -134,6 +160,101 @@ open class Widget: NSView, Widget_p {
// MARK: - stubs
open func settings(superview: NSView) {}
open func settings(width: CGFloat) -> NSView { return NSView() }
open func setValues(_ values: [value_t]) {}
}
public class Widget {
public let type: widget_t
public let module: String
public let preview: widget_p
public let item: widget_p
public var isActive: Bool {
get {
let arr = Store.shared.string(key: "\(self.module)_widget", defaultValue: "").split(separator: ",")
return arr.contains{ $0 == self.type.rawValue }
}
set {
var arr = Store.shared.string(key: "\(self.module)_widget", defaultValue: "").split(separator: ",").map{ String($0) }
if newValue {
arr.append(self.type.rawValue)
} else {
arr.removeAll{ $0 == self.type.rawValue }
}
Store.shared.set(key: "\(self.module)_widget", value: arr.joined(separator: ","))
}
}
private var menuBarItem: NSStatusItem? = nil
private let log: OSLog
public init(_ type: widget_t, module: String, preview: widget_p, item: widget_p) {
self.type = type
self.module = module
self.preview = preview
self.item = item
self.log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: self.module)
self.item.widthHandler = { [weak self] value in
if let s = self {
s.menuBarItem?.length = value
os_log(.debug, log: s.log, "Widget %s change width to %.2f", "\(s.type)", value)
}
}
}
// show item in the menu bar
public func enable() {
guard self.isActive else {
return
}
let item = NSStatusBar.system.statusItem(withLength: self.item.frame.width)
item.autosaveName = "\(self.module)_\(self.type.name())"
item.isVisible = true
item.button?.target = self
item.button?.action = #selector(self.togglePopup)
item.button?.sendAction(on: [.leftMouseDown, .rightMouseDown])
item.button?.addSubview(self.item)
self.menuBarItem = item
os_log(.debug, log: log, "Widget %s enabled", self.type.rawValue)
}
// remove item from the menu bar
public func disable() {
if let item = self.menuBarItem {
item.length = 0
item.isVisible = false
os_log(.debug, log: log, "Widget %s disabled", self.type.rawValue)
}
}
// toggle the widget
public func toggle() {
self.isActive = !self.isActive
if !self.isActive {
self.disable()
} else {
self.enable()
}
NotificationCenter.default.post(name: .toggleWidget, object: nil, userInfo: ["module": self.module])
}
@objc private func togglePopup(_ sender: Any) {
if let window = self.menuBarItem?.button?.window {
NotificationCenter.default.post(name: .togglePopup, object: nil, userInfo: [
"module": self.module,
"origin": window.frame.origin,
"center": window.frame.width/2,
])
}
}
}

View File

@@ -76,9 +76,6 @@ public class Battery: Module {
}
}
self.usageReader?.readyCallback = { [unowned self] in
self.readyHandler()
}
self.usageReader?.callbackHandler = { [unowned self] value in
self.usageCallback(value)
}
@@ -103,26 +100,27 @@ public class Battery: Module {
return sources.count > 0
}
private func usageCallback(_ value: Battery_Usage?) {
if value == nil {
private func usageCallback(_ raw: Battery_Usage?) {
guard let value = raw else {
return
}
self.checkNotification(value: value!)
self.popupView.usageCallback(value!)
if let widget = self.widget as? Mini {
widget.setValue(abs(value!.level))
}
if let widget = self.widget as? BarChart {
widget.setValue([value!.level])
}
if let widget = self.widget as? BatterykWidget {
widget.setValue(
percentage: value?.level ?? 0,
ACStatus: value?.powerSource != "Battery Power",
isCharging: value?.isCharging ?? false,
time: (value?.timeToEmpty == 0 && value?.timeToCharge != 0 ? value?.timeToCharge : value?.timeToEmpty) ?? 0
)
self.checkNotification(value: value)
self.popupView.usageCallback(value)
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as Mini: widget.setValue(abs(value.level))
case let widget as BarChart: widget.setValue([value.level])
case let widget as BatterykWidget:
widget.setValue(
percentage: value.level ,
ACStatus: value.powerSource != "Battery Power",
isCharging: value.isCharging ,
time: value.timeToEmpty == 0 && value.timeToCharge != 0 ? value.timeToCharge : value.timeToEmpty
)
default: break
}
}
}

View File

@@ -224,7 +224,7 @@ internal class Popup: NSView, Popup_p {
self.dashboardBatteryView?.setValue(abs(value.level))
self.levelField?.stringValue = "\(Int(abs(value.level) * 100)) %"
self.sourceField?.stringValue = "\(LocalizedString(value.powerSource))"
self.sourceField?.stringValue = LocalizedString(value.powerSource)
self.timeField?.stringValue = ""
if value.powerSource == "Battery Power" {

View File

@@ -51,11 +51,11 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
let num: CGFloat = widget == .battery ? 3 : 2
let num: CGFloat = widgets.filter{ $0 == .battery }.isEmpty ? 2 : 3
let height: CGFloat = ((rowHeight + Constants.Settings.margin) * num) + Constants.Settings.margin
let levels: [String] = self.levelsList.map { (v: String) -> String in
@@ -91,7 +91,7 @@ internal class Settings: NSView, Settings_v {
selected: "\(self.numberOfProcesses)"
))
if widget == .battery {
if !widgets.filter({ $0 == .battery }).isEmpty {
self.addSubview(SelectRow(
frame: NSRect(
x: Constants.Settings.margin,

View File

@@ -78,9 +78,6 @@ public class CPU: Module {
self.loadReader?.setInterval(value)
}
self.loadReader?.readyCallback = { [unowned self] in
self.readyHandler()
}
self.loadReader?.callbackHandler = { [unowned self] value in
self.loadCallback(value)
}
@@ -116,27 +113,25 @@ public class CPU: Module {
}
}
private func loadCallback(_ value: CPU_Load?) {
guard value != nil else {
private func loadCallback(_ raw: CPU_Load?) {
guard let value = raw else {
return
}
self.popupView.loadCallback(value!)
self.popupView.loadCallback(value)
if let widget = self.widget as? Mini {
widget.setValue(value!.totalUsage)
}
if let widget = self.widget as? LineChart {
widget.setValue(value!.totalUsage)
}
if let widget = self.widget as? BarChart {
widget.setValue(self.usagePerCoreState ? value!.usagePerCore : [value!.totalUsage])
}
if let widget = self.widget as? PieChart {
widget.setValue([
circle_segment(value: value!.systemLoad, color: NSColor.systemRed),
circle_segment(value: value!.userLoad, color: NSColor.systemBlue)
])
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as Mini: widget.setValue(value.totalUsage)
case let widget as LineChart: widget.setValue(value.totalUsage)
case let widget as BarChart: widget.setValue(self.usagePerCoreState ? value.usagePerCore : [value.totalUsage])
case let widget as PieChart:
widget.setValue([
circle_segment(value: value.systemLoad, color: NSColor.systemRed),
circle_segment(value: value.userLoad, color: NSColor.systemBlue)
])
default: break
}
}
}
}

View File

@@ -56,11 +56,11 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
let num: CGFloat = widget == .barChart ? self.hasHyperthreadingCores ? 3 : 2 : 1
let num: CGFloat = !widgets.filter{ $0 == .barChart }.isEmpty ? self.hasHyperthreadingCores ? 3 : 2 : 1
self.addSubview(SelectTitleRow(
frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * num, width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight),
@@ -70,7 +70,7 @@ internal class Settings: NSView, Settings_v {
selected: "\(self.updateIntervalValue) sec"
))
if widget == .barChart {
if !widgets.filter({ $0 == .barChart }).isEmpty {
self.addSubview(ToggleTitleRow(
frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * (num-1), width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight),
title: LocalizedString("Show usage per core"),

View File

@@ -105,9 +105,6 @@ public class Disk: Module {
self.capacityReader?.store = store
self.selectedDisk = store.pointee.string(key: "\(self.config.name)_disk", defaultValue: self.selectedDisk)
self.capacityReader?.readyCallback = { [unowned self] in
self.readyHandler()
}
self.capacityReader?.callbackHandler = { [unowned self] value in
self.capacityCallback(value)
}
@@ -156,17 +153,14 @@ public class Disk: Module {
}
let percentage = Double(usedSpace) / Double(total)
if let widget = self.widget as? Mini {
widget.setValue(percentage)
}
if let widget = self.widget as? BarChart {
widget.setValue([percentage])
}
if let widget = self.widget as? MemoryWidget {
widget.setValue((DiskSize(free).getReadableMemory(), DiskSize(usedSpace).getReadableMemory()))
}
if let widget = self.widget as? SpeedWidget {
widget.setValue(upload: d.stats?.write ?? 0, download: d.stats?.read ?? 0)
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as Mini: widget.setValue(percentage)
case let widget as BarChart: widget.setValue([percentage])
case let widget as MemoryWidget: widget.setValue((DiskSize(free).getReadableMemory(), DiskSize(usedSpace).getReadableMemory()))
case let widget as SpeedWidget: widget.setValue(upload: d.stats?.write ?? 0, download: d.stats?.read ?? 0)
default: break
}
}
}
}

View File

@@ -49,22 +49,20 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
let num: CGFloat = widget != .speed ? 3 : 2
let num: CGFloat = 3
if widget != .speed {
self.intervalSelectView = SelectTitleRow(
frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 2, width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight),
title: LocalizedString("Update interval"),
action: #selector(changeUpdateInterval),
items: ReaderUpdateIntervals.map{ "\($0) sec" },
selected: "\(self.updateIntervalValue) sec"
)
self.intervalSelectView = SelectTitleRow(
frame: NSRect(x: Constants.Settings.margin, y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 2, width: self.frame.width - (Constants.Settings.margin*2), height: rowHeight),
title: LocalizedString("Update interval"),
action: #selector(changeUpdateInterval),
items: ReaderUpdateIntervals.map{ "\($0) sec" },
selected: "\(self.updateIntervalValue) sec"
)
self.addSubview(self.intervalSelectView!)
}
self.addDiskSelector()

View File

@@ -65,9 +65,6 @@ public class Fans: Module {
self.fansReader.setInterval(value)
}
self.fansReader.readyCallback = { [unowned self] in
self.readyHandler()
}
self.fansReader.callbackHandler = { [unowned self] value in
self.usageCallback(value)
}
@@ -85,24 +82,27 @@ public class Fans: Module {
}
}
private func usageCallback(_ value: [Fan]?) {
if value == nil {
private func usageCallback(_ raw: [Fan]?) {
guard let value = raw else {
return
}
self.popupView.usageCallback(value!)
self.popupView.usageCallback(value)
let label: Bool = store.pointee.bool(key: "Fans_label", defaultValue: false)
var list: [KeyValue_t] = []
value!.forEach { (f: Fan) in
value.forEach { (f: Fan) in
if f.state {
let str = label ? "\(f.name.prefix(1).uppercased()): \(f.formattedValue)" : f.formattedValue
list.append(KeyValue_t(key: "Fan#\(f.id)", value: str))
}
}
if let widget = self.widget as? SensorsWidget {
widget.setValues(list)
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as SensorsWidget: widget.setValues(list)
default: break
}
}
}
}

View File

@@ -48,7 +48,7 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
func load(widget: widget_t) {
func load(widgets: [widget_t]) {
guard !self.list.pointee.isEmpty else {
return
}

View File

@@ -93,9 +93,6 @@ public class GPU: Module {
self.infoReader?.smc = smc
self.selectedGPU = store.pointee.string(key: "\(self.config.name)_gpu", defaultValue: self.selectedGPU)
self.infoReader?.readyCallback = { [unowned self] in
self.readyHandler()
}
self.infoReader?.callbackHandler = { [unowned self] value in
self.infoCallback(value)
}
@@ -135,15 +132,15 @@ public class GPU: Module {
return
}
if let widget = self.widget as? Mini {
widget.setValue(utilization)
widget.setTitle(self.showType ? "\(selectedGPU.type)GPU" : nil)
}
if let widget = self.widget as? LineChart {
widget.setValue(utilization)
}
if let widget = self.widget as? BarChart {
widget.setValue([utilization])
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as Mini:
widget.setValue(utilization)
widget.setTitle(self.showType ? "\(selectedGPU.type)GPU" : nil)
case let widget as LineChart: widget.setValue(utilization)
case let widget as BarChart: widget.setValue([utilization])
default: break
}
}
}
}

View File

@@ -50,11 +50,11 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30
let num: CGFloat = widget == .mini ? 3 : 2
let num: CGFloat = widgets.filter{ $0 == .mini }.isEmpty ? 2 : 3
self.addSubview(SelectTitleRow(
frame: NSRect(
@@ -69,7 +69,7 @@ internal class Settings: NSView, Settings_v {
selected: "\(self.updateIntervalValue) sec"
))
if widget == .mini {
if !widgets.filter({ $0 == .mini }).isEmpty {
self.addSubview(ToggleTitleRow(
frame: NSRect(
x: Constants.Settings.margin,

View File

@@ -95,9 +95,6 @@ public class Network: Module {
}
}
self.usageReader?.readyCallback = { [unowned self] in
self.readyHandler()
}
self.usageReader?.callbackHandler = { [unowned self] value in
self.usageCallback(value)
}
@@ -131,16 +128,19 @@ public class Network: Module {
return list.count > 0
}
private func usageCallback(_ value: Network_Usage?) {
guard let value = value else {
private func usageCallback(_ raw: Network_Usage?) {
guard let value = raw else {
return
}
self.popupView.usageCallback(value)
if let widget = self.widget as? SpeedWidget {
widget.setValue(upload: value.bandwidth.upload, download: value.bandwidth.download)
} else if let widget = self.widget as? NetworkChart {
widget.setValue(upload: Double(value.bandwidth.upload), download: Double(value.bandwidth.download))
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as SpeedWidget: widget.setValue(upload: value.bandwidth.upload, download: value.bandwidth.download)
case let widget as NetworkChart: widget.setValue(upload: Double(value.bandwidth.upload), download: Double(value.bandwidth.download))
default: break
}
}
}
}

View File

@@ -54,7 +54,7 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30

View File

@@ -81,9 +81,6 @@ public class RAM: Module {
}
}
self.usageReader?.readyCallback = { [unowned self] in
self.readyHandler()
}
self.usageReader?.callbackHandler = { [unowned self] value in
self.loadCallback(value)
}
@@ -108,30 +105,31 @@ public class RAM: Module {
}
self.popupView.loadCallback(value)
if let widget = self.widget as? Mini {
widget.setValue(value.usage)
widget.setPressure(value.pressureLevel)
}
if let widget = self.widget as? LineChart {
widget.setValue(value.usage)
widget.setPressure(value.pressureLevel)
}
if let widget = self.widget as? BarChart {
widget.setValue([value.usage])
widget.setPressure(value.pressureLevel)
}
if let widget = self.widget as? PieChart {
let total: Double = value.total
widget.setValue([
circle_segment(value: value.app/total, color: NSColor.systemBlue),
circle_segment(value: value.wired/total, color: NSColor.systemOrange),
circle_segment(value: value.compressed/total, color: NSColor.systemPink)
])
}
if let widget = self.widget as? MemoryWidget {
let free = Units(bytes: Int64(value.free)).getReadableMemory()
let used = Units(bytes: Int64(value.used)).getReadableMemory()
widget.setValue((free, used))
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as Mini:
widget.setValue(value.usage)
widget.setPressure(value.pressureLevel)
case let widget as LineChart:
widget.setValue(value.usage)
widget.setPressure(value.pressureLevel)
case let widget as BarChart:
widget.setValue([value.usage])
widget.setPressure(value.pressureLevel)
case let widget as PieChart:
let total: Double = value.total == 0 ? 1 : value.total
widget.setValue([
circle_segment(value: value.app/total, color: NSColor.systemBlue),
circle_segment(value: value.wired/total, color: NSColor.systemOrange),
circle_segment(value: value.compressed/total, color: NSColor.systemPink)
])
case let widget as MemoryWidget:
let free = Units(bytes: Int64(value.free)).getReadableMemory()
let used = Units(bytes: Int64(value.used)).getReadableMemory()
widget.setValue((free, used))
default: break
}
}
}
}

View File

@@ -45,7 +45,7 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
self.subviews.forEach{ $0.removeFromSuperview() }
let rowHeight: CGFloat = 30

View File

@@ -40,9 +40,6 @@ public class Sensors: Module {
self.sensorsReader.setInterval(value)
}
self.sensorsReader.readyCallback = { [unowned self] in
self.readyHandler()
}
self.sensorsReader.callbackHandler = { [unowned self] value in
self.usageCallback(value)
}
@@ -60,21 +57,25 @@ public class Sensors: Module {
}
}
private func usageCallback(_ value: [Sensor_t]?) {
if value == nil {
private func usageCallback(_ raw: [Sensor_t]?) {
guard let value = raw else {
return
}
var list: [KeyValue_t] = []
value!.forEach { (s: Sensor_t) in
value.forEach { (s: Sensor_t) in
if s.state {
list.append(KeyValue_t(key: s.key, value: s.formattedMiniValue))
}
}
self.popupView.usageCallback(value!)
if let widget = self.widget as? SensorsWidget {
widget.setValues(list)
self.popupView.usageCallback(value)
self.widgets.filter{ $0.isActive }.forEach { (w: Widget) in
switch w.item {
case let widget as SensorsWidget: widget.setValues(list)
default: break
}
}
}
}

View File

@@ -45,7 +45,7 @@ internal class Settings: NSView, Settings_v {
fatalError("init(coder:) has not been implemented")
}
public func load(widget: widget_t) {
public func load(widgets: [widget_t]) {
guard !self.list.pointee.isEmpty else {
return
}

View File

@@ -177,7 +177,7 @@ public class NetworkChartView: NSView {
context.saveGState()
var underLinePath = uploadlinePath.copy() as! NSBezierPath
underLinePath.line(to: CGPoint(x: columnXPoint(points.count - 1), y: zero))
underLinePath.line(to: CGPoint(x: columnXPoint(points.count), y: zero))
underLinePath.line(to: CGPoint(x: columnXPoint(0), y: zero))
underLinePath.close()
underLinePath.addClip()
@@ -188,7 +188,7 @@ public class NetworkChartView: NSView {
context.saveGState()
underLinePath = downloadlinePath.copy() as! NSBezierPath
underLinePath.line(to: CGPoint(x: columnXPoint(points.count - 1), y: zero))
underLinePath.line(to: CGPoint(x: columnXPoint(points.count), y: zero))
underLinePath.line(to: CGPoint(x: columnXPoint(0), y: zero))
underLinePath.close()
underLinePath.addClip()

View File

@@ -387,6 +387,8 @@ public extension NSView {
public extension Notification.Name {
static let toggleSettings = Notification.Name("toggleSettings")
static let toggleModule = Notification.Name("toggleModule")
static let togglePopup = Notification.Name("togglePopup")
static let toggleWidget = Notification.Name("toggleWidget")
static let openModuleSettings = Notification.Name("openModuleSettings")
static let settingsAppear = Notification.Name("settingsAppear")
static let switchWidget = Notification.Name("switchWidget")
@@ -398,12 +400,12 @@ public extension Notification.Name {
public class NSButtonWithPadding: NSButton {
public var horizontalPadding: CGFloat = 0
public var verticalPadding: CGFloat = 0
public override var intrinsicContentSize: NSSize {
var size = super.intrinsicContentSize
size.width += self.horizontalPadding
size.height += self.verticalPadding
return size;
return size
}
}
@@ -507,3 +509,52 @@ public extension CATransaction {
CATransaction.commit()
}
}
public final class FlippedClipView: NSClipView {
public override var isFlipped: Bool {
return true
}
}
public final class ScrollableStackView: NSView {
public let stackView: NSStackView = NSStackView()
public let clipView: FlippedClipView = FlippedClipView()
private let scrollView: NSScrollView = NSScrollView()
public override init(frame: NSRect) {
super.init(frame: frame)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.borderType = .noBorder
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = false
scrollView.autohidesScrollers = true
scrollView.horizontalScrollElasticity = .none
scrollView.drawsBackground = false
self.addSubview(self.scrollView)
NSLayoutConstraint.activate([
scrollView.leftAnchor.constraint(equalTo: self.leftAnchor),
scrollView.rightAnchor.constraint(equalTo: self.rightAnchor),
scrollView.topAnchor.constraint(equalTo: self.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
])
clipView.drawsBackground = false
scrollView.contentView = clipView
stackView.orientation = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.documentView = stackView
NSLayoutConstraint.activate([
stackView.leftAnchor.constraint(equalTo: clipView.leftAnchor),
stackView.rightAnchor.constraint(equalTo: clipView.rightAnchor),
stackView.topAnchor.constraint(equalTo: clipView.topAnchor),
])
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}