diff --git a/Kit/Widgets/BarChart.swift b/Kit/Widgets/BarChart.swift index e1c26cf1..cd196032 100644 --- a/Kit/Widgets/BarChart.swift +++ b/Kit/Widgets/BarChart.swift @@ -81,6 +81,7 @@ public class BarChart: WidgetWrapper { } self.setFrameSize(NSSize(width: 36, height: self.frame.size.height)) self.invalidateIntrinsicContentSize() + self.display() } } @@ -92,7 +93,7 @@ public class BarChart: WidgetWrapper { public override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - var width: CGFloat = (Constants.Widget.margin.x*2) + var width: CGFloat = Constants.Widget.margin.x*2 var x: CGFloat = 0 let lineWidth = 1 / (NSScreen.main?.backingScaleFactor ?? 1) let offset = lineWidth / 2 @@ -237,34 +238,30 @@ public class BarChart: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabel), state: self.labelState )) - self.boxSettingsView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + self.boxSettingsView = toggleSettingRow( title: localizedString("Box"), action: #selector(toggleBox), state: self.boxState ) view.addArrangedSubview(self.boxSettingsView!) - self.frameSettingsView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + self.frameSettingsView = toggleSettingRow( title: localizedString("Frame"), action: #selector(toggleFrame), state: self.frameState ) view.addArrangedSubview(self.frameSettingsView!) - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Color"), action: #selector(toggleColor), items: self.colors, diff --git a/Kit/Widgets/Battery.swift b/Kit/Widgets/Battery.swift index 25c8ea95..00f27f58 100644 --- a/Kit/Widgets/Battery.swift +++ b/Kit/Widgets/Battery.swift @@ -326,31 +326,28 @@ public class BatterykWidget: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() var additionalOptions = BatteryAdditionals if self.title == "Bluetooth" { additionalOptions = additionalOptions.filter({ $0.key == "none" || $0.key == "percentage" }) } - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Additional information"), action: #selector(toggleAdditional), items: additionalOptions, selected: self.additional )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Hide additional information when full"), action: #selector(toggleHideAdditionalWhenFull), state: self.hideAdditionalWhenFull )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Colorize"), action: #selector(toggleColor), state: self.colorState diff --git a/Kit/Widgets/LineChart.swift b/Kit/Widgets/LineChart.swift index 60679787..12de29d8 100644 --- a/Kit/Widgets/LineChart.swift +++ b/Kit/Widgets/LineChart.swift @@ -19,12 +19,12 @@ public class LineChart: WidgetWrapper { private var valueColorState: Bool = false private var colorState: Color = .systemAccent - private let width: CGFloat = 34 + private let width: CGFloat = 30 private var chart: LineChartView = LineChartView(frame: NSRect( x: 0, y: 0, - width: 34, + width: 30, height: Constants.Widget.height - (2*Constants.Widget.margin.y) ), num: 60) private var colors: [Color] = Color.allCases @@ -62,7 +62,7 @@ public class LineChart: WidgetWrapper { super.init(.lineChart, title: widgetTitle, frame: CGRect( x: Constants.Widget.margin.x, y: Constants.Widget.margin.y, - width: self.width + (2*Constants.Widget.margin.x), + width: self.width + (Constants.Widget.margin.x*2), height: Constants.Widget.height - (2*Constants.Widget.margin.y) )) @@ -101,7 +101,7 @@ public class LineChart: WidgetWrapper { guard let context = NSGraphicsContext.current?.cgContext else { return } - var width = self.width + var width = self.width + (Constants.Widget.margin.x*2) var x: CGFloat = 0 let lineWidth = 1 / (NSScreen.main?.backingScaleFactor ?? 1) let offset = lineWidth / 2 @@ -159,7 +159,7 @@ public class LineChart: WidgetWrapper { NSAttributedString.Key.paragraphStyle: style ] - let rect = CGRect(x: x, y: boxSize.height-7, width: boxSize.width-1, height: 7) + let rect = CGRect(x: x+4, y: boxSize.height-7, width: boxSize.width-1, height: 7) let str = NSAttributedString.init(string: "\(Int((value.rounded(toPlaces: 2)) * 100))%", attributes: stringAttributes) str.draw(with: rect) @@ -169,7 +169,7 @@ public class LineChart: WidgetWrapper { let box = NSBezierPath(roundedRect: NSRect( x: x+offset, y: offset, - width: self.width - Constants.Widget.margin.x*2 - offset*2, + width: self.width - offset*2, height: boxSize.height - (offset*2) ), xRadius: 2, yRadius: 2) @@ -242,58 +242,43 @@ public class LineChart: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let rowHeight: CGFloat = 30 - let settingsNumber: CGFloat = 6 - let height: CGFloat = ((rowHeight + Constants.Settings.margin) * settingsNumber) + Constants.Settings.margin + public override func settings() -> NSView { + let view = SettingsContainerView() - let view: NSView = NSView(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin, - width: width - (Constants.Settings.margin*2), - height: height - )) - - view.addSubview(toggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 5, width: view.frame.width, height: rowHeight), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabel), state: self.labelState )) - view.addSubview(toggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 4, width: view.frame.width, height: rowHeight), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Value"), action: #selector(toggleValue), state: self.valueState )) - self.boxSettingsView = toggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 3, width: view.frame.width, height: rowHeight), + self.boxSettingsView = toggleSettingRow( title: localizedString("Box"), action: #selector(toggleBox), state: self.boxState ) - view.addSubview(self.boxSettingsView!) + view.addArrangedSubview(self.boxSettingsView!) - self.frameSettingsView = toggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 2, width: view.frame.width, height: rowHeight), + self.frameSettingsView = toggleSettingRow( title: localizedString("Frame"), action: #selector(toggleFrame), state: self.frameState ) - view.addSubview(self.frameSettingsView!) + view.addArrangedSubview(self.frameSettingsView!) - view.addSubview(selectRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 1, width: view.frame.width, height: rowHeight), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Color"), action: #selector(toggleColor), items: self.colors, selected: self.colorState.key )) - view.addSubview(toggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 0, width: view.frame.width, height: rowHeight), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Colorize value"), action: #selector(toggleValueColor), state: self.valueColorState diff --git a/Kit/Widgets/Memory.swift b/Kit/Widgets/Memory.swift index 75ec0181..124104c8 100644 --- a/Kit/Widgets/Memory.swift +++ b/Kit/Widgets/Memory.swift @@ -98,19 +98,10 @@ public class MemoryWidget: WidgetWrapper { }) } - public override func settings(width: CGFloat) -> NSView { - let rowHeight: CGFloat = 30 - let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 1) + Constants.Settings.margin + public override func settings() -> NSView { + let view = SettingsContainerView() - let view: NSView = NSView(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin, - width: width - (Constants.Settings.margin*2), - height: height - )) - - view.addSubview(toggleTitleRow( - frame: NSRect(x: 0, y: (rowHeight + Constants.Settings.margin) * 0, width: view.frame.width, height: rowHeight), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Reverse values order"), action: #selector(toggleOrder), state: self.orderReversedState diff --git a/Kit/Widgets/Mini.swift b/Kit/Widgets/Mini.swift index bd570b14..fcb0f3d7 100644 --- a/Kit/Widgets/Mini.swift +++ b/Kit/Widgets/Mini.swift @@ -179,26 +179,23 @@ public class Mini: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabel), state: self.labelState )) - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Color"), action: #selector(toggleColor), items: self.colors, selected: self.colorState.key )) - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Alignment"), action: #selector(toggleAlignment), items: Alignments, diff --git a/Kit/Widgets/NetworkChart.swift b/Kit/Widgets/NetworkChart.swift index 21017257..b85a64b0 100644 --- a/Kit/Widgets/NetworkChart.swift +++ b/Kit/Widgets/NetworkChart.swift @@ -21,12 +21,12 @@ public class NetworkChart: WidgetWrapper { frame: NSRect( x: 0, y: 0, - width: 34, + width: 30, height: Constants.Widget.height - (2*Constants.Widget.margin.y) ), num: 60, minMax: false ) - private let width: CGFloat = 34 + private let width: CGFloat = 30 private var boxSettingsView: NSView? = nil private var frameSettingsView: NSView? = nil @@ -79,7 +79,7 @@ public class NetworkChart: WidgetWrapper { let offset = lineWidth / 2 let boxSize: CGSize = CGSize(width: self.width - (Constants.Widget.margin.x*2), height: self.frame.size.height) var x: CGFloat = 0 - var width: CGFloat = self.width + var width = self.width + (Constants.Widget.margin.x*2) if self.labelState { let style = NSMutableParagraphStyle() @@ -108,7 +108,7 @@ public class NetworkChart: WidgetWrapper { let box = NSBezierPath(roundedRect: NSRect( x: x + offset, y: offset, - width: boxSize.width - (offset*2), + width: self.width - offset*2, height: boxSize.height - (offset*2) ), xRadius: 2, yRadius: 2) @@ -120,12 +120,14 @@ public class NetworkChart: WidgetWrapper { context.saveGState() - self.chart.draw(NSRect( - x: x+offset, - y: 1, - width: box.bounds.width - 1 - offset, - height: box.bounds.height - ((box.bounds.origin.y + lineWidth)*2) - )) + let chartFrame = NSRect( + x: x+offset+lineWidth, + y: offset, + width: box.bounds.width - (offset*2+lineWidth), + height: box.bounds.height - offset + ) + self.chart.setFrameSize(NSSize(width: chartFrame.width, height: chartFrame.height)) + self.chart.draw(chartFrame) context.restoreGState() @@ -147,34 +149,30 @@ public class NetworkChart: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabel), state: self.labelState )) - self.boxSettingsView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + self.boxSettingsView = toggleSettingRow( title: localizedString("Box"), action: #selector(toggleBox), state: self.boxState ) view.addArrangedSubview(self.boxSettingsView!) - self.frameSettingsView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + self.frameSettingsView = toggleSettingRow( title: localizedString("Frame"), action: #selector(toggleFrame), state: self.frameState ) view.addArrangedSubview(self.frameSettingsView!) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Monochrome accent"), action: #selector(toggleMonochrome), state: self.monochromeState diff --git a/Kit/Widgets/PieChart.swift b/Kit/Widgets/PieChart.swift index 93bb0dfc..73620988 100644 --- a/Kit/Widgets/PieChart.swift +++ b/Kit/Widgets/PieChart.swift @@ -91,19 +91,10 @@ public class PieChart: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let rowHeight: CGFloat = 30 - let height: CGFloat = ((rowHeight + Constants.Settings.margin) * 1) + Constants.Settings.margin + public override func settings() -> NSView { + let view = SettingsContainerView() - let view: NSView = NSView(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin, - width: width - (Constants.Settings.margin*2), - height: height - )) - - view.addSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: rowHeight), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabel), state: self.labelState diff --git a/Kit/Widgets/Sensors.swift b/Kit/Widgets/Sensors.swift index 419165a2..1695076d 100644 --- a/Kit/Widgets/Sensors.swift +++ b/Kit/Widgets/Sensors.swift @@ -35,11 +35,6 @@ public class SensorsWidget: WidgetWrapper { } } - if title == "Fans" { // hack for fans. Because fan value contain RPM. - self.oneRowWidth = 64 - self.twoRowWidth = 50 - } - super.init(.sensors, title: title, frame: CGRect( x: 0, y: Constants.Widget.margin.y, @@ -180,19 +175,17 @@ public class SensorsWidget: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Display mode"), action: #selector(changeMode), items: SensorsWidgetMode, selected: self.modeState )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Static width"), action: #selector(toggleSize), state: self.fixedSizeState diff --git a/Kit/Widgets/Speed.swift b/Kit/Widgets/Speed.swift index 1acc3190..6b692f15 100644 --- a/Kit/Widgets/Speed.swift +++ b/Kit/Widgets/Speed.swift @@ -212,41 +212,36 @@ public class SpeedWidget: WidgetWrapper { } } - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Pictogram"), action: #selector(toggleIcon), items: SpeedPictogram, selected: self.icon )) - view.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(selectSettingsRow( title: localizedString("Base"), action: #selector(toggleBase), items: SpeedBase, selected: self.baseValue )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Value"), action: #selector(toggleValue), state: self.valueState )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Units"), action: #selector(toggleUnits), state: self.unitsState )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Monochrome accent"), action: #selector(toggleMonochrome), state: self.monochromeState diff --git a/Kit/Widgets/Tachometer.swift b/Kit/Widgets/Tachometer.swift index 746e825c..a3fa46aa 100644 --- a/Kit/Widgets/Tachometer.swift +++ b/Kit/Widgets/Tachometer.swift @@ -87,18 +87,16 @@ public class Tachometer: WidgetWrapper { // MARK: - Settings - public override func settings(width: CGFloat) -> NSView { - let view = SettingsContainerView(width: width) + public override func settings() -> NSView { + let view = SettingsContainerView() - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabel), state: self.labelState )) - view.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + view.addArrangedSubview(toggleSettingRow( title: localizedString("Monochrome accent"), action: #selector(toggleMonochrome), state: self.monochromeState diff --git a/Kit/extensions.swift b/Kit/extensions.swift index c0391e6b..78aa48c2 100644 --- a/Kit/extensions.swift +++ b/Kit/extensions.swift @@ -224,27 +224,30 @@ public extension NSView { } } - func toggleTitleRow(frame: NSRect, title: String, action: Selector, state: Bool) -> NSView { - let row: NSStackView = NSStackView(frame: frame) - row.orientation = .horizontal - row.spacing = 0 - row.distribution = .fillProportionally + func toggleSettingRow(title: String, action: Selector, state: Bool) -> NSView { + let view: NSStackView = NSStackView() + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + view.orientation = .horizontal + view.alignment = .centerY + view.distribution = .fill + view.spacing = 0 - let title: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), title) - title.font = NSFont.systemFont(ofSize: 13, weight: .light) - title.textColor = .textColor + let titleField: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), title) + titleField.font = NSFont.systemFont(ofSize: 12, weight: .regular) + titleField.textColor = .textColor let state: NSControl.StateValue = state ? .on : .off var toggle: NSControl = NSControl() if #available(OSX 10.15, *) { - let switchButton = NSSwitch(frame: NSRect(x: 0, y: 0, width: 50, height: row.frame.height)) + let switchButton = NSSwitch() switchButton.state = state switchButton.action = action switchButton.target = self toggle = switchButton } else { - let button: NSButton = NSButton(frame: NSRect(x: 0, y: 0, width: 20, height: row.frame.height)) + let button: NSButton = NSButton() button.widthAnchor.constraint(equalToConstant: button.bounds.width).isActive = true button.setButtonType(.switch) button.state = state @@ -258,23 +261,50 @@ public extension NSView { toggle = button } - row.addArrangedSubview(title) - row.addArrangedSubview(toggle) + view.addArrangedSubview(titleField) + view.addArrangedSubview(NSView()) + view.addArrangedSubview(toggle) - row.widthAnchor.constraint(equalToConstant: row.bounds.width).isActive = true - row.heightAnchor.constraint(equalToConstant: row.bounds.height).isActive = true - - return row + return view } - func selectTitleRow(frame: NSRect, title: String, action: Selector, items: [String], selected: String) -> NSView { - let row: NSView = NSView(frame: frame) + func selectSettingsRow(title: String, action: Selector, items: [KeyValue_p], selected: String) -> NSView { + let view = NSStackView() + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + view.orientation = .horizontal + view.alignment = .centerY + view.distribution = .fill + view.spacing = 0 - let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (row.frame.height - 16)/2, width: row.frame.width - 52, height: 17), title) - rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light) - rowTitle.textColor = .textColor + let titleField: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), title) + titleField.font = NSFont.systemFont(ofSize: 12, weight: .regular) + titleField.textColor = .textColor - let select: NSPopUpButton = NSPopUpButton(frame: NSRect(x: row.frame.width - 50, y: (row.frame.height-26)/2, width: 50, height: 26)) + let select: NSPopUpButton = selectView(action: action, items: items, selected: selected) + select.sizeToFit() + + view.addArrangedSubview(titleField) + view.addArrangedSubview(NSView()) + view.addArrangedSubview(select) + + return view + } + + func selectSettingsRowV1(title: String, action: Selector, items: [String], selected: String) -> NSView { + let view = NSStackView() + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + view.orientation = .horizontal + view.alignment = .centerY + view.distribution = .fill + view.spacing = 0 + + let titleField: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), title) + titleField.font = NSFont.systemFont(ofSize: 12, weight: .regular) + titleField.textColor = .textColor + + let select: NSPopUpButton = NSPopUpButton() select.target = self select.action = action @@ -294,38 +324,11 @@ public extension NSView { select.menu = menu select.sizeToFit() - rowTitle.setFrameSize(NSSize(width: row.frame.width - select.frame.width, height: rowTitle.frame.height)) - select.setFrameOrigin(NSPoint(x: row.frame.width - select.frame.width, y: select.frame.origin.y)) + view.addArrangedSubview(titleField) + view.addArrangedSubview(NSView()) + view.addArrangedSubview(select) - row.addSubview(select) - row.addSubview(rowTitle) - - row.widthAnchor.constraint(equalToConstant: row.bounds.width).isActive = true - row.heightAnchor.constraint(equalToConstant: row.bounds.height).isActive = true - - return row - } - - func selectRow(frame: NSRect, title: String, action: Selector, items: [KeyValue_p], selected: String) -> NSView { - let row: NSView = NSView(frame: frame) - - let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (row.frame.height - 16)/2, width: row.frame.width - 52, height: 17), title) - rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light) - rowTitle.textColor = .textColor - - let select: NSPopUpButton = selectView(action: action, items: items, selected: selected) - select.sizeToFit() - - rowTitle.setFrameSize(NSSize(width: row.frame.width - select.frame.width, height: rowTitle.frame.height)) - select.setFrameOrigin(NSPoint(x: row.frame.width - select.frame.width, y: select.frame.origin.y)) - - row.addSubview(select) - row.addSubview(rowTitle) - - row.widthAnchor.constraint(equalToConstant: row.bounds.width).isActive = true - row.heightAnchor.constraint(equalToConstant: row.bounds.height).isActive = true - - return row + return view } func selectView(action: Selector, items: [KeyValue_p], selected: String) -> NSPopUpButton { @@ -473,10 +476,15 @@ public final class ScrollableStackView: NSView { scrollView.documentView = stackView NSLayoutConstraint.activate([ + clipView.leftAnchor.constraint(equalTo: scrollView.leftAnchor), + clipView.rightAnchor.constraint(equalTo: scrollView.rightAnchor), + stackView.leftAnchor.constraint(equalTo: clipView.leftAnchor), stackView.rightAnchor.constraint(equalTo: clipView.rightAnchor), stackView.topAnchor.constraint(equalTo: clipView.topAnchor) ]) + + clipView.translatesAutoresizingMaskIntoConstraints = false } required public init?(coder: NSCoder) { diff --git a/Kit/helpers.swift b/Kit/helpers.swift index b6faf59f..3fd744c9 100644 --- a/Kit/helpers.swift +++ b/Kit/helpers.swift @@ -814,14 +814,10 @@ public func process(path: String, arguments: [String]) -> String? { } public class SettingsContainerView: NSStackView { - public init(width: CGFloat) { - super.init(frame: NSRect( - x: Constants.Settings.margin, - y: 0, - width: width - (Constants.Settings.margin*2), - height: 0 - )) + public init() { + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) + self.translatesAutoresizingMaskIntoConstraints = false self.orientation = .vertical self.distribution = .gravityAreas self.edgeInsets = NSEdgeInsets( @@ -836,18 +832,6 @@ public class SettingsContainerView: NSStackView { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - - private func resize() { - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.bounds.width, height: h)) - } - } - - public override func addArrangedSubview(_ view: NSView) { - super.addArrangedSubview(view) - self.resize() - } } public class SMCHelper { diff --git a/Kit/module/settings.swift b/Kit/module/settings.swift index 0152e4b0..99f4dc6e 100644 --- a/Kit/module/settings.swift +++ b/Kit/module/settings.swift @@ -20,25 +20,24 @@ public protocol Settings_v: NSView { func load(widgets: [widget_t]) } -open class Settings: NSView, Settings_p { +open class Settings: NSStackView, Settings_p { public var toggleCallback: () -> Void = {} - private let headerHeight: CGFloat = 42 - private var config: UnsafePointer private var widgets: UnsafeMutablePointer<[Widget]> - - private var activeWidget: Widget? { - get { - return self.widgets.pointee.first{ $0.isActive } - } - } - private var moduleSettings: Settings_v? - private var enableControl: NSControl? - private var container: ScrollableStackView? - private var widgetSettings: widget_t? - private var moduleSettingsContainer: NSView? + + private var moduleSettingsContainer: NSStackView? + private var widgetSettingsContainer: NSStackView? + + private let headerSeparator: NSView = { + let view: NSView = NSView() + view.heightAnchor.constraint(equalToConstant: 1).isActive = true + view.wantsLayer = true + view.layer?.backgroundColor = NSColor(hexString: "#d1d1d1").cgColor + + return view + }() init(config: UnsafePointer, widgets: UnsafeMutablePointer<[Widget]>, enabled: Bool, moduleSettings: Settings_v?) { self.config = config @@ -51,10 +50,16 @@ open class Settings: NSView, Settings_p { self.appearance = NSAppearance(named: .aqua) self.layer?.backgroundColor = NSColor(hexString: "#ececec").cgColor - NotificationCenter.default.addObserver(self, selector: #selector(externalModuleToggle), name: .toggleModule, object: nil) + self.orientation = .vertical + self.alignment = .width + self.distribution = .fill + self.spacing = 0 - self.addSubview(self.header(state: enabled)) - self.addSubview(self.body()) + self.addArrangedSubview(self.header(enabled)) + self.addArrangedSubview(self.headerSeparator) + self.addArrangedSubview(self.body()) + + self.addArrangedSubview(NSView()) } deinit { @@ -65,13 +70,24 @@ open class Settings: NSView, Settings_p { fatalError("init(coder:) has not been implemented") } - // MARK: - Views + // MARK: - parts - private func header(state: Bool) -> NSView { - let view: NSView = NSView(frame: NSRect(x: 0, y: self.frame.height - self.headerHeight, width: self.frame.width, height: self.headerHeight)) - view.wantsLayer = true + private func header(_ enabled: Bool) -> NSStackView { + let view: NSStackView = NSStackView() - let titleView = NSTextField(frame: NSRect(x: Constants.Settings.margin, y: (view.frame.height-20)/2, width: self.frame.width - 65, height: 20)) + view.orientation = .horizontal + view.distribution = .fillEqually + view.alignment = .centerY + view.distribution = .fillProportionally + view.spacing = 0 + view.edgeInsets = NSEdgeInsets( + top: Constants.Settings.margin, + left: Constants.Settings.margin, + bottom: Constants.Settings.margin, + right: Constants.Settings.margin + ) + + let titleView = NSTextField() titleView.isEditable = false titleView.isSelectable = false titleView.isBezeled = false @@ -83,41 +99,39 @@ open class Settings: NSView, Settings_p { titleView.font = NSFont.systemFont(ofSize: 18, weight: .light) titleView.stringValue = localizedString(self.config.pointee.name) - var toggle: NSControl = NSControl() + var toggleBtn: NSControl = NSControl() if #available(OSX 10.15, *) { - let switchButton = NSSwitch(frame: NSRect(x: self.frame.width-55, y: 0, width: 50, height: view.frame.height)) - switchButton.state = state ? .on : .off + let switchButton = NSSwitch() + switchButton.state = enabled ? .on : .off switchButton.action = #selector(self.toggleEnable) switchButton.target = self - toggle = switchButton + toggleBtn = switchButton } else { - let button: NSButton = NSButton(frame: NSRect(x: self.frame.width-30, y: 0, width: 15, height: view.frame.height)) + let button: NSButton = NSButton() button.setButtonType(.switch) - button.state = state ? .on : .off + button.state = enabled ? .on : .off button.title = "" button.action = #selector(self.toggleEnable) button.isBordered = false button.isTransparent = true button.target = self - toggle = button + toggleBtn = button } - let line: NSView = NSView(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: 1)) - line.wantsLayer = true - line.layer?.backgroundColor = NSColor(hexString: "#d1d1d1").cgColor - - view.addSubview(titleView) - view.addSubview(toggle) - view.addSubview(line) - self.enableControl = toggle + view.addArrangedSubview(titleView) + view.addArrangedSubview(NSView()) + view.addArrangedSubview(toggleBtn) return view } - private func body() -> NSView { - let view = NSStackView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: Constants.Settings.height - self.headerHeight)) + private func body() -> NSStackView { + let view: NSStackView = NSStackView() + + view.translatesAutoresizingMaskIntoConstraints = false + view.orientation = .vertical view.edgeInsets = NSEdgeInsets( top: Constants.Settings.margin, left: Constants.Settings.margin, @@ -125,25 +139,19 @@ open class Settings: NSView, Settings_p { right: Constants.Settings.margin ) view.spacing = Constants.Settings.margin - view.orientation = .vertical - view.wantsLayer = true - view.layer?.backgroundColor = NSColor(hexString: "#ececec").cgColor - view.addArrangedSubview(self.initWidgetSelector()) - view.addArrangedSubview(self.initModuleSettings()) + view.addArrangedSubview(self.widgetSelector()) + view.addArrangedSubview(self.settings()) return view } - private func initWidgetSelector() -> NSView { - let view = NSStackView(frame: NSRect( - x: 0, - y: 0, - width: self.frame.width - (Constants.Settings.margin*2), - height: Constants.Widget.height + (Constants.Settings.margin*2) - )) - view.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true - view.heightAnchor.constraint(equalToConstant: view.bounds.height).isActive = true + // MARK: - views + + private func widgetSelector() -> NSView { + let view = NSStackView() + view.heightAnchor.constraint(equalToConstant: Constants.Widget.height + (Constants.Settings.margin*2)).isActive = true + view.translatesAutoresizingMaskIntoConstraints = false view.wantsLayer = true view.layer?.backgroundColor = .white view.layer?.cornerRadius = 3 @@ -157,256 +165,156 @@ open class Settings: NSView, Settings_p { for i in 0...self.widgets.pointee.count - 1 { let preview = WidgetPreview(&self.widgets.pointee[i]) - preview.settingsCallback = { [weak self] value in - self?.toggleSettings(value) - } preview.stateCallback = { [weak self] in - self?.widgetStateCallback() + self?.loadModuleSettings() + self?.loadWidgetSettings() } view.addArrangedSubview(preview) } + view.addArrangedSubview(NSView()) return view } - private func initModuleSettings() -> NSView { - let view: ScrollableStackView = ScrollableStackView(frame: NSRect( - x: 0, - y: 0, - width: self.frame.width - (Constants.Settings.margin*2), - height: Constants.Settings.height - self.headerHeight - Constants.Widget.height - (Constants.Settings.margin*5) - )) - view.widthAnchor.constraint(equalToConstant: view.bounds.width).isActive = true - view.heightAnchor.constraint(equalToConstant: view.bounds.height).isActive = true - view.stackView.spacing = Constants.Settings.margin - self.container = view + private func settings() -> NSView { + let view: NSTabView = NSTabView() + view.widthAnchor.constraint(equalToConstant: Constants.Settings.width - Constants.Settings.margin*2).isActive = true + view.heightAnchor.constraint(equalToConstant: Constants.Settings.height - 40 - Constants.Widget.height - (Constants.Settings.margin*5)).isActive = true + view.tabViewType = .topTabsBezelBorder + view.tabViewBorderType = .line - guard let settingsView = self.moduleSettings else { + let moduleTab: NSTabViewItem = NSTabViewItem() + moduleTab.label = localizedString("Module settings") + moduleTab.view = { + let view = ScrollableStackView() + self.moduleSettingsContainer = view.stackView + self.loadModuleSettings() return view - } + }() - let container: NSView = NSView(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) - container.wantsLayer = true - container.layer?.backgroundColor = .white - container.layer?.cornerRadius = 3 - self.moduleSettingsContainer = container + let widgetTab: NSTabViewItem = NSTabViewItem() + widgetTab.label = localizedString("Widget settings") + widgetTab.view = { + let view = ScrollableStackView() + self.widgetSettingsContainer = view.stackView + self.loadWidgetSettings() + return view + }() - self.moduleSettings?.load(widgets: self.widgets.pointee.filter{ $0.isActive }.map{ $0.type }) - - container.addSubview(settingsView) - view.stackView.addArrangedSubview(container) - - NSLayoutConstraint.activate([ - container.heightAnchor.constraint(equalTo: settingsView.heightAnchor) - ]) + view.addTabViewItem(moduleTab) + view.addTabViewItem(widgetTab) return view } // MARK: - helpers - private func toggleSettings(_ type: widget_t) { - guard let widget = self.widgets.pointee.first(where: { $0.type == type }) else { - return - } - - let container: NSView = NSView() - container.wantsLayer = true - container.layer?.backgroundColor = .white - container.layer?.cornerRadius = 3 - - let width: CGFloat = self.container?.clipView.bounds.width ?? self.frame.width - let settingsView = widget.item.settings(width: width) - container.addSubview(settingsView) - - if let view = self.container { - if self.widgetSettings == nil { - view.stackView.insertArrangedSubview(container, at: 0) - self.widgetSettings = type - } else if self.widgetSettings != nil && self.widgetSettings == type { - view.stackView.arrangedSubviews[0].removeFromSuperview() - self.widgetSettings = nil - } else { - view.stackView.arrangedSubviews[0].removeFromSuperview() - self.widgetSettings = type - view.stackView.insertArrangedSubview(container, at: 0) - } - } - - NSLayoutConstraint.activate([ - container.heightAnchor.constraint(equalTo: settingsView.heightAnchor) - ]) - } - @objc private func toggleEnable(_ sender: Any) { self.toggleCallback() } - @objc private func externalModuleToggle(_ notification: Notification) { - if let name = notification.userInfo?["module"] as? String { - if name == self.config.pointee.name { - if let state = notification.userInfo?["state"] as? Bool { - toggleNSControlState(self.enableControl, state: state ? .on : .off) - } - } + @objc private func loadModuleSettings() { + self.moduleSettingsContainer?.subviews.forEach{ $0.removeFromSuperview() } + + if let settingsView = self.moduleSettings { + settingsView.load(widgets: self.widgets.pointee.filter{ $0.isActive }.map{ $0.type }) + self.moduleSettingsContainer?.addArrangedSubview(settingsView) + } else { + self.moduleSettingsContainer?.addArrangedSubview(NSView()) } } - @objc private func widgetStateCallback() { - guard let container = self.moduleSettingsContainer, let settingsView = self.moduleSettings else { + @objc private func loadWidgetSettings() { + self.widgetSettingsContainer?.subviews.forEach{ $0.removeFromSuperview() } + let list = self.widgets.pointee.filter({ $0.isActive && $0.type != .label }) + + guard !list.isEmpty else { return } - container.subviews.forEach{ $0.removeFromSuperview() } - settingsView.load(widgets: self.widgets.pointee.filter{ $0.isActive }.map{ $0.type }) - self.moduleSettingsContainer?.addSubview(settingsView) - - NSLayoutConstraint.activate([ - container.heightAnchor.constraint(equalTo: settingsView.heightAnchor) - ]) + for i in 0...list.count - 1 { + let container = NSStackView() + container.orientation = .vertical + container.edgeInsets = NSEdgeInsets( + top: 0, + left: Constants.Settings.margin, + bottom: 0, + right: Constants.Settings.margin + ) + container.spacing = 0 + + let header = NSStackView() + header.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + header.orientation = .horizontal + header.spacing = 0 + + let image = NSImageView(frame: NSRect(origin: .zero, size: list[i].image.size)) + image.image = list[i].image + + let title: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), list[i].type.name()) + title.font = NSFont.systemFont(ofSize: 13, weight: .regular) + title.textColor = .textColor + + header.addArrangedSubview(image) + header.addArrangedSubview(title) + header.addArrangedSubview(NSView()) + + container.addArrangedSubview(header) + container.addArrangedSubview(list[i].item.settings()) + + self.widgetSettingsContainer?.addArrangedSubview(container) + } } } internal class WidgetPreview: NSStackView { - public var settingsCallback: (widget_t) -> Void = {_ in } public var stateCallback: () -> Void = {} private var widget: UnsafeMutablePointer - private var size: CGFloat { - get { - if self.widget.pointee.type == .label { - return Constants.Widget.spacing*2 - } - return self.widget.pointee.isActive ? Constants.Widget.height + (Constants.Widget.spacing*3) + 1 : Constants.Widget.spacing*2 - } - } - private var widthConstant: NSLayoutConstraint? - - private let separator: NSView = initSeparator() - private var button: NSView? = nil public init(_ widget: UnsafeMutablePointer) { self.widget = widget - super.init(frame: NSRect( - x: 0, - y: 0, - width: 0, - height: Constants.Widget.height - )) - - self.button = self.initButton() + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: Constants.Widget.height)) self.wantsLayer = true self.layer?.cornerRadius = 2 - self.layer?.borderColor = self.widget.pointee.isActive ? NSColor.systemBlue.cgColor : NSColor(hexString: "#dddddd").cgColor + self.layer?.borderColor = widget.pointee.isActive ? NSColor.systemBlue.cgColor : NSColor(hexString: "#dddddd").cgColor self.layer?.borderWidth = 1 self.toolTip = localizedString("Select widget", widget.pointee.type.name()) - self.orientation = .horizontal - self.distribution = .fillProportionally + self.orientation = .vertical + self.distribution = .fill + self.alignment = .centerY self.spacing = 0 - self.edgeInsets = NSEdgeInsets( - top: 0, - left: Constants.Widget.spacing, - bottom: 0, - right: Constants.Widget.spacing - ) - let container: NSView = NSView(frame: NSRect( - x: Constants.Widget.spacing, - y: 0, - width: widget.pointee.preview.frame.width, - height: self.frame.height - )) - container.wantsLayer = true - container.addSubview(widget.pointee.preview) + let image = NSImageView(frame: NSRect(origin: .zero, size: widget.pointee.image.size)) + image.image = widget.pointee.image - self.addArrangedSubview(container) - if self.widget.pointee.isActive && self.widget.pointee.type != .label { - self.addArrangedSubview(self.separator) - if let button = self.button { - self.addArrangedSubview(button) - } - } + self.addArrangedSubview(image) - widget.pointee.preview.widthHandler = { [weak self] value in - self?.trackingAreas.forEach({ (area: NSTrackingArea) in - self?.removeTrackingArea(area) - }) - - let rect = NSRect(x: Constants.Widget.spacing, y: 0, width: value, height: self!.frame.height) - let trackingArea = NSTrackingArea( - rect: rect, - options: [NSTrackingArea.Options.activeAlways, NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeInActiveApp], - owner: self, - userInfo: nil - ) - self?.addTrackingArea(trackingArea) - } - - let rect = NSRect(x: Constants.Widget.spacing, y: 0, width: container.frame.width, height: self.frame.height) self.addTrackingArea(NSTrackingArea( - rect: rect, + rect: NSRect( + x: Constants.Widget.spacing, + y: 0, + width: image.frame.width + Constants.Widget.spacing*2, + height: self.frame.height + ), options: [NSTrackingArea.Options.activeAlways, NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeInActiveApp], owner: self, userInfo: nil )) NSLayoutConstraint.activate([ + self.widthAnchor.constraint(equalToConstant: image.frame.width + Constants.Widget.spacing*2), self.heightAnchor.constraint(equalToConstant: self.frame.height) ]) - - self.widthConstant = self.widthAnchor.constraint(equalTo: self.widget.pointee.preview.widthAnchor, constant: self.size) - self.widthConstant?.isActive = true - } - - private func initButton() -> NSView { - let size: CGFloat = Constants.Widget.height - let button = NSButton(frame: NSRect(x: 0, y: 0, width: size, height: size)) - button.title = localizedString("Open widget settings") - button.toolTip = localizedString("Open widget settings") - button.bezelStyle = .regularSquare - if let image = Bundle(for: type(of: self)).image(forResource: "widget_settings") { - button.image = image - } - button.imageScaling = .scaleProportionallyDown - if #available(OSX 10.14, *) { - button.contentTintColor = .lightGray - } - button.isBordered = false - button.action = #selector(self.toggleSettings) - button.target = self - button.focusRingType = .none - - NSLayoutConstraint.activate([ - button.widthAnchor.constraint(equalToConstant: button.frame.width) - ]) - - return button - } - - private static func initSeparator() -> NSView { - let separator = NSView() - separator.widthAnchor.constraint(equalToConstant: 1).isActive = true - separator.wantsLayer = true - separator.layer?.backgroundColor = NSColor(hexString: "#dddddd").cgColor - - NSLayoutConstraint.activate([ - separator.heightAnchor.constraint(equalToConstant: Constants.Widget.height) - ]) - - return separator } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - @objc private func toggleSettings() { - self.settingsCallback(self.widget.pointee.type) - } - override func mouseEntered(with: NSEvent) { self.layer?.borderColor = NSColor.systemBlue.cgColor NSCursor.pointingHand.set() @@ -420,21 +328,5 @@ internal class WidgetPreview: NSStackView { override func mouseDown(with: NSEvent) { self.widget.pointee.toggle() self.stateCallback() - - if self.widget.pointee.type != .label { - if self.widget.pointee.isActive { - self.addArrangedSubview(self.separator) - if let button = self.button { - self.addArrangedSubview(button) - } - } else { - self.removeView(self.separator) - if let button = self.button { - self.removeView(button) - } - } - } - - self.widthConstant?.constant = self.size } } diff --git a/Kit/module/widget.swift b/Kit/module/widget.swift index 45d6f75e..4976d333 100644 --- a/Kit/module/widget.swift +++ b/Kit/module/widget.swift @@ -26,8 +26,10 @@ public enum widget_t: String { case tachometer = "tachometer" public func new(module: String, config: NSDictionary, defaultWidget: widget_t) -> Widget? { + var image: NSImage? = nil var preview: widget_p? = nil var item: widget_p? = nil + guard let widgetConfig: NSDictionary = config[self.rawValue] as? NSDictionary else { return nil } @@ -69,8 +71,41 @@ public enum widget_t: String { default: break } - if let preview = preview, let item = item { - return Widget(self, defaultWidget: defaultWidget, module: module, preview: preview, item: item) + if let view = preview { + var width: CGFloat = view.bounds.width + + switch preview { + case is BarChart: + if module == "GPU" || module == "RAM" || module == "Disk" { + width = 15 + } else if module == "Fans" { + width = 26 + } else if module == "CPU" { + width = 34 + } + case is SensorsWidget: + if module == "Sensors" { + width = 25 + } + default: width = view.bounds.width + } + + let r = NSRect( + x: -view.frame.origin.x/2, + y: 0, + width: width - view.frame.origin.x, + height: view.bounds.height + ) + + if let rep = view.bitmapImageRepForCachingDisplay(in: r) { + view.cacheDisplay(in: r, to: rep) + image = NSImage(size: r.size) + image?.addRepresentation(rep) + } + } + + if let item = item, let image = image { + return Widget(self, defaultWidget: defaultWidget, module: module, item: item, image: image) } return nil @@ -102,7 +137,7 @@ public protocol widget_p: NSView { var widthHandler: ((CGFloat) -> Void)? { get set } func setValues(_ values: [value_t]) - func settings(width: CGFloat) -> NSView + func settings() -> NSView } open class WidgetWrapper: NSView, widget_p { @@ -136,7 +171,7 @@ open class WidgetWrapper: NSView, widget_p { // MARK: - stubs - open func settings(width: CGFloat) -> NSView { return NSView() } + open func settings() -> NSView { return NSView() } open func setValues(_ values: [value_t]) {} } @@ -144,7 +179,7 @@ public class Widget { public let type: widget_t public let defaultWidget: widget_t public let module: String - public let preview: widget_p + public let image: NSImage public let item: widget_p public var isActive: Bool { @@ -176,12 +211,12 @@ public class Widget { } } - public init(_ type: widget_t, defaultWidget: widget_t, module: String, preview: widget_p, item: widget_p) { + public init(_ type: widget_t, defaultWidget: widget_t, module: String, item: widget_p, image: NSImage) { self.type = type self.module = module - self.preview = preview self.item = item self.defaultWidget = defaultWidget + self.image = image self.item.widthHandler = { [weak self] value in if let s = self, let item = s.menuBarItem, item.length != value { diff --git a/Modules/Battery/settings.swift b/Modules/Battery/settings.swift index 6480b7ed..cdc5e518 100644 --- a/Modules/Battery/settings.swift +++ b/Modules/Battery/settings.swift @@ -63,12 +63,7 @@ internal class Settings: NSStackView, Settings_v { self.numberOfProcesses = Store.shared.int(key: "\(self.title)_processes", defaultValue: self.numberOfProcesses) self.timeFormat = Store.shared.string(key: "\(self.title)_timeFormat", defaultValue: self.timeFormat) - super.init(frame: NSRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.orientation = .vertical self.distribution = .gravityAreas @@ -88,26 +83,21 @@ internal class Settings: NSStackView, Settings_v { public func load(widgets: [widget_t]) { self.subviews.forEach{ $0.removeFromSuperview() } - let width: CGFloat = self.frame.width - (Constants.Settings.margin*2) - - self.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRow( title: localizedString("Low level notification"), action: #selector(changeUpdateIntervalLow), items: self.lowLevelsList, selected: self.lowLevelNotification == "Disabled" ? self.lowLevelNotification : "\(Int((Double(self.lowLevelNotification) ?? 0)*100))%" )) - self.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRow( title: localizedString("High level notification"), action: #selector(changeUpdateIntervalHigh), items: self.highLevelsList, selected: self.highLevelNotification == "Disabled" ? self.highLevelNotification : "\(Int((Double(self.highLevelNotification) ?? 0)*100))%" )) - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Number of top processes"), action: #selector(changeNumberOfProcesses), items: NumbersOfProcesses.map{ "\($0)" }, @@ -115,19 +105,13 @@ internal class Settings: NSStackView, Settings_v { )) if !widgets.filter({ $0 == .battery }).isEmpty { - self.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRow( title: localizedString("Time format"), action: #selector(toggleTimeFormat), items: ShortLong, selected: self.timeFormat )) } - - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.bounds.width, height: h)) - } } @objc private func changeUpdateIntervalLow(_ sender: NSMenuItem) { diff --git a/Modules/Bluetooth/settings.swift b/Modules/Bluetooth/settings.swift index 9abab7a5..d1c8c2a3 100644 --- a/Modules/Bluetooth/settings.swift +++ b/Modules/Bluetooth/settings.swift @@ -18,12 +18,7 @@ internal class Settings: NSStackView, Settings_v { private var list: [String: Bool] = [:] public init() { - super.init(frame: NSRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 20 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.orientation = .vertical self.distribution = .gravityAreas @@ -34,6 +29,8 @@ internal class Settings: NSStackView, Settings_v { right: Constants.Settings.margin ) self.spacing = Constants.Settings.margin + + self.addArrangedSubview(NSView()) } required init?(coder: NSCoder) { @@ -50,8 +47,7 @@ internal class Settings: NSStackView, Settings_v { list.forEach { (d: BLEDevice) in if self.list[d.id] == nil { - let row: NSView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: self.frame.width - (Constants.Settings.margin*2), height: Constants.Settings.row), + let row: NSView = toggleSettingRow( title: d.name, action: #selector(self.handleSelection), state: d.state @@ -63,11 +59,6 @@ internal class Settings: NSStackView, Settings_v { self.addArrangedSubview(row) } } - - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.bounds.width, height: h)) - } } @objc private func handleSelection(_ sender: NSControl) { diff --git a/Modules/CPU/settings.swift b/Modules/CPU/settings.swift index c9760e28..79610189 100644 --- a/Modules/CPU/settings.swift +++ b/Modules/CPU/settings.swift @@ -47,15 +47,11 @@ internal class Settings: NSStackView, Settings_v { } self.hasHyperthreadingCores = sysctlByName("hw.physicalcpu") != sysctlByName("hw.logicalcpu") - super.init(frame: NSRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.orientation = .vertical self.distribution = .gravityAreas + self.translatesAutoresizingMaskIntoConstraints = false self.edgeInsets = NSEdgeInsets( top: Constants.Settings.margin, left: Constants.Settings.margin, @@ -73,24 +69,20 @@ internal class Settings: NSStackView, Settings_v { self.subviews.forEach{ $0.removeFromSuperview() } var hasIPG = false - let width: CGFloat = self.frame.width - (Constants.Settings.margin*2) - #if arch(x86_64) let path: CFString = "/Library/Frameworks/IntelPowerGadget.framework" as CFString let bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, CFURLPathStyle.cfurlposixPathStyle, true) hasIPG = CFBundleCreate(kCFAllocatorDefault, bundleURL) != nil #endif - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval"), action: #selector(changeUpdateInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, selected: "\(self.updateIntervalValue) sec" )) - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval for top processes"), action: #selector(changeUpdateTopInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, @@ -98,16 +90,14 @@ internal class Settings: NSStackView, Settings_v { )) if !widgets.filter({ $0 == .barChart }).isEmpty { - self.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(toggleSettingRow( title: localizedString("Show usage per core"), action: #selector(toggleUsagePerCore), state: self.usagePerCoreState )) if self.hasHyperthreadingCores { - self.hyperthreadView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: self.frame.width - (Constants.Settings.margin*2), height: Constants.Settings.row), + self.hyperthreadView = toggleSettingRow( title: localizedString("Show hyper-threading cores"), action: #selector(toggleMultithreading), state: self.hyperthreadState @@ -119,8 +109,7 @@ internal class Settings: NSStackView, Settings_v { self.addArrangedSubview(self.hyperthreadView!) } - self.splitValueView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.splitValueView = toggleSettingRow( title: localizedString("Split the value (System/User)"), action: #selector(toggleSplitValue), state: self.splitValueState @@ -133,26 +122,19 @@ internal class Settings: NSStackView, Settings_v { } if hasIPG { - self.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(toggleSettingRow( title: "\(localizedString("CPU frequency")) (IPG)", action: #selector(toggleIPG), state: self.IPGState )) } - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Number of top processes"), action: #selector(changeNumberOfProcesses), items: NumbersOfProcesses.map{ "\($0)" }, selected: "\(self.numberOfProcesses)" )) - - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.bounds.width, height: h)) - } } @objc private func changeUpdateInterval(_ sender: NSMenuItem) { diff --git a/Modules/Disk/config.plist b/Modules/Disk/config.plist index f5f02c92..e47563d9 100644 --- a/Modules/Disk/config.plist +++ b/Modules/Disk/config.plist @@ -82,7 +82,7 @@ Default Icon - characters + chars Symbols W diff --git a/Modules/Disk/settings.swift b/Modules/Disk/settings.swift index 7b84699a..9ee2db64 100644 --- a/Modules/Disk/settings.swift +++ b/Modules/Disk/settings.swift @@ -12,7 +12,7 @@ import Cocoa import Kit -internal class Settings: NSView, Settings_v { +internal class Settings: NSStackView, Settings_v { private var removableState: Bool = false private var updateIntervalValue: Int = 10 @@ -31,15 +31,18 @@ internal class Settings: NSView, Settings_v { self.removableState = Store.shared.bool(key: "\(self.title)_removable", defaultValue: self.removableState) self.updateIntervalValue = Store.shared.int(key: "\(self.title)_updateInterval", defaultValue: self.updateIntervalValue) - super.init(frame: CGRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.wantsLayer = true - self.canDrawConcurrently = true + self.orientation = .vertical + self.distribution = .gravityAreas + self.edgeInsets = NSEdgeInsets( + top: Constants.Settings.margin, + left: Constants.Settings.margin, + bottom: Constants.Settings.margin, + right: Constants.Settings.margin + ) + self.spacing = Constants.Settings.margin } required init?(coder: NSCoder) { @@ -49,60 +52,45 @@ internal class Settings: NSView, Settings_v { public func load(widgets: [widget_t]) { self.subviews.forEach{ $0.removeFromSuperview() } - let rowHeight: CGFloat = 30 - let num: CGFloat = 3 - - self.intervalSelectView = selectTitleRow( - frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 2, - width: self.frame.width - (Constants.Settings.margin*2), - height: rowHeight - ), + self.intervalSelectView = selectSettingsRowV1( title: localizedString("Update interval"), action: #selector(changeUpdateInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, selected: "\(self.updateIntervalValue) sec" ) - self.addSubview(self.intervalSelectView!) + self.addArrangedSubview(self.intervalSelectView!) self.addDiskSelector() - self.addSubview(toggleTitleRow( - frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0, - width: self.frame.width - (Constants.Settings.margin*2), - height: rowHeight - ), + self.addArrangedSubview(toggleSettingRow( title: localizedString("Show removable disks"), action: #selector(toggleRemovable), state: self.removableState )) - - self.setFrameSize(NSSize(width: self.frame.width, height: rowHeight*num + (Constants.Settings.margin*(num+1)))) } private func addDiskSelector() { - let view: NSView = NSView(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin*2 + 30, - width: self.frame.width - Constants.Settings.margin*2, - height: 30 - )) + let view: NSStackView = NSStackView() + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + view.orientation = .horizontal + view.alignment = .centerY + view.distribution = .fill + view.spacing = 0 - let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (view.frame.height - 16)/2, width: view.frame.width - 52, height: 17), localizedString("Disk to show")) + let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 17), localizedString("Disk to show")) rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light) rowTitle.textColor = .textColor - self.button = NSPopUpButton(frame: NSRect(x: view.frame.width - 140, y: -1, width: 140, height: 30)) + self.button = NSPopUpButton(frame: NSRect(x: 0, y: 0, width: 0, height: 30)) self.button!.target = self self.button?.action = #selector(self.handleSelection) - view.addSubview(rowTitle) - view.addSubview(self.button!) + view.addArrangedSubview(rowTitle) + view.addArrangedSubview(NSView()) + view.addArrangedSubview(self.button!) - self.addSubview(view) + self.addArrangedSubview(view) } internal func setList(_ list: Disks) { diff --git a/Modules/Fans/main.swift b/Modules/Fans/main.swift index 68b5d7b5..2adfa15f 100644 --- a/Modules/Fans/main.swift +++ b/Modules/Fans/main.swift @@ -28,7 +28,7 @@ public struct Fan { var formattedValue: String { get { - return "\(Int(value)) RPM" + return "\(Int(value))" } } } diff --git a/Modules/Fans/settings.swift b/Modules/Fans/settings.swift index 7399b602..472499cb 100644 --- a/Modules/Fans/settings.swift +++ b/Modules/Fans/settings.swift @@ -28,12 +28,7 @@ internal class Settings: NSStackView, Settings_v { self.title = title self.list = list - super.init(frame: CGRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.wantsLayer = true self.orientation = .vertical @@ -58,50 +53,50 @@ internal class Settings: NSStackView, Settings_v { public func load(widgets: [widget_t]) { self.subviews.forEach{ $0.removeFromSuperview() } - let width: CGFloat = self.frame.width - (Constants.Settings.margin*2) - - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: Constants.Settings.margin, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval"), action: #selector(changeUpdateInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, selected: "\(self.updateIntervalValue) sec" )) - self.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: Constants.Settings.margin, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(toggleSettingRow( title: localizedString("Label"), action: #selector(toggleLabelState), state: self.labelState )) - self.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: Constants.Settings.margin, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(toggleSettingRow( title: localizedString("Save the fan speed"), action: #selector(toggleSpeedState), state: self.speedState )) - let view: NSStackView = NSStackView(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin, - width: self.frame.width - (Constants.Settings.margin*2), - height: 0 - )) - view.orientation = .vertical - view.distribution = .gravityAreas - view.spacing = Constants.Settings.margin + let header = NSStackView() + header.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + header.spacing = 0 - let title: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: view.frame.width, height: 19), localizedString("Fans")) - title.font = NSFont.systemFont(ofSize: 14, weight: .regular) - title.textColor = .secondaryLabelColor - title.alignment = .center - title.heightAnchor.constraint(equalToConstant: title.bounds.height).isActive = true - view.addArrangedSubview(title) + let titleField: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), localizedString("Fans")) + titleField.font = NSFont.systemFont(ofSize: 13, weight: .medium) + titleField.textColor = .labelColor + + header.addArrangedSubview(titleField) + header.addArrangedSubview(NSView()) + + self.addArrangedSubview(header) + + let container = NSStackView() + container.orientation = .vertical + container.edgeInsets = NSEdgeInsets( + top: 0, + left: Constants.Settings.margin, + bottom: 0, + right: Constants.Settings.margin + ) + container.spacing = 0 self.list.pointee.forEach { (f: Fan) in - let row: NSView = toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: view.frame.width, height: Constants.Settings.row), + let row: NSView = toggleSettingRow( title: f.name, action: #selector(self.handleSelection), state: f.state @@ -109,22 +104,10 @@ internal class Settings: NSStackView, Settings_v { row.subviews.filter{ $0 is NSControl }.forEach { (control: NSView) in control.identifier = NSUserInterfaceItemIdentifier(rawValue: "\(f.id)") } - view.addArrangedSubview(row) + container.addArrangedSubview(row) } - let listHeight = view.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing - view.setFrameSize(NSSize(width: view.frame.width, height: listHeight)) - NSLayoutConstraint.activate([ - view.heightAnchor.constraint(equalToConstant: listHeight), - view.widthAnchor.constraint(equalToConstant: view.bounds.width) - ]) - - self.addArrangedSubview(view) - - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.frame.width, height: h)) - } + self.addArrangedSubview(container) } @objc private func handleSelection(_ sender: NSControl) { diff --git a/Modules/GPU/config.plist b/Modules/GPU/config.plist index b74060ed..d2d0e32e 100644 --- a/Modules/GPU/config.plist +++ b/Modules/GPU/config.plist @@ -51,7 +51,7 @@ Preview Value - 0.36,0.28,0.32,0.26 + 0.58 Color diff --git a/Modules/GPU/settings.swift b/Modules/GPU/settings.swift index 0c80d98c..b7335a7d 100644 --- a/Modules/GPU/settings.swift +++ b/Modules/GPU/settings.swift @@ -12,7 +12,7 @@ import Cocoa import Kit -internal class Settings: NSView, Settings_v { +internal class Settings: NSStackView, Settings_v { private var updateIntervalValue: Int = 1 private var selectedGPU: String private var showTypeValue: Bool = false @@ -32,15 +32,18 @@ internal class Settings: NSView, Settings_v { self.updateIntervalValue = Store.shared.int(key: "\(self.title)_updateInterval", defaultValue: self.updateIntervalValue) self.showTypeValue = Store.shared.bool(key: "\(self.title)_showType", defaultValue: self.showTypeValue) - super.init(frame: CGRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.wantsLayer = true - self.canDrawConcurrently = true + self.orientation = .vertical + self.distribution = .gravityAreas + self.edgeInsets = NSEdgeInsets( + top: Constants.Settings.margin, + left: Constants.Settings.margin, + bottom: Constants.Settings.margin, + right: Constants.Settings.margin + ) + self.spacing = Constants.Settings.margin } required init?(coder: NSCoder) { @@ -50,16 +53,7 @@ internal class Settings: NSView, Settings_v { public func load(widgets: [widget_t]) { self.subviews.forEach{ $0.removeFromSuperview() } - let rowHeight: CGFloat = 30 - let num: CGFloat = widgets.filter{ $0 == .mini }.isEmpty ? 2 : 3 - - self.addSubview(selectTitleRow( - frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * (num-1), - width: self.frame.width - (Constants.Settings.margin*2), - height: rowHeight - ), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval"), action: #selector(changeUpdateInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, @@ -67,34 +61,26 @@ internal class Settings: NSView, Settings_v { )) if !widgets.filter({ $0 == .mini }).isEmpty { - self.addSubview(toggleTitleRow( - frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 1, - width: self.frame.width - (Constants.Settings.margin*2), - height: rowHeight - ), + self.addArrangedSubview(toggleSettingRow( title: localizedString("Show GPU type"), action: #selector(toggleShowType), state: self.showTypeValue )) } - self.addGPUSelector(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin + (rowHeight + Constants.Settings.margin) * 0, - width: self.frame.width - (Constants.Settings.margin*2), - height: rowHeight - )) - - self.setFrameSize(NSSize(width: self.frame.width, height: (rowHeight*num) + (Constants.Settings.margin*(num+1)))) + self.addGPUSelector() } - private func addGPUSelector(frame: NSRect) { - let view: NSGridView = NSGridView(frame: frame) - view.yPlacement = .center + private func addGPUSelector() { + let view: NSStackView = NSStackView() + view.translatesAutoresizingMaskIntoConstraints = false + view.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + view.orientation = .horizontal + view.alignment = .centerY + view.distribution = .fill + view.spacing = 0 - let title: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 100, height: 17), localizedString("GPU to show")) + let title: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 17), localizedString("GPU to show")) title.font = NSFont.systemFont(ofSize: 13, weight: .light) title.textColor = .textColor @@ -107,9 +93,11 @@ internal class Settings: NSView, Settings_v { self.button = button container.addRow(with: [button]) - view.addRow(with: [title, container]) + view.addArrangedSubview(title) + view.addArrangedSubview(NSView()) + view.addArrangedSubview(container) - self.addSubview(view) + self.addArrangedSubview(view) } internal func setList(_ gpus: GPUs) { diff --git a/Modules/Net/settings.swift b/Modules/Net/settings.swift index 580c92cb..d1abc60b 100644 --- a/Modules/Net/settings.swift +++ b/Modules/Net/settings.swift @@ -33,7 +33,7 @@ internal class Settings: NSStackView, Settings_v { self.readerType = Store.shared.string(key: "\(self.title)_reader", defaultValue: self.readerType) self.usageReset = Store.shared.string(key: "\(self.title)_usageReset", defaultValue: self.usageReset) - super.init(frame: NSRect(x: 0, y: 0, width: Constants.Settings.width - (Constants.Settings.margin*2), height: 0)) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) for interface in SCNetworkInterfaceCopyAll() as NSArray { if let bsdName = SCNetworkInterfaceGetBSDName(interface as! SCNetworkInterface), @@ -60,42 +60,32 @@ internal class Settings: NSStackView, Settings_v { public func load(widgets: [widget_t]) { self.subviews.forEach{ $0.removeFromSuperview() } - let width: CGFloat = self.frame.width - (Constants.Settings.margin*2) - - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Number of top processes"), action: #selector(changeNumberOfProcesses), items: NumbersOfProcesses.map{ "\($0)" }, selected: "\(self.numberOfProcesses)" )) - self.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRow( title: localizedString("Reader type"), action: #selector(changeReaderType), items: NetworkReaders, selected: self.readerType )) - self.addArrangedSubview(selectRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRow( title: localizedString("Reset data usage"), action: #selector(toggleUsageReset), items: AppUpdateIntervals.dropLast(2), selected: self.usageReset )) - self.addInterfaceSelector() - - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.bounds.width, height: h)) - } +// self.addInterfaceSelector() } private func addInterfaceSelector() { - let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: self.frame.width, height: 30)) + let view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: 0, height: 30)) let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (view.frame.height - 16)/2, width: view.frame.width - 52, height: 17), localizedString("Network interface")) rowTitle.font = NSFont.systemFont(ofSize: 13, weight: .light) diff --git a/Modules/RAM/settings.swift b/Modules/RAM/settings.swift index 077dc658..add9daa7 100644 --- a/Modules/RAM/settings.swift +++ b/Modules/RAM/settings.swift @@ -32,12 +32,7 @@ internal class Settings: NSStackView, Settings_v { self.numberOfProcesses = Store.shared.int(key: "\(self.title)_processes", defaultValue: self.numberOfProcesses) self.splitValueState = Store.shared.bool(key: "\(self.title)_splitValue", defaultValue: self.splitValueState) - super.init(frame: NSRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.orientation = .vertical self.distribution = .gravityAreas @@ -56,26 +51,22 @@ internal class Settings: NSStackView, Settings_v { public func load(widgets: [widget_t]) { self.subviews.forEach{ $0.removeFromSuperview() } - let width: CGFloat = self.frame.width - (Constants.Settings.margin*2) - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval"), action: #selector(changeUpdateInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, selected: "\(self.updateIntervalValue) sec" )) - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval for top processes"), action: #selector(changeUpdateTopInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, selected: "\(self.updateTopIntervalValue) sec" )) - self.addArrangedSubview(selectTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Number of top processes"), action: #selector(changeNumberOfProcesses), items: NumbersOfProcesses.map{ "\($0)" }, @@ -83,18 +74,12 @@ internal class Settings: NSStackView, Settings_v { )) if !widgets.filter({ $0 == .barChart }).isEmpty { - self.addArrangedSubview(toggleTitleRow( - frame: NSRect(x: 0, y: 0, width: width, height: Constants.Settings.row), + self.addArrangedSubview(toggleSettingRow( title: localizedString("Split the value (App/Wired/Compressed)"), action: #selector(toggleSplitValue), state: self.splitValueState )) } - - let h = self.arrangedSubviews.map({ $0.bounds.height + self.spacing }).reduce(0, +) - self.spacing + self.edgeInsets.top + self.edgeInsets.bottom - if self.frame.size.height != h { - self.setFrameSize(NSSize(width: self.bounds.width, height: h)) - } } @objc private func changeUpdateInterval(_ sender: NSMenuItem) { diff --git a/Modules/Sensors/settings.swift b/Modules/Sensors/settings.swift index a0d6fcac..5d0c64d6 100644 --- a/Modules/Sensors/settings.swift +++ b/Modules/Sensors/settings.swift @@ -12,7 +12,7 @@ import Cocoa import Kit -internal class Settings: NSView, Settings_v { +internal class Settings: NSStackView, Settings_v { private var updateIntervalValue: Int = 3 private let title: String @@ -25,15 +25,19 @@ internal class Settings: NSView, Settings_v { self.title = title self.list = list - super.init(frame: CGRect( - x: 0, - y: 0, - width: Constants.Settings.width - (Constants.Settings.margin*2), - height: 0 - )) + super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) self.wantsLayer = true - self.canDrawConcurrently = true + self.orientation = .vertical + self.distribution = .gravityAreas + self.translatesAutoresizingMaskIntoConstraints = false + self.edgeInsets = NSEdgeInsets( + top: Constants.Settings.margin, + left: Constants.Settings.margin, + bottom: Constants.Settings.margin, + right: Constants.Settings.margin + ) + self.spacing = Constants.Settings.margin self.updateIntervalValue = Store.shared.int(key: "\(self.title)_updateInterval", defaultValue: self.updateIntervalValue) } @@ -55,28 +59,27 @@ internal class Settings: NSView, Settings_v { } } - let rowHeight: CGFloat = 30 - let settingsHeight: CGFloat = (rowHeight*1) + Constants.Settings.margin - let sensorsListHeight: CGFloat = (rowHeight+Constants.Settings.margin) * CGFloat(self.list.count) + ((rowHeight+Constants.Settings.margin) * CGFloat(types.count) + 1) - let height: CGFloat = settingsHeight + sensorsListHeight - let x: CGFloat = height < 360 ? 0 : Constants.Settings.margin - let view: NSView = NSView(frame: NSRect( - x: Constants.Settings.margin, - y: Constants.Settings.margin, - width: self.frame.width - (Constants.Settings.margin*2) - x, - height: height - )) - - self.addSubview(selectTitleRow( - frame: NSRect(x: Constants.Settings.margin, y: height - rowHeight, width: view.frame.width, height: rowHeight), + self.addArrangedSubview(selectSettingsRowV1( title: localizedString("Update interval"), action: #selector(changeUpdateInterval), items: ReaderUpdateIntervals.map{ "\($0) sec" }, selected: "\(self.updateIntervalValue) sec" )) - var y: CGFloat = 0 types.reversed().forEach { (typ: SensorType) in + let header = NSStackView() + header.heightAnchor.constraint(equalToConstant: Constants.Settings.row).isActive = true + header.spacing = 0 + + let titleField: NSTextField = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0), localizedString(typ.rawValue)) + titleField.font = NSFont.systemFont(ofSize: 13, weight: .medium) + titleField.textColor = .labelColor + + header.addArrangedSubview(titleField) + header.addArrangedSubview(NSView()) + + self.addArrangedSubview(header) + let filtered = self.list.filter{ $0.type == typ } var groups: [SensorGroup] = [] filtered.forEach { (s: Sensor_p) in @@ -85,10 +88,19 @@ internal class Settings: NSView, Settings_v { } } + let container = NSStackView() + container.orientation = .vertical + container.edgeInsets = NSEdgeInsets( + top: 0, + left: Constants.Settings.margin, + bottom: 0, + right: Constants.Settings.margin + ) + container.spacing = 0 + groups.reversed().forEach { (group: SensorGroup) in filtered.reversed().filter{ $0.group == group }.forEach { (s: Sensor_p) in - let row: NSView = toggleTitleRow( - frame: NSRect(x: 0, y: y, width: view.frame.width, height: rowHeight), + let row: NSView = toggleSettingRow( title: s.name, action: #selector(self.handleSelection), state: s.state @@ -96,24 +108,12 @@ internal class Settings: NSView, Settings_v { row.subviews.filter{ $0 is NSControl }.forEach { (control: NSView) in control.identifier = NSUserInterfaceItemIdentifier(rawValue: s.key) } - view.addSubview(row) - y += rowHeight + Constants.Settings.margin + container.addArrangedSubview(row) } } - - let rowTitleView: NSView = NSView(frame: NSRect(x: 0, y: y, width: view.frame.width, height: rowHeight)) - let rowTitle: NSTextField = LabelField(frame: NSRect(x: 0, y: (rowHeight-19)/2, width: view.frame.width, height: 19), localizedString(typ.rawValue)) - rowTitle.font = NSFont.systemFont(ofSize: 14, weight: .regular) - rowTitle.textColor = .secondaryLabelColor - rowTitle.alignment = .center - rowTitleView.addSubview(rowTitle) - - view.addSubview(rowTitleView) - y += rowHeight + Constants.Settings.margin + + self.addArrangedSubview(container) } - - self.addSubview(view) - self.setFrameSize(NSSize(width: self.frame.width, height: height + (Constants.Settings.margin*1))) } @objc private func handleSelection(_ sender: NSControl) {