From 3bd9974ad9451abff452fa0d05283fba7e5d0d5c Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Sun, 19 Jan 2020 23:40:04 +0100 Subject: [PATCH] improved widget updates; now charts updates only if a popup is opened; removed shortName from widget; widgets refactoring; --- Stats/MenuBar.swift | 2 +- Stats/Modules/Battery/Battery.swift | 2 + Stats/Modules/CPU/CPU.swift | 2 + Stats/Modules/CPU/CPUPopup.swift | 18 +++-- Stats/Modules/Disk/Disk.swift | 2 + Stats/Modules/Module.swift | 22 +++--- Stats/Modules/Network/Network.swift | 2 + Stats/Modules/RAM/RAM.swift | 2 + Stats/Modules/RAM/RAMPopup.swift | 16 +++-- Stats/Views/PopupViewController.swift | 10 +++ Stats/Widgets/Battery/BatteryWidget.swift | 33 ++++----- Stats/Widgets/Charts/BarChart.swift | 37 +++++----- Stats/Widgets/Charts/LineChart.swift | 69 +++++++++---------- Stats/Widgets/Charts/LineChartWithValue.swift | 8 ++- Stats/Widgets/Mini.swift | 26 +++---- Stats/Widgets/Network/NetworkArrows.swift | 23 +++---- Stats/Widgets/Network/NetworkArrowsText.swift | 23 +++---- Stats/Widgets/Network/NetworkDots.swift | 23 +++---- Stats/Widgets/Network/NetworkDotsText.swift | 23 +++---- Stats/Widgets/Network/NetworkText.swift | 15 ++-- Stats/Widgets/Widget.swift | 11 ++- Stats/libs/Extensions.swift | 5 ++ 22 files changed, 189 insertions(+), 185 deletions(-) diff --git a/Stats/MenuBar.swift b/Stats/MenuBar.swift index 00d40307..d1cedf70 100644 --- a/Stats/MenuBar.swift +++ b/Stats/MenuBar.swift @@ -52,7 +52,7 @@ class MenuBar { } self.menuBarButton.addSubview(stackView) - + if self.stackView.subviews.count == 0 { self.menuBarButton.image = NSImage(named:NSImage.Name("tray_icon")) self.stackView.frame.size.width = widgetSize.width diff --git a/Stats/Modules/Battery/Battery.swift b/Stats/Modules/Battery/Battery.swift index 56dd6641..eb56c053 100644 --- a/Stats/Modules/Battery/Battery.swift +++ b/Stats/Modules/Battery/Battery.swift @@ -46,6 +46,8 @@ class Battery: Module { public var timeValue: NSTextField = NSTextField() init() { + if !self.available { return } + self.enabled = defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini diff --git a/Stats/Modules/CPU/CPU.swift b/Stats/Modules/CPU/CPU.swift index d2cb2336..efc7393f 100644 --- a/Stats/Modules/CPU/CPU.swift +++ b/Stats/Modules/CPU/CPU.swift @@ -33,6 +33,8 @@ class CPU: Module { public var chart: LineChartView = LineChartView() init() { + if !self.available { return } + self.enabled = defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini diff --git a/Stats/Modules/CPU/CPUPopup.swift b/Stats/Modules/CPU/CPUPopup.swift index d28603b7..e5265d9f 100644 --- a/Stats/Modules/CPU/CPUPopup.swift +++ b/Stats/Modules/CPU/CPUPopup.swift @@ -56,7 +56,8 @@ extension CPU { marker.chartView = self.chart self.chart.marker = marker - let lineChartEntry = [ChartDataEntry]() + var lineChartEntry = [ChartDataEntry]() + lineChartEntry.append(ChartDataEntry(x: 0, y: 0)) let chartDataSet = LineChartDataSet(entries: lineChartEntry, label: "\(self.name) Usage") chartDataSet.drawCirclesEnabled = false chartDataSet.mode = .cubicBezier @@ -70,23 +71,26 @@ extension CPU { data.setDrawValues(false) self.chart.data = LineChartData(dataSet: chartDataSet) - self.popup.view.view?.addSubview(self.chart) } public func chartUpdater(value: Double) { + if self.chart.data == nil { return } + let v: Double = Double((value * 100).roundTo(decimalPlaces: 2))! - + let index = Double((self.chart.data?.getDataSetByIndex(0)?.entryCount)!) self.chart.data?.addEntry(ChartDataEntry(x: index, y: v), dataSetIndex: 0) if index > 120 { self.chart.xAxis.axisMinimum = index - 120 } - self.chart.xAxis.axisMaximum = index - self.chart.notifyDataSetChanged() - self.chart.moveViewToX(index) + + if self.popup.active { + self.chart.notifyDataSetChanged() + self.chart.moveViewToX(index) + } } private func makeOverview() { @@ -202,6 +206,8 @@ extension CPU { } public func processesUpdater(value: [TopProcess]) { + if self.processViewList.isEmpty { return } + for (i, process) in value.enumerated() { if i < 5 { let processView = self.processViewList[i] diff --git a/Stats/Modules/Disk/Disk.swift b/Stats/Modules/Disk/Disk.swift index 33582bee..7100c5e7 100644 --- a/Stats/Modules/Disk/Disk.swift +++ b/Stats/Modules/Disk/Disk.swift @@ -26,6 +26,8 @@ class Disk: Module { public var submenu: NSMenu = NSMenu() init() { + if !self.available { return } + self.enabled = defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini diff --git a/Stats/Modules/Module.swift b/Stats/Modules/Module.swift index a507da7b..ce41c720 100644 --- a/Stats/Modules/Module.swift +++ b/Stats/Modules/Module.swift @@ -18,7 +18,7 @@ protocol Module: class { var widget: ModuleWidget { get set } // view for widget var menu: NSMenuItem { get } // view for menu - var popup: ModulePopup { get } // popup + var popup: ModulePopup { get set } // popup var readers: [Reader] { get } // list of readers available for module var task: Repeater? { get set } // reader cron task @@ -45,10 +45,17 @@ protocol Reader { struct ModulePopup { var available: Bool = true // say if module have popup view var view: NSTabViewItem = NSTabViewItem() // module popup view + var active: Bool = false // indicate that popup is opened and selected this view init(_ a: Bool = true) { available = a } + + mutating func setActive(_ state: Bool) { + if self.active != state { + self.active = state + } + } } struct ModuleWidget { @@ -94,13 +101,12 @@ extension Module { } widget.name = self.name - widget.shortName = String(self.name.prefix(3)).uppercased() - widget.Init() - - self.readers.forEach { reader in - reader.read() - } - + widget.start() + +// self.readers.forEach { reader in +// reader.read() +// } + self.widget.view = widget as! NSView } } diff --git a/Stats/Modules/Network/Network.swift b/Stats/Modules/Network/Network.swift index d23921c0..35b72b97 100644 --- a/Stats/Modules/Network/Network.swift +++ b/Stats/Modules/Network/Network.swift @@ -26,6 +26,8 @@ class Network: Module { public var submenu: NSMenu = NSMenu() init() { + if !self.available { return } + self.enabled = defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini diff --git a/Stats/Modules/RAM/RAM.swift b/Stats/Modules/RAM/RAM.swift index c9ecd593..f7c3ec08 100644 --- a/Stats/Modules/RAM/RAM.swift +++ b/Stats/Modules/RAM/RAM.swift @@ -33,6 +33,8 @@ class RAM: Module { public var chart: LineChartView = LineChartView() init() { + if !self.available { return } + self.enabled = defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true self.widget.type = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini diff --git a/Stats/Modules/RAM/RAMPopup.swift b/Stats/Modules/RAM/RAMPopup.swift index c9acbcc4..3399199d 100644 --- a/Stats/Modules/RAM/RAMPopup.swift +++ b/Stats/Modules/RAM/RAMPopup.swift @@ -57,7 +57,8 @@ extension RAM { marker.chartView = self.chart self.chart.marker = marker - let lineChartEntry = [ChartDataEntry]() + var lineChartEntry = [ChartDataEntry]() + lineChartEntry.append(ChartDataEntry(x: 0, y: 0)) let chartDataSet = LineChartDataSet(entries: lineChartEntry, label: "\(self.name) Usage") chartDataSet.drawCirclesEnabled = false chartDataSet.mode = .cubicBezier @@ -76,16 +77,21 @@ extension RAM { } public func chartUpdater(value: RAMUsage) { + if self.chart.data == nil { return } + let index = Double((self.chart.data?.getDataSetByIndex(0)?.entryCount)!) let usage = Units(bytes: Int64(value.used)).getReadableTuple().0 self.chart.data?.addEntry(ChartDataEntry(x: index, y: usage), dataSetIndex: 0) - + if index > 120 { self.chart.xAxis.axisMinimum = index - 120 } self.chart.xAxis.axisMaximum = index - self.chart.notifyDataSetChanged() - self.chart.moveViewToX(index) + + if self.popup.active { + self.chart.notifyDataSetChanged() + self.chart.moveViewToX(index) + } } private func makeOverview() { @@ -201,6 +207,8 @@ extension RAM { } public func processesUpdater(value: [TopProcess]) { + if self.processViewList.isEmpty { return } + for (i, process) in value.enumerated() { if i < 5 { let processView = self.processViewList[i] diff --git a/Stats/Views/PopupViewController.swift b/Stats/Views/PopupViewController.swift index b8006c92..fecb64e1 100644 --- a/Stats/Views/PopupViewController.swift +++ b/Stats/Views/PopupViewController.swift @@ -40,6 +40,9 @@ class MainViewController: NSViewController { } override func viewWillAppear() { + if self.segmentsControl == nil { return } + menuBar?.modules[self.segmentsControl.selectedSegment].popup.setActive(true) + DispatchQueue.global(qos: .background).async { for module in menuBar!.modules { if module.popup.available && module.available && module.enabled { @@ -52,6 +55,9 @@ class MainViewController: NSViewController { } override func viewWillDisappear() { + if self.segmentsControl == nil { return } + menuBar?.modules[self.segmentsControl.selectedSegment].popup.setActive(false) + DispatchQueue.global(qos: .background).async { for module in menuBar!.modules { if module.popup.available && module.available && module.enabled { @@ -119,6 +125,10 @@ class MainViewController: NSViewController { @objc func switchTabs(_ sender: NSSegmentedControl) { if let selectedLabel = self.segmentsControl.label(forSegment: sender.selectedSegment) { let tabNumber = self.tabView.indexOfTabViewItem(withIdentifier: selectedLabel) + + menuBar?.modules[self.segmentsControl.selectedSegment].popup.setActive(false) + menuBar?.modules[sender.selectedSegment].popup.setActive(true) + self.tabView.selectTabViewItem(at: tabNumber) } } diff --git a/Stats/Widgets/Battery/BatteryWidget.swift b/Stats/Widgets/Battery/BatteryWidget.swift index e9c1a538..71ce435d 100644 --- a/Stats/Widgets/Battery/BatteryWidget.swift +++ b/Stats/Widgets/Battery/BatteryWidget.swift @@ -10,7 +10,6 @@ import Cocoa class BatteryWidget: NSView, Widget { public var name: String = "Battery" - public var shortName: String = "BAT" public var menus: [NSMenuItem] = [] public var size: CGFloat = 30 public var batterySize: CGFloat = 30 @@ -18,24 +17,9 @@ class BatteryWidget: NSView, Widget { private let defaults = UserDefaults.standard private var color: Bool = false - public var value: Double { - didSet { - self.redraw() - self.update() - } - } - public var time: Double { - didSet { - self.redraw() - self.update() - } - } - public var charging: Bool { - didSet { - self.redraw() - self.update() - } - } + public var value: Double = 0 + public var time: Double = 0 + public var charging: Bool = false override var intrinsicContentSize: CGSize { return CGSize(width: self.frame.size.width, height: self.frame.size.height) @@ -53,7 +37,7 @@ class BatteryWidget: NSView, Widget { fatalError("init(coder:) has not been implemented") } - func Init() { + func start() { self.color = defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false self.initMenu() self.redraw() @@ -115,17 +99,26 @@ class BatteryWidget: NSView, Widget { func setValue(data: [Double]) { let value: Double = data.first! let time: Double = data.last! + var changed: Bool = false + if self.value != value { self.value = value + changed = true } if self.time != time { self.time = time + changed = true + } + + if changed { + self.redraw() } } func setCharging(value: Bool) { if self.charging != value { self.charging = value + self.redraw() } } diff --git a/Stats/Widgets/Charts/BarChart.swift b/Stats/Widgets/Charts/BarChart.swift index 86ce5e51..55099f31 100644 --- a/Stats/Widgets/Charts/BarChart.swift +++ b/Stats/Widgets/Charts/BarChart.swift @@ -9,21 +9,15 @@ import Cocoa class BarChart: NSView, Widget { - var size: CGFloat = widgetSize.width + 10 - let defaults = UserDefaults.standard + public var name: String = "" + public var menus: [NSMenuItem] = [] - var labelPadding: CGFloat = 12.0 - var label: Bool = false - var name: String = "" - var shortName: String = "" + private var size: CGFloat = widgetSize.width + 10 + private var labelPadding: CGFloat = 12.0 + private var label: Bool = false + private let defaults = UserDefaults.standard - var menus: [NSMenuItem] = [] - - var partitions: [Double] { - didSet { - self.redraw() - } - } + private var partitions: [Double] = [] override var intrinsicContentSize: CGSize { return CGSize(width: self.frame.size.width, height: self.frame.size.height) @@ -41,7 +35,7 @@ class BarChart: NSView, Widget { fatalError("init(coder:) has not been implemented") } - func Init() { + func start() { self.label = defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true self.initPreferences() } @@ -109,7 +103,7 @@ class BarChart: NSView, Widget { let letterWidth: CGFloat = 10.0 var yMargin = widgetSize.margin - for char in self.shortName.reversed() { + for char in String(self.name.prefix(3)).uppercased().reversed() { let rect = CGRect(x: widgetSize.margin, y: yMargin, width: letterWidth, height: letterHeight) let str = NSAttributedString.init(string: "\(char)", attributes: stringAttributes) str.draw(with: rect) @@ -119,7 +113,13 @@ class BarChart: NSView, Widget { } func setValue(data: [Double]) { - self.partitions = data + let values = data.map { v -> Double in + return v.rounded(toPlaces: 2) + } + if self.partitions != values { + self.partitions = values + self.redraw() + } } func redraw() { @@ -133,13 +133,12 @@ class BarChart: NSView, Widget { if self.label { width += labelPadding } - + if self.frame.size.width != width { self.setFrameSize(NSSize(width: width, height: self.frame.size.height)) menuBar!.refresh() } - self.needsDisplay = true - setNeedsDisplay(self.frame) + self.display() } } diff --git a/Stats/Widgets/Charts/LineChart.swift b/Stats/Widgets/Charts/LineChart.swift index acbef40b..a02046c3 100644 --- a/Stats/Widgets/Charts/LineChart.swift +++ b/Stats/Widgets/Charts/LineChart.swift @@ -9,20 +9,16 @@ import Cocoa class Chart: NSView, Widget { - var size: CGFloat = widgetSize.width + 7 - var labelPadding: CGFloat = 10.0 - var label: Bool = false - var name: String = "" - var shortName: String = "" - var menus: [NSMenuItem] = [] - let defaults = UserDefaults.standard + public var name: String = "" + public var menus: [NSMenuItem] = [] - var height: CGFloat = 0.0 - var points: [Double] { - didSet { - self.redraw() - } - } + internal let defaults = UserDefaults.standard + internal var size: CGFloat = widgetSize.width + 7 + internal var labelPadding: CGFloat = 10.0 + internal var label: Bool = false + + internal var height: CGFloat = 0.0 + internal var points: [Double] = [] override var intrinsicContentSize: CGSize { return CGSize(width: self.frame.size.width, height: self.frame.size.height) @@ -39,7 +35,7 @@ class Chart: NSView, Widget { fatalError("init(coder:) has not been implemented") } - func Init() { + func start() { self.label = defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true self.initMenu() @@ -73,10 +69,10 @@ class Chart: NSView, Widget { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - + let lineColor: NSColor = NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 1.0) let gradientColor: NSColor = NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.5) - + let context = NSGraphicsContext.current!.cgContext var xOffset: CGFloat = 4.0 if label { @@ -86,52 +82,52 @@ class Chart: NSView, Widget { if height == 0 { height = self.frame.size.height - CGFloat((yOffset * 2)) } - + var xRatio = Double(self.frame.size.width - (xOffset * 2)) / (Double(self.points.count) - 1) if label { xRatio = Double(self.frame.size.width - (xOffset * 2) + labelPadding) / (Double(self.points.count) - 1) } - + let columnXPoint = { (point: Int) -> CGFloat in return CGFloat((Double(point) * xRatio)) + xOffset } let columnYPoint = { (point: Int) -> CGFloat in return CGFloat((CGFloat(truncating: self.points[point] as NSNumber) * self.height)) + yOffset } - + let graphPath = NSBezierPath() let x: CGFloat = columnXPoint(0) let y: CGFloat = columnYPoint(0) graphPath.move(to: CGPoint(x: x, y: y)) - + for i in 1.. Double { + let divisor = pow(10.0, Double(places)) + return (self * divisor).rounded() / divisor + } + func usageColor(reversed: Bool = false, color: Bool = false) -> NSColor { if !color { return NSColor.textColor