improved widget updates;

now charts updates only if a popup is opened;
removed shortName from widget;
widgets refactoring;
This commit is contained in:
Serhiy Mytrovtsiy
2020-01-19 23:40:04 +01:00
parent 66969e1766
commit 3bd9974ad9
22 changed files with 189 additions and 185 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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)
}
}

View File

@@ -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()
}
}

View File

@@ -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()
}
}

View File

@@ -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..<self.points.count {
graphPath.line(to: CGPoint(x: columnXPoint(i), y: columnYPoint(i)))
}
lineColor.setStroke()
graphPath.stroke()
context.saveGState()
let clippingPath = graphPath.copy() as! NSBezierPath
clippingPath.line(to: CGPoint(x: columnXPoint(self.points.count - 1), y: yOffset - 0.5))
clippingPath.line(to: CGPoint(x: columnXPoint(0), y: yOffset - 0.5))
clippingPath.close()
clippingPath.addClip()
gradientColor.setFill()
let rectPath = NSBezierPath(rect: dirtyRect)
rectPath.fill()
context.restoreGState()
graphPath.lineWidth = 0.5
graphPath.stroke()
if !self.label {
return
}
let style = NSMutableParagraphStyle()
style.alignment = .center
let stringAttributes = [
@@ -139,33 +135,32 @@ class Chart: NSView, Widget {
NSAttributedString.Key.foregroundColor: NSColor.labelColor,
NSAttributedString.Key.paragraphStyle: style
]
let letterHeight = (self.frame.size.height - (widgetSize.margin*2)) / 3
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)
yMargin += letterHeight
}
}
func redraw() {
self.needsDisplay = true
setNeedsDisplay(self.frame)
self.display()
}
func setValue(data: [Double]) {
let value: Double = data.first!
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]
@@ -173,5 +168,7 @@ class Chart: NSView, Widget {
self.points[i] = value
}
}
self.redraw()
}
}

View File

