diff --git a/CHANGELOG.md b/CHANGELOG.md index e3ccc072..03af945e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Changelog All notable changes to this project will be documented in this file. +### [v1.2.8] + - small changes in Widgets structure + - widgets settings moved from modules to widgets + - fixed Bar chart visibility on start + - small changes in Widget protocol + - appStore mode added + - fixed few bugs + ### [v1.2.7] - added hyperthreading mode in Bar Chart for CPU - fixed few bugs @@ -55,6 +63,7 @@ All notable changes to this project will be documented in this file. ### [v1.0.0] - first release +[v1.2.8]: https://github.com/exelban/stats/releases/tag/v1.2.8 [v1.2.7]: https://github.com/exelban/stats/releases/tag/v1.2.7 [v1.2.6]: https://github.com/exelban/stats/releases/tag/v1.2.6 [v1.2.5]: https://github.com/exelban/stats/releases/tag/v1.2.5 diff --git a/Stats.xcodeproj/project.pbxproj b/Stats.xcodeproj/project.pbxproj index c75ad661..d8a139a4 100755 --- a/Stats.xcodeproj/project.pbxproj +++ b/Stats.xcodeproj/project.pbxproj @@ -18,11 +18,9 @@ 9A57A19D22A1E3270033E318 /* CPU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A57A19C22A1E3270033E318 /* CPU.swift */; }; 9A58D1B022C150C800405315 /* Network.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1AF22C150C800405315 /* Network.swift */; }; 9A58D1B222C150D700405315 /* NetworkReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1B122C150D700405315 /* NetworkReader.swift */; }; - 9A58D1B422C179B200405315 /* NetworkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58D1B322C179B200405315 /* NetworkView.swift */; }; 9A5B1CBF229E78F0008B9D3C /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5B1CBE229E78F0008B9D3C /* Observable.swift */; }; 9A5B1CC5229E7B40008B9D3C /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5B1CC4229E7B40008B9D3C /* Extensions.swift */; }; 9A6CFC0122A1C9F5001E782D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */; }; - 9A74D59422B4315C004FE1FA /* Chart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D59322B4315C004FE1FA /* Chart.swift */; }; 9A74D59722B44498004FE1FA /* Mini.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D59622B44498004FE1FA /* Mini.swift */; }; 9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36922D3BEE600BF1C3A /* Widget.swift */; }; 9A79B36C22D3BEF000BF1C3A /* Module.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A79B36B22D3BEF000BF1C3A /* Module.swift */; }; @@ -32,7 +30,14 @@ 9A7B8F6B22A2C3A700DEB352 /* Disk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7B8F6A22A2C3A700DEB352 /* Disk.swift */; }; 9A7B8F6D22A2C3D600DEB352 /* MemoryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7B8F6C22A2C3D600DEB352 /* MemoryReader.swift */; }; 9A7B8F6F22A2C57000DEB352 /* DiskReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A7B8F6E22A2C57000DEB352 /* DiskReader.swift */; }; - 9A9696EC22D526D900F967A5 /* BarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9696EB22D526D900F967A5 /* BarChart.swift */; }; + 9AF0F31B22DA924000026AE6 /* LineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F31A22DA924000026AE6 /* LineChart.swift */; }; + 9AF0F31D22DA925000026AE6 /* LineChartWithValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F31C22DA925000026AE6 /* LineChartWithValue.swift */; }; + 9AF0F31F22DA925700026AE6 /* BarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F31E22DA925700026AE6 /* BarChart.swift */; }; + 9AF0F32122DA92AD00026AE6 /* NetworkDots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F32022DA92AD00026AE6 /* NetworkDots.swift */; }; + 9AF0F32322DA92B900026AE6 /* NetworkArrows.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F32222DA92B900026AE6 /* NetworkArrows.swift */; }; + 9AF0F32522DA92C400026AE6 /* NetworkText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F32422DA92C400026AE6 /* NetworkText.swift */; }; + 9AF0F32722DA92DD00026AE6 /* NetworkDotsText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F32622DA92DD00026AE6 /* NetworkDotsText.swift */; }; + 9AF0F32922DA92E800026AE6 /* NetworkArrowsText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AF0F32822DA92E800026AE6 /* NetworkArrowsText.swift */; }; 9AFA402522AE49A200FE90BC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9AFA402422AE49A200FE90BC /* Assets.xcassets */; }; 9AFA402822AE49A200FE90BC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AFA402622AE49A200FE90BC /* Main.storyboard */; }; 9AFA402F22AE49AE00FE90BC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AFA402E22AE49AE00FE90BC /* AppDelegate.swift */; }; @@ -69,11 +74,9 @@ 9A57A19C22A1E3270033E318 /* CPU.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CPU.swift; sourceTree = ""; }; 9A58D1AF22C150C800405315 /* Network.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Network.swift; sourceTree = ""; }; 9A58D1B122C150D700405315 /* NetworkReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkReader.swift; sourceTree = ""; }; - 9A58D1B322C179B200405315 /* NetworkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkView.swift; sourceTree = ""; }; 9A5B1CBE229E78F0008B9D3C /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; 9A5B1CC4229E7B40008B9D3C /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 9A6CFC0022A1C9F5001E782D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 9A74D59322B4315C004FE1FA /* Chart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Chart.swift; sourceTree = ""; }; 9A74D59622B44498004FE1FA /* Mini.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mini.swift; sourceTree = ""; }; 9A79B36922D3BEE600BF1C3A /* Widget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widget.swift; sourceTree = ""; }; 9A79B36B22D3BEF000BF1C3A /* Module.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Module.swift; sourceTree = ""; }; @@ -83,9 +86,16 @@ 9A7B8F6A22A2C3A700DEB352 /* Disk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Disk.swift; sourceTree = ""; }; 9A7B8F6C22A2C3D600DEB352 /* MemoryReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoryReader.swift; sourceTree = ""; }; 9A7B8F6E22A2C57000DEB352 /* DiskReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskReader.swift; sourceTree = ""; }; - 9A9696EB22D526D900F967A5 /* BarChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarChart.swift; sourceTree = ""; }; 9A998CD722A199920087ADE7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 9A998CD922A199970087ADE7 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; + 9AF0F31A22DA924000026AE6 /* LineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChart.swift; sourceTree = ""; }; + 9AF0F31C22DA925000026AE6 /* LineChartWithValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartWithValue.swift; sourceTree = ""; }; + 9AF0F31E22DA925700026AE6 /* BarChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarChart.swift; sourceTree = ""; }; + 9AF0F32022DA92AD00026AE6 /* NetworkDots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkDots.swift; sourceTree = ""; }; + 9AF0F32222DA92B900026AE6 /* NetworkArrows.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkArrows.swift; sourceTree = ""; }; + 9AF0F32422DA92C400026AE6 /* NetworkText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkText.swift; sourceTree = ""; }; + 9AF0F32622DA92DD00026AE6 /* NetworkDotsText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkDotsText.swift; sourceTree = ""; }; + 9AF0F32822DA92E800026AE6 /* NetworkArrowsText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkArrowsText.swift; sourceTree = ""; }; 9AFA401E22AE49A100FE90BC /* StatsLauncher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StatsLauncher.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9AFA402422AE49A200FE90BC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9AFA402722AE49A200FE90BC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -203,12 +213,11 @@ 9A74D59522B440D4004FE1FA /* Widgets */ = { isa = PBXGroup; children = ( + 9AF0F31922DA923100026AE6 /* Network */, + 9AF0F31822DA922800026AE6 /* Charts */, 9A09C8A122B3D94D0018426F /* BatteryView.swift */, - 9A74D59322B4315C004FE1FA /* Chart.swift */, 9A74D59622B44498004FE1FA /* Mini.swift */, - 9A58D1B322C179B200405315 /* NetworkView.swift */, 9A79B36922D3BEE600BF1C3A /* Widget.swift */, - 9A9696EB22D526D900F967A5 /* BarChart.swift */, ); path = Widgets; sourceTree = ""; @@ -249,6 +258,28 @@ name = Frameworks; sourceTree = ""; }; + 9AF0F31822DA922800026AE6 /* Charts */ = { + isa = PBXGroup; + children = ( + 9AF0F31A22DA924000026AE6 /* LineChart.swift */, + 9AF0F31C22DA925000026AE6 /* LineChartWithValue.swift */, + 9AF0F31E22DA925700026AE6 /* BarChart.swift */, + ); + path = Charts; + sourceTree = ""; + }; + 9AF0F31922DA923100026AE6 /* Network */ = { + isa = PBXGroup; + children = ( + 9AF0F32022DA92AD00026AE6 /* NetworkDots.swift */, + 9AF0F32222DA92B900026AE6 /* NetworkArrows.swift */, + 9AF0F32422DA92C400026AE6 /* NetworkText.swift */, + 9AF0F32622DA92DD00026AE6 /* NetworkDotsText.swift */, + 9AF0F32822DA92E800026AE6 /* NetworkArrowsText.swift */, + ); + path = Network; + sourceTree = ""; + }; 9AFA401F22AE49A100FE90BC /* StatsLauncher */ = { isa = PBXGroup; children = ( @@ -374,9 +405,10 @@ 9A79B36E22D3BEF900BF1C3A /* Reader.swift in Sources */, 9A7B8F6F22A2C57000DEB352 /* DiskReader.swift in Sources */, 9A7B8F6922A2C3A100DEB352 /* Memory.swift in Sources */, + 9AF0F32522DA92C400026AE6 /* NetworkText.swift in Sources */, 9A7B8F5E22A2A57600DEB352 /* CPUReader.swift in Sources */, - 9A74D59422B4315C004FE1FA /* Chart.swift in Sources */, - 9A58D1B422C179B200405315 /* NetworkView.swift in Sources */, + 9AF0F32322DA92B900026AE6 /* NetworkArrows.swift in Sources */, + 9AF0F31D22DA925000026AE6 /* LineChartWithValue.swift in Sources */, 9A09C89E22B3A7C90018426F /* Battery.swift in Sources */, 9A7B8F6D22A2C3D600DEB352 /* MemoryReader.swift in Sources */, 9A79B36C22D3BEF000BF1C3A /* Module.swift in Sources */, @@ -388,10 +420,14 @@ 9A5B1CBF229E78F0008B9D3C /* Observable.swift in Sources */, 9A7B8F6B22A2C3A700DEB352 /* Disk.swift in Sources */, 9A1410F9229E721100D29793 /* AppDelegate.swift in Sources */, - 9A9696EC22D526D900F967A5 /* BarChart.swift in Sources */, + 9AF0F32722DA92DD00026AE6 /* NetworkDotsText.swift in Sources */, + 9AF0F32922DA92E800026AE6 /* NetworkArrowsText.swift in Sources */, + 9AF0F31F22DA925700026AE6 /* BarChart.swift in Sources */, + 9AF0F31B22DA924000026AE6 /* LineChart.swift in Sources */, 9A74D59722B44498004FE1FA /* Mini.swift in Sources */, 9A5B1CC5229E7B40008B9D3C /* Extensions.swift in Sources */, 9A79B36A22D3BEE600BF1C3A /* Widget.swift in Sources */, + 9AF0F32122DA92AD00026AE6 /* NetworkDots.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Stats/AppDelegate.swift b/Stats/AppDelegate.swift index de397f70..9baff488 100755 --- a/Stats/AppDelegate.swift +++ b/Stats/AppDelegate.swift @@ -16,6 +16,8 @@ extension Notification.Name { let modules: Observable<[Module]> = Observable([CPU(), Memory(), Disk(), Battery(), Network()]) let updater = macAppUpdater(user: "exelban", repo: "stats") +let appStoreMode: Bool = false + @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { let defaults = UserDefaults.standard @@ -45,7 +47,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { NSApp.setActivationPolicy(dockIconStatus) } - if defaults.object(forKey: "checkUpdatesOnLogin") == nil || defaults.bool(forKey: "checkUpdatesOnLogin") { + if !appStoreMode && defaults.object(forKey: "checkUpdatesOnLogin") == nil || defaults.bool(forKey: "checkUpdatesOnLogin") { updater.check() { result, error in if error != nil && error as! String == "No internet connection" { return diff --git a/Stats/MenuBar.swift b/Stats/MenuBar.swift index cc29d27f..99ada7af 100644 --- a/Stats/MenuBar.swift +++ b/Stats/MenuBar.swift @@ -9,10 +9,6 @@ import Cocoa import ServiceManagement -let MODULE_HEIGHT: CGFloat = NSApplication.shared.mainMenu?.menuBarHeight ?? 22 -let MODULE_WIDTH: CGFloat = 32 -let MODULE_MARGIN: CGFloat = 2 - class MenuBar { let defaults = UserDefaults.standard let menuBarItem: NSStatusItem @@ -86,7 +82,9 @@ class MenuBar { let aboutMenu = NSMenuItem(title: "About Stats", action: #selector(openAbout), keyEquivalent: "") aboutMenu.target = self - menu.addItem(updateMenu) + if !appStoreMode { + menu.addItem(updateMenu) + } menu.addItem(aboutMenu) menu.addItem(NSMenuItem(title: "Quit Stats", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "")) @@ -133,8 +131,8 @@ class MenuBar { } self.menuBarButton.image = NSImage(named:NSImage.Name("tray_icon")) - self.menuBarItem.length = MODULE_WIDTH - var WIDTH = CGFloat(modules.value.count) * MODULE_WIDTH + self.menuBarItem.length = widgetSize.width + var WIDTH = CGFloat(modules.value.count) * widgetSize.width WIDTH = 0 for module in modules.value { @@ -144,7 +142,7 @@ class MenuBar { } } - let view: NSView = NSView(frame: NSMakeRect(0, 0, WIDTH, MODULE_HEIGHT)) + let view: NSView = NSView(frame: NSMakeRect(0, 0, WIDTH, widgetSize.height)) var x: CGFloat = 0 for module in modules.value { diff --git a/Stats/Modules/Battery/Battery.swift b/Stats/Modules/Battery/Battery.swift index d40bf7f0..73dcdfd0 100644 --- a/Stats/Modules/Battery/Battery.swift +++ b/Stats/Modules/Battery/Battery.swift @@ -16,8 +16,6 @@ class Battery: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable - var color: Observable - var label: Observable var reader: Reader = BatteryReader() let defaults = UserDefaults.standard @@ -28,9 +26,7 @@ class Battery: Module { self.available = Observable(self.reader.available) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.percentageView = Observable(defaults.object(forKey: "\(self.name)_percentage") != nil ? defaults.bool(forKey: "\(self.name)_percentage") : false) - self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) - self.label = Observable(defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : false) - self.view = BatteryView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + self.view = BatteryView(frame: NSMakeRect(0, 0, widgetSize.width, widgetSize.height)) initMenu() initWidget() } @@ -73,12 +69,12 @@ class Battery: Module { percentage.state = defaults.bool(forKey: "\(self.name)_percentage") ? NSControl.StateValue.on : NSControl.StateValue.off percentage.target = self - let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") - color.state = defaults.bool(forKey: "\(name)_color") ? NSControl.StateValue.on : NSControl.StateValue.off - color.target = self - + if let view = self.view as? Widget { + for widgetMenu in view.menus { + submenu.addItem(widgetMenu) + } + } submenu.addItem(percentage) - submenu.addItem(color) menu.submenu = submenu } @@ -107,11 +103,5 @@ class Battery: Module { self.percentageView << state self.initWidget() } - - @objc func toggleColor(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") - self.color << (sender.state == NSControl.StateValue.on) - } } diff --git a/Stats/Modules/CPU/CPU.swift b/Stats/Modules/CPU/CPU.swift index 519e3a1b..1668b308 100644 --- a/Stats/Modules/CPU/CPU.swift +++ b/Stats/Modules/CPU/CPU.swift @@ -16,8 +16,6 @@ class CPU: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable - var color: Observable - var label: Observable var hyperthreading: Observable var reader: Reader = CPUReader() @@ -29,15 +27,15 @@ class CPU: Module { self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.hyperthreading = Observable(defaults.object(forKey: "\(name)_hyperthreading") != nil ? defaults.bool(forKey: "\(name)_hyperthreading") : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini - self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) - self.label = Observable(defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true) - initMenu() - initWidget() if self.widgetType == Widgets.BarChart { (self.reader as! CPUReader).perCoreMode = true (self.reader as! CPUReader).hyperthreading = self.hyperthreading.value + self.reader.read() } + + initWidget() + initMenu() } func initMenu() { @@ -71,14 +69,6 @@ class CPU: Module { hyperthreading.state = self.hyperthreading.value ? NSControl.StateValue.on : NSControl.StateValue.off hyperthreading.target = self - let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") - color.state = self.color.value ? NSControl.StateValue.on : NSControl.StateValue.off - color.target = self - - let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") - label.state = self.label.value ? NSControl.StateValue.on : NSControl.StateValue.off - label.target = self - submenu.addItem(mini) submenu.addItem(chart) submenu.addItem(chartWithValue) @@ -86,15 +76,15 @@ class CPU: Module { submenu.addItem(NSMenuItem.separator()) + if let view = self.view as? Widget { + for widgetMenu in view.menus { + submenu.addItem(widgetMenu) + } + } + if self.widgetType == Widgets.BarChart { submenu.addItem(hyperthreading) } - if self.widgetType == Widgets.BarChart || self.widgetType == Widgets.ChartWithValue || self.widgetType == Widgets.Chart { - submenu.addItem(label) - } - if self.widgetType == Widgets.Mini || self.widgetType == Widgets.ChartWithValue { - submenu.addItem(color) - } menu.submenu = submenu } @@ -161,18 +151,4 @@ class CPU: Module { self.hyperthreading << (sender.state == NSControl.StateValue.on) (self.reader as! CPUReader).hyperthreading = sender.state == NSControl.StateValue.on } - - @objc func toggleColor(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") - self.color << (sender.state == NSControl.StateValue.on) - } - - @objc func toggleLabel(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_label") - self.active << false - self.label << (sender.state == NSControl.StateValue.on) - self.active << true - } } diff --git a/Stats/Modules/CPU/CPUReader.swift b/Stats/Modules/CPU/CPUReader.swift index bb90eaa5..ad4e578c 100644 --- a/Stats/Modules/CPU/CPUReader.swift +++ b/Stats/Modules/CPU/CPUReader.swift @@ -86,7 +86,9 @@ class CPUReader: Reader { inUseOnAllCores = inUseOnAllCores + inUse totalOnAllCores = totalOnAllCores + total - usagePerCore.append(Double(inUse) / Double(total)) + if total != 0 { + usagePerCore.append(Double(inUse) / Double(total)) + } } if self.perCoreMode { diff --git a/Stats/Modules/Disk/Disk.swift b/Stats/Modules/Disk/Disk.swift index 4f9156c0..c32a20df 100644 --- a/Stats/Modules/Disk/Disk.swift +++ b/Stats/Modules/Disk/Disk.swift @@ -19,8 +19,6 @@ class Disk: Module { var active: Observable var available: Observable - var color: Observable - var label: Observable var reader: Reader = DiskReader() @@ -30,11 +28,9 @@ class Disk: Module { self.available = Observable(true) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini - self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) - self.label = Observable(defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true) - self.initMenu() self.initWidget() + self.initMenu() } func initMenu() { @@ -56,24 +52,15 @@ class Disk: Module { barChart.state = self.widgetType == Widgets.BarChart ? NSControl.StateValue.on : NSControl.StateValue.off barChart.target = self - let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") - color.state = self.color.value ? NSControl.StateValue.on : NSControl.StateValue.off - color.target = self - - let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") - label.state = self.label.value ? NSControl.StateValue.on : NSControl.StateValue.off - label.target = self - submenu.addItem(mini) submenu.addItem(barChart) submenu.addItem(NSMenuItem.separator()) - if self.widgetType == Widgets.BarChart { - submenu.addItem(label) - } - if self.widgetType == Widgets.Mini { - submenu.addItem(color) + if let view = self.view as? Widget { + for widgetMenu in view.menus { + submenu.addItem(widgetMenu) + } } menu.submenu = submenu @@ -119,22 +106,8 @@ class Disk: Module { self.defaults.set(widgetCode, forKey: "\(name)_widget") self.widgetType = widgetCode self.active << false - self.initMenu() self.initWidget() - self.active << true - } - - @objc func toggleColor(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") - self.color << (sender.state == NSControl.StateValue.on) - } - - @objc func toggleLabel(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_label") - self.active << false - self.label << (sender.state == NSControl.StateValue.on) + self.initMenu() self.active << true } } diff --git a/Stats/Modules/Memory/Memory.swift b/Stats/Modules/Memory/Memory.swift index 20ed211a..c3f11e87 100644 --- a/Stats/Modules/Memory/Memory.swift +++ b/Stats/Modules/Memory/Memory.swift @@ -16,8 +16,6 @@ class Memory: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable - var color: Observable - var label: Observable var reader: Reader = MemoryReader() var widgetType: WidgetType @@ -29,10 +27,8 @@ class Memory: Module { self.available = Observable(true) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.Mini - self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) - self.label = Observable(defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true) - initMenu() initWidget() + initMenu() } func initMenu() { @@ -62,14 +58,6 @@ class Memory: Module { barChart.state = self.widgetType == Widgets.BarChart ? NSControl.StateValue.on : NSControl.StateValue.off barChart.target = self - let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") - color.state = self.color.value ? NSControl.StateValue.on : NSControl.StateValue.off - color.target = self - - let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") - label.state = self.label.value ? NSControl.StateValue.on : NSControl.StateValue.off - label.target = self - submenu.addItem(mini) submenu.addItem(chart) submenu.addItem(chartWithValue) @@ -77,11 +65,10 @@ class Memory: Module { submenu.addItem(NSMenuItem.separator()) - if self.widgetType == Widgets.BarChart || self.widgetType == Widgets.ChartWithValue || self.widgetType == Widgets.Chart { - submenu.addItem(label) - } - if self.widgetType == Widgets.Mini || self.widgetType == Widgets.ChartWithValue { - submenu.addItem(color) + if let view = self.view as? Widget { + for widgetMenu in view.menus { + submenu.addItem(widgetMenu) + } } menu.submenu = submenu @@ -137,18 +124,4 @@ class Memory: Module { self.initMenu() self.active << true } - - @objc func toggleColor(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") - self.color << (sender.state == NSControl.StateValue.on) - } - - @objc func toggleLabel(_ sender: NSMenuItem) { - sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on - self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_label") - self.active << false - self.label << (sender.state == NSControl.StateValue.on) - self.active << true - } } diff --git a/Stats/Modules/Module.swift b/Stats/Modules/Module.swift index 2fd9cdb1..b13e9ce9 100644 --- a/Stats/Modules/Module.swift +++ b/Stats/Modules/Module.swift @@ -18,8 +18,6 @@ protocol Module: class { var active: Observable { get } var available: Observable { get } - var color: Observable { get } - var label: Observable { get } var reader: Reader { get } @@ -29,35 +27,36 @@ protocol Module: class { extension Module { func initWidget(label: Bool = false) { - var widget: Widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + var widget: Widget = Mini() switch self.widgetType { case Widgets.Mini: - widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = Mini() case Widgets.Chart: - widget = Chart(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + widget = Chart() case Widgets.ChartWithValue: - widget = ChartWithValue(frame: NSMakeRect(0, 0, MODULE_WIDTH + 7, MODULE_HEIGHT)) + widget = ChartWithValue() case Widgets.NetworkDots: - widget = NetworkDotsView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = NetworkDotsView() case Widgets.NetworkArrows: - widget = NetworkArrowsView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = NetworkArrowsView() case Widgets.NetworkText: - widget = NetworkTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = NetworkTextView() case Widgets.NetworkDotsWithText: - widget = NetworkDotsTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = NetworkDotsTextView() case Widgets.NetworkArrowsWithText: - widget = NetworkArrowsTextView(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = NetworkArrowsTextView() case Widgets.BarChart: - widget = BarChart(frame: NSMakeRect(0, 0, MODULE_WIDTH + 10, MODULE_HEIGHT)) + widget = BarChart() default: - widget = Mini(frame: NSMakeRect(0, 0, MODULE_WIDTH, MODULE_HEIGHT)) + widget = Mini() } - widget.label = self.shortName - widget.toggleColor(state: self.color.value) - widget.toggleLabel(state: self.label.value) - widget.active = self.active + widget.name = self.name + widget.shortName = self.shortName + widget.activeModule = self.active + widget.Init() + self.view = widget as! NSView } @@ -78,27 +77,10 @@ extension Module { widget.setValue(data: value) } } - - self.color.subscribe(observer: self) { (value, _) in - guard let widget = self.view as? Widget else { - return - } - widget.toggleColor(state: value) - widget.redraw() - } - - self.label.subscribe(observer: self) { (value, _) in - guard let widget = self.view as? Widget else { - return - } - widget.toggleLabel(state: value) - } } func stop() { self.reader.stop() self.reader.value.unsubscribe(observer: self) - self.color.unsubscribe(observer: self) - self.label.unsubscribe(observer: self) } } diff --git a/Stats/Modules/Network/Network.swift b/Stats/Modules/Network/Network.swift index 959de96f..d8503e13 100644 --- a/Stats/Modules/Network/Network.swift +++ b/Stats/Modules/Network/Network.swift @@ -16,8 +16,6 @@ class Network: Module { var submenu: NSMenu = NSMenu() var active: Observable var available: Observable - var color: Observable - var label: Observable var reader: Reader = NetworkReader() var widgetType: WidgetType = 2.0 @@ -27,8 +25,6 @@ class Network: Module { self.available = Observable(self.reader.available) self.active = Observable(defaults.object(forKey: name) != nil ? defaults.bool(forKey: name) : true) self.widgetType = defaults.object(forKey: "\(name)_widget") != nil ? defaults.float(forKey: "\(name)_widget") : Widgets.NetworkDots - self.color = Observable(defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false) - self.label = Observable(defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : false) initMenu() initWidget() } @@ -84,6 +80,14 @@ class Network: Module { submenu.addItem(dotsWithText) submenu.addItem(arrowsWithText) + submenu.addItem(NSMenuItem.separator()) + + if let view = self.view as? Widget { + for widgetMenu in view.menus { + submenu.addItem(widgetMenu) + } + } + menu.submenu = submenu } diff --git a/Stats/Supporting Files/Info.plist b/Stats/Supporting Files/Info.plist index 95c2fb83..138fcdae 100755 --- a/Stats/Supporting Files/Info.plist +++ b/Stats/Supporting Files/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.7 + 1.2.8 CFBundleVersion 1 LSApplicationCategoryType diff --git a/Stats/Widgets/BatteryView.swift b/Stats/Widgets/BatteryView.swift index 96f98ac7..124d9e66 100644 --- a/Stats/Widgets/BatteryView.swift +++ b/Stats/Widgets/BatteryView.swift @@ -9,9 +9,12 @@ import Cocoa class BatteryView: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = MODULE_WIDTH - var label: String = "" + var activeModule: Observable = Observable(false) + var size: CGFloat = widgetSize.width + var name: String = "" + var shortName: String = "" + var menus: [NSMenuItem] = [] + let defaults = UserDefaults.standard let batteryWidth: CGFloat = 32 let percentageWidth: CGFloat = 40 @@ -39,7 +42,7 @@ class BatteryView: NSView, Widget { self.value = 1.0 self.charging = false self.percentage = false - super.init(frame: frame) + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) self.wantsLayer = true self.percentageView() } @@ -48,6 +51,20 @@ class BatteryView: NSView, Widget { fatalError("init(coder:) has not been implemented") } + func Init() { + self.color = defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false + self.initMenu() + self.redraw() + } + + func initMenu() { + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = self.color ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + + self.menus.append(color) + } + override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) @@ -133,14 +150,6 @@ class BatteryView: NSView, Widget { } } - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - } - } - - func toggleLabel(state: Bool) {} - func setCharging(value: Bool) { if self.charging != value { self.charging = value @@ -153,4 +162,10 @@ class BatteryView: NSView, Widget { self.percentageView() } } + + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color = sender.state == NSControl.StateValue.on + } } diff --git a/Stats/Widgets/BarChart.swift b/Stats/Widgets/Charts/BarChart.swift similarity index 59% rename from Stats/Widgets/BarChart.swift rename to Stats/Widgets/Charts/BarChart.swift index fb579af3..8d025294 100644 --- a/Stats/Widgets/BarChart.swift +++ b/Stats/Widgets/Charts/BarChart.swift @@ -9,13 +9,16 @@ import Cocoa class BarChart: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = MODULE_WIDTH + 10 + var activeModule: Observable = Observable(false) + var size: CGFloat = widgetSize.width + 10 + let defaults = UserDefaults.standard var labelPadding: CGFloat = 12.0 - var labelEnabled: Bool = false - var label: String = "" - var color: Bool = false + var label: Bool = false + var name: String = "" + var shortName: String = "" + + var menus: [NSMenuItem] = [] var partitions: [Double] { didSet { @@ -24,29 +27,49 @@ class BarChart: NSView, Widget { } override init(frame: NSRect) { + self.label = defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true self.partitions = Array(repeating: 0.0, count: 1) - super.init(frame: frame) + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) self.wantsLayer = true self.addSubview(NSView()) - - if self.labelEnabled { - self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) - } } required init?(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } + func Init() { + self.label = defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true + self.initPreferences() + + if self.label { + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) + } + } + + func initPreferences() { + let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") + label.state = self.label ? NSControl.StateValue.on : NSControl.StateValue.off + label.target = self + + self.menus.append(label) + } + + @objc func toggleLabel(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(self.name)_label") + self.label = (sender.state == NSControl.StateValue.on) + } + override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let gradientColor: NSColor = NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8) - let width = self.frame.size.width - (MODULE_MARGIN * 2) - let height = self.frame.size.height - (MODULE_MARGIN * 2) + let width = self.frame.size.width - (widgetSize.margin * 2) + let height = self.frame.size.height - (widgetSize.margin * 2) - var x = MODULE_MARGIN - if labelEnabled { + var x = widgetSize.margin + if label { x = x + labelPadding } @@ -63,7 +86,7 @@ class BarChart: NSView, Widget { if partitonHeight < 1 { partitonHeight = 1 } - let partition = NSBezierPath(rect: NSRect(x: x, y: MODULE_MARGIN, width: partitionWidth - 0.5, height: partitonHeight)) + let partition = NSBezierPath(rect: NSRect(x: x, y: widgetSize.margin, width: partitionWidth - 0.5, height: partitonHeight)) gradientColor.setFill() partition.fill() partition.close() @@ -71,7 +94,7 @@ class BarChart: NSView, Widget { x += partitionWidth + partitionMargin } - if !self.labelEnabled { + if !self.label { return } @@ -83,12 +106,12 @@ class BarChart: NSView, Widget { NSAttributedString.Key.paragraphStyle: style ] - let letterHeight = (self.frame.size.height - (MODULE_MARGIN*2)) / 3 + let letterHeight = (self.frame.size.height - (widgetSize.margin*2)) / 3 let letterWidth: CGFloat = 10.0 - var yMargin = MODULE_MARGIN - for char in self.label.reversed() { - let rect = CGRect(x: MODULE_MARGIN, y: yMargin, width: letterWidth, height: letterHeight) + var yMargin = widgetSize.margin + for char in self.shortName.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) @@ -100,39 +123,22 @@ class BarChart: NSView, Widget { self.partitions = data } - func toggleLabel(state: Bool) { - labelEnabled = state - var width = self.frame.size.width - if width == MODULE_WIDTH + 10 && state { - width = width + labelPadding - } else { - width = MODULE_WIDTH + 10 - } - self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: self.frame.size.height) - } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - } - } - func redraw() { - var width: CGFloat = MODULE_WIDTH + 10 + var width: CGFloat = widgetSize.width + 10 if self.partitions.count == 1 { width = 18 } if self.partitions.count == 2 { width = 28 } - if self.labelEnabled { + if self.label { width += labelPadding } if self.frame.size.width != width { - self.active << false + self.activeModule << false self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: self.frame.size.height) - self.active << true + self.activeModule << true } self.needsDisplay = true diff --git a/Stats/Widgets/Chart.swift b/Stats/Widgets/Charts/LineChart.swift similarity index 56% rename from Stats/Widgets/Chart.swift rename to Stats/Widgets/Charts/LineChart.swift index 5531887b..ff791ce6 100644 --- a/Stats/Widgets/Chart.swift +++ b/Stats/Widgets/Charts/LineChart.swift @@ -1,22 +1,24 @@ // -// CPUView.swift +// LineChart.swift // Stats // -// Created by Serhiy Mytrovtsiy on 14.06.2019. +// Created by Serhiy Mytrovtsiy on 14.07.2019. // Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. // import Cocoa class Chart: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = MODULE_WIDTH + 7 + var activeModule: Observable = Observable(false) + var size: CGFloat = widgetSize.width + 7 var labelPadding: CGFloat = 10.0 - var labelEnabled: Bool = false - var label: String = "" + var label: Bool = false + var name: String = "" + var shortName: String = "" + var menus: [NSMenuItem] = [] + let defaults = UserDefaults.standard var height: CGFloat = 0.0 - var color: Bool = false var points: [Double] { didSet { self.redraw() @@ -25,19 +27,48 @@ class Chart: NSView, Widget { override init(frame: NSRect) { self.points = Array(repeating: 0.0, count: 50) - super.init(frame: frame) + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) self.wantsLayer = true self.addSubview(NSView()) - - if self.labelEnabled { - self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) - } } required init?(coder decoder: NSCoder) { fatalError("init(coder:) has not been implemented") } + func Init() { + self.label = defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true + self.initMenu() + + if self.label { + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) + } + } + + func initMenu() { + let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") + label.state = self.label ? NSControl.StateValue.on : NSControl.StateValue.off + label.target = self + + self.menus.append(label) + } + + @objc func toggleLabel(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(self.name)_label") + self.label = (sender.state == NSControl.StateValue.on) + + var width = self.size + if self.label { + width = width + labelPadding + } + + self.activeModule << false + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: self.frame.size.height) + self.activeModule << true + self.redraw() + } + override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) @@ -46,7 +77,7 @@ class Chart: NSView, Widget { let context = NSGraphicsContext.current!.cgContext var xOffset: CGFloat = 4.0 - if labelEnabled { + if label { xOffset = xOffset + labelPadding } let yOffset: CGFloat = 3.0 @@ -55,7 +86,7 @@ class Chart: NSView, Widget { } var xRatio = Double(self.frame.size.width - (xOffset * 2)) / (Double(self.points.count) - 1) - if labelEnabled { + if label { xRatio = Double(self.frame.size.width - (xOffset * 2) + labelPadding) / (Double(self.points.count) - 1) } @@ -95,7 +126,7 @@ class Chart: NSView, Widget { graphPath.lineWidth = 0.5 graphPath.stroke() - if !self.labelEnabled { + if !self.label { return } @@ -106,13 +137,13 @@ class Chart: NSView, Widget { NSAttributedString.Key.foregroundColor: NSColor.labelColor, NSAttributedString.Key.paragraphStyle: style ] - - let letterHeight = (self.frame.size.height - (MODULE_MARGIN*2)) / 3 + + let letterHeight = (self.frame.size.height - (widgetSize.margin*2)) / 3 let letterWidth: CGFloat = 10.0 - var yMargin = MODULE_MARGIN - for char in self.label.reversed() { - let rect = CGRect(x: MODULE_MARGIN, y: yMargin, width: letterWidth, height: letterHeight) + var yMargin = widgetSize.margin + for char in self.shortName.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) @@ -141,97 +172,4 @@ class Chart: NSView, Widget { } } } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - } - } - - func toggleLabel(state: Bool) { - labelEnabled = state - var width = self.size - if state { - width = width + labelPadding - } - self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: self.frame.size.height) - self.redraw() - } -} - -class ChartWithValue: Chart { - var valueLabel: NSTextField = NSTextField() - - override init(frame: NSRect) { - super.init(frame: frame) - self.wantsLayer = true - self.drawValue() - } - - required init?(coder decoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func setValue(data: [Double]) { - let value: Double = data.first! - - self.valueLabel.stringValue = "\(Int(Float(value.roundTo(decimalPlaces: 2))! * 100))%" - self.valueLabel.textColor = value.usageColor(color: self.color) - - if self.points.count < 50 { - self.points.append(value) - return - } - - for (i, _) in self.points.enumerated() { - if i+1 < self.points.count { - self.points[i] = self.points[i+1] - } else { - self.points[i] = value - } - } - } - - override func toggleLabel(state: Bool) { - labelEnabled = state - var width = self.size - if state { - width = width + labelPadding - } - self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: self.frame.size.height) - self.drawValue() - } - - override func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.valueLabel.textColor = self.points.last?.usageColor(color: state) - } - } - - func drawValue () { - for subview in self.subviews { - subview.removeFromSuperview() - } - - valueLabel = NSTextField(frame: NSMakeRect(2, MODULE_HEIGHT - 11, self.frame.size.width, 10)) - if labelEnabled { - valueLabel = NSTextField(frame: NSMakeRect(labelPadding + 2, MODULE_HEIGHT - 11, self.frame.size.width, 10)) - } - valueLabel.textColor = NSColor.red - valueLabel.isEditable = false - valueLabel.isSelectable = false - valueLabel.isBezeled = false - valueLabel.wantsLayer = true - valueLabel.textColor = .labelColor - valueLabel.backgroundColor = .controlColor - valueLabel.canDrawSubviewsIntoLayer = true - valueLabel.alignment = .natural - valueLabel.font = NSFont.systemFont(ofSize: 8, weight: .ultraLight) - valueLabel.stringValue = "" - valueLabel.addSubview(NSView()) - - self.height = 7.0 - self.addSubview(valueLabel) - } } diff --git a/Stats/Widgets/Charts/LineChartWithValue.swift b/Stats/Widgets/Charts/LineChartWithValue.swift new file mode 100644 index 00000000..a8e8d2c7 --- /dev/null +++ b/Stats/Widgets/Charts/LineChartWithValue.swift @@ -0,0 +1,114 @@ +// +// LineChartWithValue.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 14.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +class ChartWithValue: Chart { + var valueLabel: NSTextField = NSTextField() + var color: Bool = false + + override init(frame: NSRect) { + super.init(frame: CGRect(x: 0, y: 0, width: widgetSize.width + 7, height: widgetSize.height)) + self.wantsLayer = true + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func Init() { + self.label = defaults.object(forKey: "\(name)_label") != nil ? defaults.bool(forKey: "\(name)_label") : true + self.color = defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false + self.initMenu() + + if self.label { + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: self.frame.size.width + labelPadding, height: self.frame.size.height) + } + self.drawValue() + } + + override func initMenu() { + let label = NSMenuItem(title: "Label", action: #selector(toggleLabel), keyEquivalent: "") + label.state = self.label ? NSControl.StateValue.on : NSControl.StateValue.off + label.target = self + + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = self.color ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + + self.menus.append(label) + self.menus.append(color) + } + + override func setValue(data: [Double]) { + let value: Double = data.first! + + self.valueLabel.stringValue = "\(Int(Float(value.roundTo(decimalPlaces: 2))! * 100))%" + self.valueLabel.textColor = value.usageColor(color: self.color) + + if self.points.count < 50 { + self.points.append(value) + return + } + + for (i, _) in self.points.enumerated() { + if i+1 < self.points.count { + self.points[i] = self.points[i+1] + } else { + self.points[i] = value + } + } + } + + func drawValue () { + for subview in self.subviews { + subview.removeFromSuperview() + } + + valueLabel = NSTextField(frame: NSMakeRect(2, widgetSize.height - 11, self.frame.size.width, 10)) + if label { + valueLabel = NSTextField(frame: NSMakeRect(labelPadding + 2, widgetSize.height - 11, self.frame.size.width, 10)) + } + valueLabel.textColor = NSColor.red + valueLabel.isEditable = false + valueLabel.isSelectable = false + valueLabel.isBezeled = false + valueLabel.wantsLayer = true + valueLabel.textColor = .labelColor + valueLabel.backgroundColor = .controlColor + valueLabel.canDrawSubviewsIntoLayer = true + valueLabel.alignment = .natural + valueLabel.font = NSFont.systemFont(ofSize: 8, weight: .ultraLight) + valueLabel.stringValue = "" + valueLabel.addSubview(NSView()) + + self.height = 7.0 + self.addSubview(valueLabel) + } + + @objc override func toggleLabel(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(self.name)_label") + self.label = (sender.state == NSControl.StateValue.on) + + var width = self.size + if self.label { + width = width + labelPadding + } + self.activeModule << false + self.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: width, height: self.frame.size.height) + self.activeModule << true + self.drawValue() + } + + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color = sender.state == NSControl.StateValue.on + } +} diff --git a/Stats/Widgets/Mini.swift b/Stats/Widgets/Mini.swift index 09edcca8..6df037e5 100644 --- a/Stats/Widgets/Mini.swift +++ b/Stats/Widgets/Mini.swift @@ -9,22 +9,25 @@ import Cocoa class Mini: NSView, Widget { - var active: Observable = Observable(false) + var activeModule: Observable = Observable(false) + var menus: [NSMenuItem] = [] + let defaults = UserDefaults.standard - var size: CGFloat = MODULE_WIDTH + var size: CGFloat = widgetSize.width var valueView: NSTextField = NSTextField() var labelView: NSTextField = NSTextField() var color: Bool = false var value: Double = 0 - var label: String = "" { + var name: String = "" + var shortName: String = "" { didSet { - self.labelView.stringValue = label + self.labelView.stringValue = shortName } } override init(frame: NSRect) { - super.init(frame: frame) + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) self.wantsLayer = true @@ -41,7 +44,7 @@ class Mini: NSView, Widget { labelView.canDrawSubviewsIntoLayer = true labelView.alignment = .natural labelView.font = NSFont.systemFont(ofSize: 7, weight: .ultraLight) - labelView.stringValue = self.label + labelView.stringValue = self.shortName labelView.addSubview(NSView()) let valueView = NSTextField(frame: NSMakeRect(xOffset, 3, self.frame.size.width, 10)) @@ -69,6 +72,20 @@ class Mini: NSView, Widget { fatalError("init(coder:) has not been implemented") } + func Init() { + self.color = defaults.object(forKey: "\(name)_color") != nil ? defaults.bool(forKey: "\(name)_color") : false + self.initMenu() + self.redraw() + } + + func initMenu() { + let color = NSMenuItem(title: "Color", action: #selector(toggleColor), keyEquivalent: "") + color.state = self.color ? NSControl.StateValue.on : NSControl.StateValue.off + color.target = self + + self.menus.append(color) + } + func redraw() { self.valueView.textColor = self.value.usageColor(color: self.color) self.needsDisplay = true @@ -85,12 +102,9 @@ class Mini: NSView, Widget { } } - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.valueView.textColor = value.usageColor(color: state) - } + @objc func toggleColor(_ sender: NSMenuItem) { + sender.state = sender.state == NSControl.StateValue.on ? NSControl.StateValue.off : NSControl.StateValue.on + self.defaults.set(sender.state == NSControl.StateValue.on, forKey: "\(name)_color") + self.color = sender.state == NSControl.StateValue.on } - - func toggleLabel(state: Bool) {} } diff --git a/Stats/Widgets/Network/NetworkArrows.swift b/Stats/Widgets/Network/NetworkArrows.swift new file mode 100644 index 00000000..5905f8ed --- /dev/null +++ b/Stats/Widgets/Network/NetworkArrows.swift @@ -0,0 +1,99 @@ +// +// NetworkArrows.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 14.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +class NetworkArrowsView: NSView, Widget { + var menus: [NSMenuItem] = [] + var activeModule: Observable = Observable(false) + var size: CGFloat = 8 + var name: String = "" + var shortName: String = "" + + var color: Observable = Observable(false) + var download: Int64 { + didSet { + self.redraw() + } + } + var upload: Int64 { + didSet { + self.redraw() + } + } + + override init(frame: NSRect) { + self.download = 0 + self.upload = 0 + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) + self.wantsLayer = true + self.addSubview(NSView()) + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func Init() {} + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + + let arrowAngle = CGFloat(Double.pi / 5) + let pointerLineLength: CGFloat = 3.5 + let workingHeight: CGFloat = (self.frame.size.height - (widgetSize.margin * 2)) + let height: CGFloat = ((workingHeight - widgetSize.margin) / 2) + + let downloadArrow = NSBezierPath() + let downloadStart = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: height + widgetSize.margin) + let downloadEnd = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: widgetSize.margin) + + downloadArrow.addArrow(start: downloadStart, end: downloadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) + + if self.download >= 1_024 { + NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).set() + } else { + NSColor.labelColor.set() + } + downloadArrow.lineWidth = 1 + downloadArrow.stroke() + downloadArrow.close() + + let uploadArrow = NSBezierPath() + let uploadStart = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: height + (widgetSize.margin * 2)) + let uploadEnd = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: (widgetSize.margin * 2) + (height * 2)) + + uploadArrow.addArrow(start: uploadStart, end: uploadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) + + if self.upload >= 1_024 { + NSColor.red.set() + } else { + NSColor.labelColor.set() + } + uploadArrow.lineWidth = 1 + uploadArrow.stroke() + uploadArrow.close() + } + + func redraw() { + self.needsDisplay = true + setNeedsDisplay(self.frame) + } + + func setValue(data: [Double]) { + let download: Int64 = Int64(data[0]) + let upload: Int64 = Int64(data[1]) + + if self.download != download { + self.download = download + } + if self.upload != upload { + self.upload = upload + } + } +} diff --git a/Stats/Widgets/Network/NetworkArrowsText.swift b/Stats/Widgets/Network/NetworkArrowsText.swift new file mode 100644 index 00000000..82426c4f --- /dev/null +++ b/Stats/Widgets/Network/NetworkArrowsText.swift @@ -0,0 +1,133 @@ +// +// NetworkArrowsText.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 14.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +class NetworkArrowsTextView: NSView, Widget { + var menus: [NSMenuItem] = [] + var activeModule: Observable = Observable(false) + var size: CGFloat = widgetSize.width + 24 + var name: String = "" + var shortName: String = "" + + var color: Observable = Observable(false) + var download: Int64 { + didSet { + self.redraw() + } + } + var upload: Int64 { + didSet { + self.redraw() + } + } + + var downloadValue: NSTextField = NSTextField() + var uploadValue: NSTextField = NSTextField() + + override init(frame: NSRect) { + self.download = 0 + self.upload = 0 + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) + self.wantsLayer = true + self.valueView() + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func Init() {} + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + + let arrowAngle = CGFloat(Double.pi / 5) + let pointerLineLength: CGFloat = 3.5 + let workingHeight: CGFloat = (self.frame.size.height - (widgetSize.margin * 2)) + let height: CGFloat = ((workingHeight - widgetSize.margin) / 2) + + let downloadArrow = NSBezierPath() + let downloadStart = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: height + widgetSize.margin) + let downloadEnd = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: widgetSize.margin) + + downloadArrow.addArrow(start: downloadStart, end: downloadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) + + if self.download >= 1_024 { + NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).set() + } else { + NSColor.labelColor.set() + } + downloadArrow.lineWidth = 1 + downloadArrow.stroke() + downloadArrow.close() + + let uploadArrow = NSBezierPath() + let uploadStart = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: height + (widgetSize.margin * 2)) + let uploadEnd = CGPoint(x: widgetSize.margin + (pointerLineLength/2), y: (widgetSize.margin * 2) + (height * 2)) + + uploadArrow.addArrow(start: uploadStart, end: uploadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) + + if self.upload >= 1_024 { + NSColor.red.set() + } else { + NSColor.labelColor.set() + } + uploadArrow.lineWidth = 1 + uploadArrow.stroke() + uploadArrow.close() + } + + func redraw() { + self.needsDisplay = true + setNeedsDisplay(self.frame) + } + + func setValue(data: [Double]) { + let download: Int64 = Int64(data[0]) + let upload: Int64 = Int64(data[1]) + + if self.download != download { + self.download = download + downloadValue.stringValue = Units(bytes: self.download).getReadableUnit() + } + if self.upload != upload { + self.upload = upload + uploadValue.stringValue = Units(bytes: self.upload).getReadableUnit() + } + } + + func valueView() { + downloadValue = NSTextField(frame: NSMakeRect(widgetSize.margin, widgetSize.margin, self.frame.size.width - widgetSize.margin, 9)) + downloadValue.isEditable = false + downloadValue.isSelectable = false + downloadValue.isBezeled = false + downloadValue.wantsLayer = true + downloadValue.textColor = .labelColor + downloadValue.backgroundColor = .controlColor + downloadValue.canDrawSubviewsIntoLayer = true + downloadValue.alignment = .right + downloadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) + downloadValue.stringValue = "0 KB/s" + + uploadValue = NSTextField(frame: NSMakeRect(widgetSize.margin, self.frame.size.height - 10, self.frame.size.width - widgetSize.margin, 9)) + uploadValue.isEditable = false + uploadValue.isSelectable = false + uploadValue.isBezeled = false + uploadValue.wantsLayer = true + uploadValue.textColor = .labelColor + uploadValue.backgroundColor = .controlColor + uploadValue.canDrawSubviewsIntoLayer = true + uploadValue.alignment = .right + uploadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) + uploadValue.stringValue = "0 KB/s" + + self.addSubview(downloadValue) + self.addSubview(uploadValue) + } +} diff --git a/Stats/Widgets/Network/NetworkDots.swift b/Stats/Widgets/Network/NetworkDots.swift new file mode 100644 index 00000000..4b8c2652 --- /dev/null +++ b/Stats/Widgets/Network/NetworkDots.swift @@ -0,0 +1,85 @@ +// +// NetworkDots.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 14.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +class NetworkDotsView: NSView, Widget { + var activeModule: Observable = Observable(false) + var size: CGFloat = 12 + var name: String = "" + var shortName: String = "" + var menus: [NSMenuItem] = [] + + var color: Observable = Observable(false) + var download: Int64 { + didSet { + self.redraw() + } + } + var upload: Int64 { + didSet { + self.redraw() + } + } + + override init(frame: NSRect) { + self.download = 0 + self.upload = 0 + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) + self.wantsLayer = true + self.addSubview(NSView()) + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func Init() {} + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + + let workingHeight: CGFloat = (self.frame.size.height - (widgetSize.margin * 2)) + let height: CGFloat = ((workingHeight - widgetSize.margin) / 2) - 1 + + var uploadCircle = NSBezierPath() + uploadCircle = NSBezierPath(ovalIn: CGRect(x: widgetSize.margin, y: height + (widgetSize.margin * 2) + 1, width: height, height: height)) + if self.upload >= 1_024 { + NSColor.red.setFill() + } else { + NSColor.labelColor.setFill() + } + uploadCircle.fill() + + var downloadCircle = NSBezierPath() + downloadCircle = NSBezierPath(ovalIn: CGRect(x: widgetSize.margin, y: widgetSize.margin, width: height, height: height)) + if self.download >= 1_024 { + NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).setFill() + } else { + NSColor.labelColor.setFill() + } + downloadCircle.fill() + } + + func redraw() { + self.needsDisplay = true + setNeedsDisplay(self.frame) + } + + func setValue(data: [Double]) { + let download: Int64 = Int64(data[0]) + let upload: Int64 = Int64(data[1]) + + if self.download != download { + self.download = download + } + if self.upload != upload { + self.upload = upload + } + } +} diff --git a/Stats/Widgets/Network/NetworkDotsText.swift b/Stats/Widgets/Network/NetworkDotsText.swift new file mode 100644 index 00000000..ab57aa7b --- /dev/null +++ b/Stats/Widgets/Network/NetworkDotsText.swift @@ -0,0 +1,119 @@ +// +// NetworkDotsText.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 14.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +class NetworkDotsTextView: NSView, Widget { + var menus: [NSMenuItem] = [] + var activeModule: Observable = Observable(false) + var size: CGFloat = widgetSize.width + 26 + var name: String = "" + var shortName: String = "" + + var color: Observable = Observable(false) + var download: Int64 { + didSet { + self.redraw() + } + } + var upload: Int64 { + didSet { + self.redraw() + } + } + + var downloadValue: NSTextField = NSTextField() + var uploadValue: NSTextField = NSTextField() + + override init(frame: NSRect) { + self.download = 0 + self.upload = 0 + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) + self.wantsLayer = true + self.valueView() + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func Init() {} + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + + let workingHeight: CGFloat = (self.frame.size.height - (widgetSize.margin * 2)) + let height: CGFloat = ((workingHeight - widgetSize.margin) / 2) - 1 + + var uploadCircle = NSBezierPath() + uploadCircle = NSBezierPath(ovalIn: CGRect(x: widgetSize.margin, y: height + (widgetSize.margin * 2) + 1, width: height, height: height)) + if self.upload >= 1_024 { + NSColor.red.setFill() + } else { + NSColor.labelColor.setFill() + } + uploadCircle.fill() + + var downloadCircle = NSBezierPath() + downloadCircle = NSBezierPath(ovalIn: CGRect(x: widgetSize.margin, y: widgetSize.margin, width: height, height: height)) + if self.download >= 1_024 { + NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).setFill() + } else { + NSColor.labelColor.setFill() + } + downloadCircle.fill() + } + + func redraw() { + self.needsDisplay = true + setNeedsDisplay(self.frame) + } + + func setValue(data: [Double]) { + let download: Int64 = Int64(data[0]) + let upload: Int64 = Int64(data[1]) + + if self.download != download { + self.download = download + downloadValue.stringValue = Units(bytes: self.download).getReadableUnit() + } + if self.upload != upload { + self.upload = upload + uploadValue.stringValue = Units(bytes: self.upload).getReadableUnit() + } + } + + func valueView() { + downloadValue = NSTextField(frame: NSMakeRect(widgetSize.margin, widgetSize.margin, self.frame.size.width - widgetSize.margin, 9)) + downloadValue.isEditable = false + downloadValue.isSelectable = false + downloadValue.isBezeled = false + downloadValue.wantsLayer = true + downloadValue.textColor = .labelColor + downloadValue.backgroundColor = .controlColor + downloadValue.canDrawSubviewsIntoLayer = true + downloadValue.alignment = .right + downloadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) + downloadValue.stringValue = "0 KB/s" + + uploadValue = NSTextField(frame: NSMakeRect(widgetSize.margin, self.frame.size.height - 10, self.frame.size.width - widgetSize.margin, 9)) + uploadValue.isEditable = false + uploadValue.isSelectable = false + uploadValue.isBezeled = false + uploadValue.wantsLayer = true + uploadValue.textColor = .labelColor + uploadValue.backgroundColor = .controlColor + uploadValue.canDrawSubviewsIntoLayer = true + uploadValue.alignment = .right + uploadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) + uploadValue.stringValue = "0 KB/s" + + self.addSubview(downloadValue) + self.addSubview(uploadValue) + } +} diff --git a/Stats/Widgets/Network/NetworkText.swift b/Stats/Widgets/Network/NetworkText.swift new file mode 100644 index 00000000..45a37525 --- /dev/null +++ b/Stats/Widgets/Network/NetworkText.swift @@ -0,0 +1,79 @@ +// +// NetworkText.swift +// Stats +// +// Created by Serhiy Mytrovtsiy on 14.07.2019. +// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. +// + +import Cocoa + +class NetworkTextView: NSView, Widget { + var menus: [NSMenuItem] = [] + var activeModule: Observable = Observable(false) + var size: CGFloat = widgetSize.width + 20 + var name: String = "" + var shortName: String = "" + + var color: Observable = Observable(false) + var downloadValue: NSTextField = NSTextField() + var uploadValue: NSTextField = NSTextField() + + override init(frame: NSRect) { + super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: widgetSize.height)) + self.wantsLayer = true + self.valueView() + } + + required init?(coder decoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func Init() {} + + override func draw(_ dirtyRect: NSRect) { + super.draw(dirtyRect) + } + + func redraw() { + self.needsDisplay = true + setNeedsDisplay(self.frame) + } + + func setValue(data: [Double]) { + let download: Int64 = Int64(data[0]) + let upload: Int64 = Int64(data[1]) + + downloadValue.stringValue = Units(bytes: download).getReadableUnit() + uploadValue.stringValue = Units(bytes: upload).getReadableUnit() + } + + func valueView() { + downloadValue = NSTextField(frame: NSMakeRect(widgetSize.width, widgetSize.margin, self.frame.size.width - widgetSize.margin, 9)) + downloadValue.isEditable = false + downloadValue.isSelectable = false + downloadValue.isBezeled = false + downloadValue.wantsLayer = true + downloadValue.textColor = .labelColor + downloadValue.backgroundColor = .controlColor + downloadValue.canDrawSubviewsIntoLayer = true + downloadValue.alignment = .right + downloadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) + downloadValue.stringValue = "0 KB/s" + + uploadValue = NSTextField(frame: NSMakeRect(widgetSize.margin, self.frame.size.height - 10, self.frame.size.width - widgetSize.margin, 9)) + uploadValue.isEditable = false + uploadValue.isSelectable = false + uploadValue.isBezeled = false + uploadValue.wantsLayer = true + uploadValue.textColor = .labelColor + uploadValue.backgroundColor = .controlColor + uploadValue.canDrawSubviewsIntoLayer = true + uploadValue.alignment = .right + uploadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) + uploadValue.stringValue = "0 KB/s" + + self.addSubview(downloadValue) + self.addSubview(uploadValue) + } +} diff --git a/Stats/Widgets/NetworkView.swift b/Stats/Widgets/NetworkView.swift deleted file mode 100644 index b2824246..00000000 --- a/Stats/Widgets/NetworkView.swift +++ /dev/null @@ -1,504 +0,0 @@ -// -// NetworkView.swift -// Stats -// -// Created by Serhiy Mytrovtsiy on 24.06.2019. -// Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. -// - -import Cocoa - -class NetworkDotsView: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = 12 - var label: String = "" - - var color: Bool = false - var download: Int64 { - didSet { - self.redraw() - } - } - var upload: Int64 { - didSet { - self.redraw() - } - } - - override init(frame: NSRect) { - self.download = 0 - self.upload = 0 - super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: frame.size.height)) - self.wantsLayer = true - self.addSubview(NSView()) - } - - required init?(coder decoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - - let workingHeight: CGFloat = (self.frame.size.height - (MODULE_MARGIN * 2)) - let height: CGFloat = ((workingHeight - MODULE_MARGIN) / 2) - 1 - - var uploadCircle = NSBezierPath() - uploadCircle = NSBezierPath(ovalIn: CGRect(x: MODULE_MARGIN, y: height + (MODULE_MARGIN * 2) + 1, width: height, height: height)) - if self.upload >= 1_024 { - NSColor.red.setFill() - } else { - NSColor.labelColor.setFill() - } - uploadCircle.fill() - - var downloadCircle = NSBezierPath() - downloadCircle = NSBezierPath(ovalIn: CGRect(x: MODULE_MARGIN, y: MODULE_MARGIN, width: height, height: height)) - if self.download >= 1_024 { - NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).setFill() - } else { - NSColor.labelColor.setFill() - } - downloadCircle.fill() - } - - func redraw() { - self.needsDisplay = true - setNeedsDisplay(self.frame) - } - - func setValue(data: [Double]) { - let download: Int64 = Int64(data[0]) - let upload: Int64 = Int64(data[1]) - - if self.download != download { - self.download = download - } - if self.upload != upload { - self.upload = upload - } - } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.redraw() - } - } - - func toggleLabel(state: Bool) {} -} - -class NetworkTextView: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = MODULE_WIDTH + 20 - var label: String = "" - - var color: Bool = false - var downloadValue: NSTextField = NSTextField() - var uploadValue: NSTextField = NSTextField() - - override init(frame: NSRect) { - super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: frame.size.height)) - self.wantsLayer = true - self.valueView() - } - - required init?(coder decoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - } - - func redraw() { - self.needsDisplay = true - setNeedsDisplay(self.frame) - } - - func setValue(data: [Double]) { - let download: Int64 = Int64(data[0]) - let upload: Int64 = Int64(data[1]) - - downloadValue.stringValue = Units(bytes: download).getReadableUnit() - uploadValue.stringValue = Units(bytes: upload).getReadableUnit() - } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.redraw() - } - } - - func toggleLabel(state: Bool) {} - - func valueView() { - downloadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, MODULE_MARGIN, self.frame.size.width - MODULE_MARGIN, 9)) - downloadValue.isEditable = false - downloadValue.isSelectable = false - downloadValue.isBezeled = false - downloadValue.wantsLayer = true - downloadValue.textColor = .labelColor - downloadValue.backgroundColor = .controlColor - downloadValue.canDrawSubviewsIntoLayer = true - downloadValue.alignment = .right - downloadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) - downloadValue.stringValue = "0 KB/s" - - uploadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, self.frame.size.height - 10, self.frame.size.width - MODULE_MARGIN, 9)) - uploadValue.isEditable = false - uploadValue.isSelectable = false - uploadValue.isBezeled = false - uploadValue.wantsLayer = true - uploadValue.textColor = .labelColor - uploadValue.backgroundColor = .controlColor - uploadValue.canDrawSubviewsIntoLayer = true - uploadValue.alignment = .right - uploadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) - uploadValue.stringValue = "0 KB/s" - - self.addSubview(downloadValue) - self.addSubview(uploadValue) - } -} - -class NetworkArrowsView: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = 8 - var label: String = "" - - var color: Bool = false - var download: Int64 { - didSet { - self.redraw() - } - } - var upload: Int64 { - didSet { - self.redraw() - } - } - - override init(frame: NSRect) { - self.download = 0 - self.upload = 0 - super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: frame.size.height)) - self.wantsLayer = true - self.addSubview(NSView()) - } - - required init?(coder decoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - - let arrowAngle = CGFloat(Double.pi / 5) - let pointerLineLength: CGFloat = 3.5 - let workingHeight: CGFloat = (self.frame.size.height - (MODULE_MARGIN * 2)) - let height: CGFloat = ((workingHeight - MODULE_MARGIN) / 2) - - let downloadArrow = NSBezierPath() - let downloadStart = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: height + MODULE_MARGIN) - let downloadEnd = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: MODULE_MARGIN) - - downloadArrow.addArrow(start: downloadStart, end: downloadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) - - if self.download >= 1_024 { - NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).set() - } else { - NSColor.labelColor.set() - } - downloadArrow.lineWidth = 1 - downloadArrow.stroke() - downloadArrow.close() - - let uploadArrow = NSBezierPath() - let uploadStart = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: height + (MODULE_MARGIN * 2)) - let uploadEnd = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: (MODULE_MARGIN * 2) + (height * 2)) - - uploadArrow.addArrow(start: uploadStart, end: uploadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) - - if self.upload >= 1_024 { - NSColor.red.set() - } else { - NSColor.labelColor.set() - } - uploadArrow.lineWidth = 1 - uploadArrow.stroke() - uploadArrow.close() - } - - func redraw() { - self.needsDisplay = true - setNeedsDisplay(self.frame) - } - - func setValue(data: [Double]) { - let download: Int64 = Int64(data[0]) - let upload: Int64 = Int64(data[1]) - - if self.download != download { - self.download = download - } - if self.upload != upload { - self.upload = upload - } - } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.redraw() - } - } - - func toggleLabel(state: Bool) {} -} - -class NetworkDotsTextView: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = MODULE_WIDTH + 26 - var label: String = "" - - var color: Bool = false - var download: Int64 { - didSet { - self.redraw() - } - } - var upload: Int64 { - didSet { - self.redraw() - } - } - - var downloadValue: NSTextField = NSTextField() - var uploadValue: NSTextField = NSTextField() - - override init(frame: NSRect) { - self.download = 0 - self.upload = 0 - super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: frame.size.height)) - self.wantsLayer = true - self.valueView() - } - - required init?(coder decoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - - let workingHeight: CGFloat = (self.frame.size.height - (MODULE_MARGIN * 2)) - let height: CGFloat = ((workingHeight - MODULE_MARGIN) / 2) - 1 - - var uploadCircle = NSBezierPath() - uploadCircle = NSBezierPath(ovalIn: CGRect(x: MODULE_MARGIN, y: height + (MODULE_MARGIN * 2) + 1, width: height, height: height)) - if self.upload >= 1_024 { - NSColor.red.setFill() - } else { - NSColor.labelColor.setFill() - } - uploadCircle.fill() - - var downloadCircle = NSBezierPath() - downloadCircle = NSBezierPath(ovalIn: CGRect(x: MODULE_MARGIN, y: MODULE_MARGIN, width: height, height: height)) - if self.download >= 1_024 { - NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).setFill() - } else { - NSColor.labelColor.setFill() - } - downloadCircle.fill() - } - - func redraw() { - self.needsDisplay = true - setNeedsDisplay(self.frame) - } - - func setValue(data: [Double]) { - let download: Int64 = Int64(data[0]) - let upload: Int64 = Int64(data[1]) - - if self.download != download { - self.download = download - downloadValue.stringValue = Units(bytes: self.download).getReadableUnit() - } - if self.upload != upload { - self.upload = upload - uploadValue.stringValue = Units(bytes: self.upload).getReadableUnit() - } - } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.redraw() - } - } - - func toggleLabel(state: Bool) {} - - func valueView() { - downloadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, MODULE_MARGIN, self.frame.size.width - MODULE_MARGIN, 9)) - downloadValue.isEditable = false - downloadValue.isSelectable = false - downloadValue.isBezeled = false - downloadValue.wantsLayer = true - downloadValue.textColor = .labelColor - downloadValue.backgroundColor = .controlColor - downloadValue.canDrawSubviewsIntoLayer = true - downloadValue.alignment = .right - downloadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) - downloadValue.stringValue = "0 KB/s" - - uploadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, self.frame.size.height - 10, self.frame.size.width - MODULE_MARGIN, 9)) - uploadValue.isEditable = false - uploadValue.isSelectable = false - uploadValue.isBezeled = false - uploadValue.wantsLayer = true - uploadValue.textColor = .labelColor - uploadValue.backgroundColor = .controlColor - uploadValue.canDrawSubviewsIntoLayer = true - uploadValue.alignment = .right - uploadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) - uploadValue.stringValue = "0 KB/s" - - self.addSubview(downloadValue) - self.addSubview(uploadValue) - } -} - -class NetworkArrowsTextView: NSView, Widget { - var active: Observable = Observable(false) - var size: CGFloat = MODULE_WIDTH + 24 - var label: String = "" - - var color: Bool = false - var download: Int64 { - didSet { - self.redraw() - } - } - var upload: Int64 { - didSet { - self.redraw() - } - } - - var downloadValue: NSTextField = NSTextField() - var uploadValue: NSTextField = NSTextField() - - override init(frame: NSRect) { - self.download = 0 - self.upload = 0 - super.init(frame: CGRect(x: 0, y: 0, width: self.size, height: frame.size.height)) - self.wantsLayer = true - self.valueView() - } - - required init?(coder decoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func draw(_ dirtyRect: NSRect) { - super.draw(dirtyRect) - - let arrowAngle = CGFloat(Double.pi / 5) - let pointerLineLength: CGFloat = 3.5 - let workingHeight: CGFloat = (self.frame.size.height - (MODULE_MARGIN * 2)) - let height: CGFloat = ((workingHeight - MODULE_MARGIN) / 2) - - let downloadArrow = NSBezierPath() - let downloadStart = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: height + MODULE_MARGIN) - let downloadEnd = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: MODULE_MARGIN) - - downloadArrow.addArrow(start: downloadStart, end: downloadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) - - if self.download >= 1_024 { - NSColor(red: (26/255.0), green: (126/255.0), blue: (252/255.0), alpha: 0.8).set() - } else { - NSColor.labelColor.set() - } - downloadArrow.lineWidth = 1 - downloadArrow.stroke() - downloadArrow.close() - - let uploadArrow = NSBezierPath() - let uploadStart = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: height + (MODULE_MARGIN * 2)) - let uploadEnd = CGPoint(x: MODULE_MARGIN + (pointerLineLength/2), y: (MODULE_MARGIN * 2) + (height * 2)) - - uploadArrow.addArrow(start: uploadStart, end: uploadEnd, pointerLineLength: pointerLineLength, arrowAngle: arrowAngle) - - if self.upload >= 1_024 { - NSColor.red.set() - } else { - NSColor.labelColor.set() - } - uploadArrow.lineWidth = 1 - uploadArrow.stroke() - uploadArrow.close() - } - - func redraw() { - self.needsDisplay = true - setNeedsDisplay(self.frame) - } - - func setValue(data: [Double]) { - let download: Int64 = Int64(data[0]) - let upload: Int64 = Int64(data[1]) - - if self.download != download { - self.download = download - downloadValue.stringValue = Units(bytes: self.download).getReadableUnit() - } - if self.upload != upload { - self.upload = upload - uploadValue.stringValue = Units(bytes: self.upload).getReadableUnit() - } - } - - func toggleColor(state: Bool) { - if self.color != state { - self.color = state - self.redraw() - } - } - - func toggleLabel(state: Bool) {} - - func valueView() { - downloadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, MODULE_MARGIN, self.frame.size.width - MODULE_MARGIN, 9)) - downloadValue.isEditable = false - downloadValue.isSelectable = false - downloadValue.isBezeled = false - downloadValue.wantsLayer = true - downloadValue.textColor = .labelColor - downloadValue.backgroundColor = .controlColor - downloadValue.canDrawSubviewsIntoLayer = true - downloadValue.alignment = .right - downloadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) - downloadValue.stringValue = "0 KB/s" - - uploadValue = NSTextField(frame: NSMakeRect(MODULE_MARGIN, self.frame.size.height - 10, self.frame.size.width - MODULE_MARGIN, 9)) - uploadValue.isEditable = false - uploadValue.isSelectable = false - uploadValue.isBezeled = false - uploadValue.wantsLayer = true - uploadValue.textColor = .labelColor - uploadValue.backgroundColor = .controlColor - uploadValue.canDrawSubviewsIntoLayer = true - uploadValue.alignment = .right - uploadValue.font = NSFont.systemFont(ofSize: 9, weight: .light) - uploadValue.stringValue = "0 KB/s" - - self.addSubview(downloadValue) - self.addSubview(uploadValue) - } -} diff --git a/Stats/Widgets/Widget.swift b/Stats/Widgets/Widget.swift index 827b3c09..30cdf6e3 100644 --- a/Stats/Widgets/Widget.swift +++ b/Stats/Widgets/Widget.swift @@ -6,26 +6,21 @@ // Copyright © 2019 Serhiy Mytrovtsiy. All rights reserved. // -import Foundation +import Cocoa protocol Widget { - var size: CGFloat { get } - var label: String { get set } - var active: Observable { get set } + var name: String { get set } + var shortName: String { get set } + var activeModule: Observable { get set } + var menus: [NSMenuItem] { get } func setValue(data: [Double]) - func toggleColor(state: Bool) - func toggleLabel(state: Bool) func redraw() -} - -extension Widget { - func lable(state: Bool) {} + func Init() } typealias WidgetType = Float - struct Widgets { static let Mini: WidgetType = 0.0 static let Chart: WidgetType = 1.0 @@ -40,3 +35,10 @@ struct Widgets { static let BarChart: WidgetType = 3.0 } + +struct WidgetSize { + let width: CGFloat = 32 + let height: CGFloat = NSApplication.shared.mainMenu?.menuBarHeight ?? 22 + let margin: CGFloat = 2 +} +let widgetSize = WidgetSize()