From 1e85f2bf4ac75e6badb01cef5d35c0fe6bafcccd Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Sat, 5 Dec 2020 21:31:03 +0100 Subject: [PATCH] - improve Battery widget on low resolution displays (#105) - make Battery widget more similar to Big Sur --- ModuleKit/Widgets/Battery.swift | 124 +++++++++++++++++------------- ModuleKit/Widgets/LineChart.swift | 4 +- 2 files changed, 71 insertions(+), 57 deletions(-) diff --git a/ModuleKit/Widgets/Battery.swift b/ModuleKit/Widgets/Battery.swift index c23de206..3ff6a4af 100644 --- a/ModuleKit/Widgets/Battery.swift +++ b/ModuleKit/Widgets/Battery.swift @@ -29,16 +29,18 @@ public class BatterykWidget: Widget { public init(preview: Bool, title: String, config: NSDictionary?, store: UnsafePointer?) { let widgetTitle: String = title self.store = store + super.init(frame: CGRect( - x: 0, + x: Constants.Widget.margin.x, y: Constants.Widget.margin.y, - width: 30, + width: 30 + (2*Constants.Widget.margin.x), height: Constants.Widget.height - (2*Constants.Widget.margin.y) )) + self.title = widgetTitle self.type = .battery self.preview = preview - self.wantsLayer = true + self.canDrawConcurrently = true if self.store != nil { self.additional = store!.pointee.string(key: "\(self.title)_\(self.type.rawValue)_additional", defaultValue: self.additional) @@ -63,8 +65,10 @@ public class BatterykWidget: Widget { public override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - var width: CGFloat = 30 - var x: CGFloat = Constants.Widget.margin.x+1 + guard let ctx = NSGraphicsContext.current?.cgContext else { return } + + var width: CGFloat = Constants.Widget.margin.x*2 + var x: CGFloat = 0 let isShortTimeFormat: Bool = self.timeFormat == "short" if !self.hideAdditionalWhenFull || (self.hideAdditionalWhenFull && self.percentage != 1) { @@ -74,74 +78,85 @@ public class BatterykWidget: Widget { value: "\(Int((self.percentage.rounded(toPlaces: 2)) * 100))%", x: x ).rounded(.up) - width += rowWidth + Constants.Widget.margin.x - x += rowWidth + Constants.Widget.margin.x + width += rowWidth + Constants.Widget.spacing + x += rowWidth + Constants.Widget.spacing case "time": let rowWidth = self.drawOneRow( value: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat), x: x ).rounded(.up) - width += rowWidth + Constants.Widget.margin.x - x += rowWidth + Constants.Widget.margin.x + width += rowWidth + Constants.Widget.spacing + x += rowWidth + Constants.Widget.spacing case "percentageAndTime": let rowWidth = self.drawTwoRows( first: "\(Int((self.percentage.rounded(toPlaces: 2)) * 100))%", second: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat), x: x ).rounded(.up) - width += rowWidth + Constants.Widget.margin.x - x += rowWidth + Constants.Widget.margin.x + width += rowWidth + Constants.Widget.spacing + x += rowWidth + Constants.Widget.spacing case "timeAndPercentage": let rowWidth = self.drawTwoRows( first: Double(self.time*60).printSecondsToHoursMinutesSeconds(short: isShortTimeFormat), second: "\(Int((self.percentage.rounded(toPlaces: 2)) * 100))%", x: x ).rounded(.up) - width += rowWidth + Constants.Widget.margin.x - x += rowWidth + Constants.Widget.margin.x + width += rowWidth + Constants.Widget.spacing + x += rowWidth + Constants.Widget.spacing default: break } } - let w: CGFloat = 28 - (Constants.Widget.margin.x*2) - 4 - let h: CGFloat = 11 - let y: CGFloat = (dirtyRect.size.height - h) / 2 - let batteryFrame = NSBezierPath(roundedRect: NSRect(x: x+1, y: y, width: w, height: h), xRadius: 1.5, yRadius: 1.5) + let borderWidth: CGFloat = 1 + let batterySize: CGSize = CGSize(width: 22, height: 12) + let offset: CGFloat = 0.5 // contant! + width += batterySize.width + borderWidth*2 // add battery width - let bPX: CGFloat = x+w+1 - let bPY: CGFloat = (dirtyRect.size.height / 2) - 2 - let batteryPoint = NSBezierPath(roundedRect: NSRect(x: bPX, y: bPY, width: 2, height: 4), xRadius: 1, yRadius: 1) - NSColor.textColor.set() - batteryPoint.lineWidth = 1.1 - batteryPoint.stroke() + let batteryFrame = NSBezierPath(roundedRect: NSRect( + x: x + borderWidth + offset, + y: ((dirtyRect.size.height - batterySize.height)/2) + offset, + width: batterySize.width - borderWidth, + height: batterySize.height - borderWidth + ), xRadius: 2, yRadius: 2) + + NSColor.textColor.withAlphaComponent(0.5).set() + batteryFrame.lineWidth = borderWidth + batteryFrame.stroke() + + let bPX: CGFloat = batteryFrame.bounds.origin.x + batteryFrame.bounds.width + 1 + let bPY: CGFloat = batteryFrame.bounds.origin.y + batteryFrame.bounds.height/2 - 2 + let batteryPoint = NSBezierPath(roundedRect: NSRect(x: bPX - 1, y: bPY, width: 3, height: 4), xRadius: 2, yRadius: 2) batteryPoint.fill() - batteryFrame.lineWidth = 1 - batteryFrame.stroke() - - if !self.charging || !self.ACStatus { - let maxWidth = w - 3 - let innerWidth: CGFloat = self.ACStatus ? maxWidth : maxWidth * CGFloat(self.percentage) - let inner = NSBezierPath(roundedRect: NSRect(x: x+2.5, y: y+1.5, width: innerWidth, height: h-3), xRadius: 0.5, yRadius: 0.5) - self.percentage.batteryColor(color: self.colorState).set() - inner.lineWidth = 0 - inner.stroke() - inner.close() - inner.fill() - } else if self.charging { - let maxHeight = h - 3 - let height: CGFloat = maxHeight * CGFloat(self.percentage) - let inner = NSBezierPath(roundedRect: NSRect(x: x+2.5, y: y+1.5, width: w-3, height: height), xRadius: 0.5, yRadius: 0.5) - (self.percentage == 1 ? NSColor.textColor : NSColor.systemGreen).set() - inner.lineWidth = 0 - inner.stroke() - inner.close() - inner.fill() - } + let batteryPointSeparator = NSBezierPath() + batteryPointSeparator.move(to: CGPoint(x: bPX, y: batteryFrame.bounds.origin.y)) + batteryPointSeparator.line(to: CGPoint(x: bPX, y: batteryFrame.bounds.origin.y + batteryFrame.bounds.height)) + ctx.saveGState() + ctx.setBlendMode(.destinationOut) + NSColor.textColor.set() + batteryPointSeparator.lineWidth = borderWidth + batteryPointSeparator.stroke() + ctx.restoreGState() + width += 2 // add battery point width + + let maxWidth = batterySize.width - offset*2 - borderWidth*2 - 1 + let innerWidth: CGFloat = self.ACStatus && !self.charging ? maxWidth : max(1, maxWidth * CGFloat(self.percentage)) + let innerOffset: CGFloat = -offset + borderWidth + 1 + let inner = NSBezierPath(roundedRect: NSRect( + x: batteryFrame.bounds.origin.x + innerOffset, + y: batteryFrame.bounds.origin.y + innerOffset, + width: innerWidth, + height: batterySize.height - offset*2 - borderWidth*2 - 1 + ), xRadius: 1, yRadius: 1) + self.percentage.batteryColor(color: self.colorState).set() + inner.fill() if self.ACStatus { - let batteryCenter: CGPoint = CGPoint(x: x+1+(w/2), y: y+(h/2)) - let boltSize: CGSize = CGSize(width: 8, height: h+3+4) + let batteryCenter: CGPoint = CGPoint( + x: batteryFrame.bounds.origin.x + (batteryFrame.bounds.width/2), + y: batteryFrame.bounds.origin.y + (batteryFrame.bounds.height/2) + ) + let boltSize: CGSize = CGSize(width: 9, height: batterySize.height + 6) let minX = batteryCenter.x - (boltSize.width/2) let maxX = batteryCenter.x + (boltSize.width/2) @@ -149,10 +164,10 @@ public class BatterykWidget: Widget { let maxY = batteryCenter.y + (boltSize.height/2) let points: [CGPoint] = [ - CGPoint(x: batteryCenter.x-2, y: minY), + CGPoint(x: batteryCenter.x-3, y: minY), // bottom CGPoint(x: maxX, y: batteryCenter.y+1.5), CGPoint(x: batteryCenter.x+1, y: batteryCenter.y+1.5), - CGPoint(x: batteryCenter.x+2, y: maxY), + CGPoint(x: batteryCenter.x+3, y: maxY), // top CGPoint(x: minX, y: batteryCenter.y-1.5), CGPoint(x: batteryCenter.x-1, y: batteryCenter.y-1.5), ] @@ -167,12 +182,11 @@ public class BatterykWidget: Widget { NSColor.textColor.set() linePath.fill() - let ctx = NSGraphicsContext.current!.cgContext ctx.saveGState() ctx.setBlendMode(.destinationOut) NSColor.orange.set() - linePath.lineWidth = 1 + linePath.lineWidth = borderWidth linePath.stroke() ctx.restoreGState() @@ -200,15 +214,15 @@ public class BatterykWidget: Widget { let style = NSMutableParagraphStyle() style.alignment = .center let attributes = [ - NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9, weight: .light), + NSAttributedString.Key.font: NSFont.systemFont(ofSize: 9, weight: .regular), NSAttributedString.Key.foregroundColor: NSColor.textColor, NSAttributedString.Key.paragraphStyle: style ] let rowHeight: CGFloat = self.frame.height / 2 let rowWidth = max( - first.widthOfString(usingFont: .systemFont(ofSize: 9, weight: .light)), - second.widthOfString(usingFont: .systemFont(ofSize: 9, weight: .light)) + first.widthOfString(usingFont: .systemFont(ofSize: 9, weight: .regular)), + second.widthOfString(usingFont: .systemFont(ofSize: 9, weight: .regular)) ) var str = NSAttributedString.init(string: first, attributes: attributes) @@ -252,6 +266,8 @@ public class BatterykWidget: Widget { } } + // MARK: - Settings + public override func settings(superview: NSView) { let rowHeight: CGFloat = 30 let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 3) + Constants.Settings.margin diff --git a/ModuleKit/Widgets/LineChart.swift b/ModuleKit/Widgets/LineChart.swift index db2a2d98..ac318a7e 100644 --- a/ModuleKit/Widgets/LineChart.swift +++ b/ModuleKit/Widgets/LineChart.swift @@ -97,8 +97,6 @@ public class LineChart: Widget { self.chart.points = list self.value = 0.38 } - -// self.addSubview(self.chart) } required init?(coder: NSCoder) { @@ -234,7 +232,7 @@ public class LineChart: Widget { self.value = value DispatchQueue.main.async(execute: { -// self.chart.addValue(value) + self.chart.addValue(value) self.display() }) }