@@ -9,8 +9,8 @@
import Cocoa
class ChartWithValue: Chart {
var valueLabel: NSTextField = NSTextField()
var color: Bool = false
private var valueLabel: NSTextField = NSTextField()
private var color: Bool = false
override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
@@ -25,7 +25,7 @@ class ChartWithValue: Chart {
fatalError("init(coder:) has not been implemented")
}
override func Init() {
override func start() {
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()
@@ -67,6 +67,8 @@ class ChartWithValue: Chart {
self.points[i] = value
}
}
self.redraw()
}
func drawValue () {

View File

@@ -9,21 +9,16 @@
import Cocoa
class Mini: NSView, Widget {
var menus: [NSMenuItem] = []
let defaults = UserDefaults.standard
public var name: String = ""
public var menus: [NSMenuItem] = []
var size: CGFloat = widgetSize.width
var valueView: NSTextField = NSTextField()
var labelView: NSTextField = NSTextField()
private var value: Double = 0
private var size: CGFloat = widgetSize.width
private var valueView: NSTextField = NSTextField()
private var labelView: NSTextField = NSTextField()
private let defaults = UserDefaults.standard
var color: Bool = false
var value: Double = 0
var name: String = ""
var shortName: String = "" {
didSet {
self.labelView.stringValue = shortName
}
}
private var color: Bool = false
override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
@@ -46,7 +41,7 @@ class Mini: NSView, Widget {
labelView.canDrawSubviewsIntoLayer = true
labelView.alignment = .natural
labelView.font = NSFont.systemFont(ofSize: 7, weight: .light)
labelView.stringValue = self.shortName
labelView.stringValue = String(self.name.prefix(3)).uppercased()
labelView.addSubview(NSView())
let valueView = NSTextField(frame: NSMakeRect(xOffset, 3, self.frame.size.width, 10))
@@ -73,8 +68,9 @@ class Mini: 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.labelView.stringValue = String(self.name.prefix(3)).uppercased()
self.initMenu()
self.redraw()
}

View File

@@ -9,21 +9,12 @@
import Cocoa
class NetworkArrowsView: NSView, Widget {
var menus: [NSMenuItem] = []
var size: CGFloat = 8
var name: String = ""
var shortName: String = ""
public var menus: [NSMenuItem] = []
public var size: CGFloat = 8
public var name: String = ""
var download: Int64 {
didSet {
self.redraw()
}
}
var upload: Int64 {
didSet {
self.redraw()
}
}
private var download: Int64 = 0
private var upload: Int64 = 0
override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
@@ -41,7 +32,7 @@ class NetworkArrowsView: NSView, Widget {
fatalError("init(coder:) has not been implemented")
}
func Init() {}
func start() {}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
@@ -97,5 +88,7 @@ class NetworkArrowsView: NSView, Widget {
if self.upload != upload {
self.upload = upload
}
self.redraw()
}
}

View File

@@ -9,21 +9,12 @@
import Cocoa
class NetworkArrowsTextView: NSView, Widget {
var menus: [NSMenuItem] = []
var size: CGFloat = widgetSize.width + 24
var name: String = ""
var shortName: String = ""
public var menus: [NSMenuItem] = []
public var size: CGFloat = widgetSize.width + 24
public var name: String = ""
var download: Int64 {
didSet {
self.redraw()
}
}
var upload: Int64 {
didSet {
self.redraw()
}
}
private var download: Int64 = 0
private var upload: Int64 = 0
var downloadValue: NSTextField = NSTextField()
var uploadValue: NSTextField = NSTextField()
@@ -44,7 +35,7 @@ class NetworkArrowsTextView: NSView, Widget {
fatalError("init(coder:) has not been implemented")
}
func Init() {}
func start() {}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
@@ -102,6 +93,8 @@ class NetworkArrowsTextView: NSView, Widget {
self.upload = upload
uploadValue.stringValue = Units(bytes: self.upload).getReadableSpeed()
}
self.redraw()
}
func valueView() {

View File

@@ -9,21 +9,12 @@
import Cocoa
class NetworkDotsView: NSView, Widget {
var size: CGFloat = 12
var name: String = ""
var shortName: String = ""
var menus: [NSMenuItem] = []
public var size: CGFloat = 12
public var name: String = ""
public var menus: [NSMenuItem] = []
var download: Int64 {
didSet {
self.redraw()
}
}
var upload: Int64 {
didSet {
self.redraw()
}
}
private var download: Int64 = 0
private var upload: Int64 = 0
override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
@@ -41,7 +32,7 @@ class NetworkDotsView: NSView, Widget {
fatalError("init(coder:) has not been implemented")
}
func Init() {}
func start() {}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
@@ -83,5 +74,7 @@ class NetworkDotsView: NSView, Widget {
if self.upload != upload {
self.upload = upload
}
self.redraw()
}
}

View File

@@ -9,21 +9,12 @@
import Cocoa
class NetworkDotsTextView: NSView, Widget {
var menus: [NSMenuItem] = []
var size: CGFloat = widgetSize.width + 26
var name: String = ""
var shortName: String = ""
public var menus: [NSMenuItem] = []
public var size: CGFloat = widgetSize.width + 26
public var name: String = ""
var download: Int64 {
didSet {
self.redraw()
}
}
var upload: Int64 {
didSet {
self.redraw()
}
}
private var download: Int64 = 0
private var upload: Int64 = 0
override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
@@ -44,7 +35,7 @@ class NetworkDotsTextView: NSView, Widget {
fatalError("init(coder:) has not been implemented")
}
func Init() {}
func start() {}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
@@ -88,6 +79,8 @@ class NetworkDotsTextView: NSView, Widget {
self.upload = upload
uploadValue.stringValue = Units(bytes: self.upload).getReadableSpeed()
}
self.redraw()
}
func valueView() {

View File

@@ -9,13 +9,12 @@
import Cocoa
class NetworkTextView: NSView, Widget {
var menus: [NSMenuItem] = []
var size: CGFloat = widgetSize.width + 20
var name: String = ""
var shortName: String = ""
public var menus: [NSMenuItem] = []
public var size: CGFloat = widgetSize.width + 20
public var name: String = ""
var downloadValue: NSTextField = NSTextField()
var uploadValue: NSTextField = NSTextField()
private var downloadValue: NSTextField = NSTextField()
private var uploadValue: NSTextField = NSTextField()
override var intrinsicContentSize: CGSize {
return CGSize(width: self.frame.size.width, height: self.frame.size.height)
@@ -31,7 +30,7 @@ class NetworkTextView: NSView, Widget {
fatalError("init(coder:) has not been implemented")
}
func Init() {}
func start() {}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
@@ -48,6 +47,8 @@ class NetworkTextView: NSView, Widget {
downloadValue.stringValue = Units(bytes: download).getReadableSpeed()
uploadValue.stringValue = Units(bytes: upload).getReadableSpeed()
self.redraw()
}
func valueView() {

View File

@@ -9,14 +9,13 @@
import Cocoa
protocol Widget {
var name: String { get set }
var shortName: String { get set }
var menus: [NSMenuItem] { get }
func setValue(data: [Double])
var name: String { get set } // module name
var menus: [NSMenuItem] { get } // module settings
func start()
func redraw()
func Init()
func setValue(data: [Double]) // pass value to widget
}
typealias WidgetType = Float

View File

@@ -14,6 +14,11 @@ extension Double {
return NSString(format: "%.\(decimalPlaces)f" as NSString, self) as String
}
func rounded(toPlaces places:Int) -> 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