mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
feat: initialized popup view for the combined modules (#1084)
This commit is contained in:
@@ -18,6 +18,7 @@ public struct Popup_c_s {
|
||||
public let spacing: CGFloat = 2
|
||||
public let headerHeight: CGFloat = 42
|
||||
public let separatorHeight: CGFloat = 30
|
||||
public let portalHeight: CGFloat = 100
|
||||
}
|
||||
|
||||
public struct Settings_c_s {
|
||||
|
||||
@@ -230,7 +230,7 @@ public struct DiskSize {
|
||||
}
|
||||
|
||||
public class LabelField: NSTextField {
|
||||
public init(frame: NSRect, _ label: String = "") {
|
||||
public init(frame: NSRect = NSRect(), _ label: String = "") {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.isEditable = false
|
||||
@@ -670,7 +670,7 @@ public class ColorView: NSView {
|
||||
private var color: NSColor
|
||||
private var state: Bool
|
||||
|
||||
public init(frame: NSRect, color: NSColor, state: Bool = false, radius: CGFloat = 2) {
|
||||
public init(frame: NSRect = NSRect.zero, color: NSColor, state: Bool = false, radius: CGFloat = 2) {
|
||||
self.color = color
|
||||
self.state = state
|
||||
|
||||
@@ -759,17 +759,24 @@ public class ProcessView: NSStackView {
|
||||
private var pid: Int? = nil
|
||||
private var lock: Bool = false
|
||||
|
||||
private var imageView: NSImageView = NSImageView(frame: NSRect(x: 5, y: 5, width: 12, height: 12))
|
||||
private var killView: NSButton = NSButton(frame: NSRect(x: 5, y: 5, width: 12, height: 12))
|
||||
private var imageView: NSImageView = NSImageView()
|
||||
private var killView: NSButton = NSButton()
|
||||
private var labelView: LabelField = {
|
||||
let view = LabelField(frame: NSRect(x: 0, y: 0, width: 0, height: 0))
|
||||
let view = LabelField()
|
||||
view.cell?.truncatesLastVisibleLine = true
|
||||
return view
|
||||
}()
|
||||
private var valueView: ValueField = ValueField(frame: NSRect(x: 0, y: 0, width: 0, height: 0))
|
||||
|
||||
public init() {
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: 264, height: 22))
|
||||
public init(size: CGSize = CGSize(width: 264, height: 22)) {
|
||||
var rect = NSRect(x: 5, y: 5, width: 12, height: 12)
|
||||
if size.height != 22 {
|
||||
rect = NSRect(x: 3, y: 3, width: 12, height: 12)
|
||||
}
|
||||
self.imageView = NSImageView(frame: rect)
|
||||
self.killView = NSButton(frame: rect)
|
||||
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: size.width, height: size.height))
|
||||
|
||||
self.wantsLayer = true
|
||||
self.orientation = .horizontal
|
||||
@@ -778,7 +785,7 @@ public class ProcessView: NSStackView {
|
||||
self.layer?.cornerRadius = 3
|
||||
|
||||
let imageBox: NSView = {
|
||||
let view = NSView(frame: NSRect(x: 0, y: 0, width: 0, height: 0))
|
||||
let view = NSView()
|
||||
|
||||
self.killView.bezelStyle = .regularSquare
|
||||
self.killView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
@@ -78,6 +78,7 @@ open class Module: Module_p {
|
||||
|
||||
public var menuBar: MenuBar
|
||||
public var settings: Settings_p? = nil
|
||||
public let portal: Portal_p?
|
||||
|
||||
public var name: String {
|
||||
config.name
|
||||
@@ -107,7 +108,8 @@ open class Module: Module_p {
|
||||
}
|
||||
}
|
||||
|
||||
public init(popup: Popup_p? = nil, settings: Settings_v? = nil) {
|
||||
public init(popup: Popup_p? = nil, settings: Settings_v? = nil, portal: Portal_p? = nil) {
|
||||
self.portal = portal
|
||||
self.config = module_c(in: Bundle(for: type(of: self)).path(forResource: "config", ofType: "plist")!)
|
||||
|
||||
self.log = NextLog.shared.copy(category: self.config.name)
|
||||
|
||||
@@ -16,12 +16,12 @@ public protocol Popup_p: NSView {
|
||||
func settings() -> NSView?
|
||||
}
|
||||
|
||||
internal class PopupWindow: NSWindow, NSWindowDelegate {
|
||||
public class PopupWindow: NSWindow, NSWindowDelegate {
|
||||
private let viewController: PopupViewController = PopupViewController()
|
||||
internal var locked: Bool = false
|
||||
internal var openedBy: widget_t? = nil
|
||||
|
||||
init(title: String, view: Popup_p?, visibilityCallback: @escaping (_ state: Bool) -> Void) {
|
||||
public init(title: String, view: Popup_p?, visibilityCallback: @escaping (_ state: Bool) -> Void) {
|
||||
self.viewController.setup(title: title, view: view)
|
||||
|
||||
super.init(
|
||||
@@ -51,12 +51,12 @@ internal class PopupWindow: NSWindow, NSWindowDelegate {
|
||||
self.delegate = self
|
||||
}
|
||||
|
||||
func windowWillMove(_ notification: Notification) {
|
||||
public func windowWillMove(_ notification: Notification) {
|
||||
self.viewController.setCloseButton(true)
|
||||
self.locked = true
|
||||
}
|
||||
|
||||
func windowDidResignKey(_ notification: Notification) {
|
||||
public func windowDidResignKey(_ notification: Notification) {
|
||||
if self.locked {
|
||||
return
|
||||
}
|
||||
|
||||
16
Kit/module/portal.swift
Normal file
16
Kit/module/portal.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// portal.swift
|
||||
// Kit
|
||||
//
|
||||
// Created by Serhiy Mytrovtsiy on 17/02/2023
|
||||
// Using Swift 5.0
|
||||
// Running on macOS 13.2
|
||||
//
|
||||
// Copyright © 2023 Serhiy Mytrovtsiy. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
public protocol Portal_p: NSView {
|
||||
var name: String { get set }
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import Kit
|
||||
class CombinedView {
|
||||
private var menuBarItem: NSStatusItem? = nil
|
||||
private var view: NSView = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: Constants.Widget.height))
|
||||
private var popup: PopupWindow? = nil
|
||||
|
||||
private var status: Bool {
|
||||
Store.shared.bool(key: "CombinedModules", defaultValue: false)
|
||||
@@ -34,6 +35,8 @@ class CombinedView {
|
||||
}
|
||||
}
|
||||
|
||||
self.popup = PopupWindow(title: "Combined modules", view: Popup()) { _ in }
|
||||
|
||||
if self.status {
|
||||
self.enable()
|
||||
}
|
||||
@@ -52,7 +55,7 @@ class CombinedView {
|
||||
self.menuBarItem?.button?.addSubview(self.view)
|
||||
|
||||
self.menuBarItem?.button?.target = self
|
||||
self.menuBarItem?.button?.action = #selector(self.openSettings)
|
||||
self.menuBarItem?.button?.action = #selector(self.togglePopup)
|
||||
self.menuBarItem?.button?.sendAction(on: [.leftMouseDown, .rightMouseDown])
|
||||
|
||||
DispatchQueue.main.async(execute: {
|
||||
@@ -82,8 +85,33 @@ class CombinedView {
|
||||
self.menuBarItem?.length = w
|
||||
}
|
||||
|
||||
@objc private func openSettings() {
|
||||
NotificationCenter.default.post(name: .toggleSettings, object: nil, userInfo: ["module": "Dashboard"])
|
||||
// call when popup appear/disappear
|
||||
private func visibilityCallback(_ state: Bool) {}
|
||||
|
||||
@objc private func togglePopup(_ sender: Any) {
|
||||
guard let popup = self.popup, let item = self.menuBarItem, let window = item.button?.window else { return }
|
||||
let openedWindows = NSApplication.shared.windows.filter{ $0 is NSPanel }
|
||||
openedWindows.forEach{ $0.setIsVisible(false) }
|
||||
|
||||
if popup.occlusionState.rawValue == 8192 {
|
||||
NSApplication.shared.activate(ignoringOtherApps: true)
|
||||
|
||||
popup.contentView?.invalidateIntrinsicContentSize()
|
||||
|
||||
let windowCenter = popup.contentView!.intrinsicContentSize.width / 2
|
||||
var x = window.frame.origin.x - windowCenter + window.frame.width/2
|
||||
let y = window.frame.origin.y - popup.contentView!.intrinsicContentSize.height - 3
|
||||
|
||||
let maxWidth = NSScreen.screens.map{ $0.frame.width }.reduce(0, +)
|
||||
if x + popup.contentView!.intrinsicContentSize.width > maxWidth {
|
||||
x = maxWidth - popup.contentView!.intrinsicContentSize.width - 3
|
||||
}
|
||||
|
||||
popup.setFrameOrigin(NSPoint(x: x, y: y))
|
||||
popup.setIsVisible(true)
|
||||
} else {
|
||||
popup.setIsVisible(false)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func listenForOneView(_ notification: Notification) {
|
||||
@@ -100,3 +128,58 @@ class CombinedView {
|
||||
self.recalculate()
|
||||
}
|
||||
}
|
||||
|
||||
private class Popup: NSStackView, Popup_p {
|
||||
public var sizeCallback: ((NSSize) -> Void)? = nil
|
||||
|
||||
init() {
|
||||
super.init(frame: NSRect(x: 0, y: 0, width: Constants.Popup.width, height: 0))
|
||||
|
||||
self.orientation = .vertical
|
||||
self.distribution = .fill
|
||||
self.alignment = .width
|
||||
self.spacing = Constants.Popup.spacing
|
||||
|
||||
self.reinit()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reinit), name: .toggleModule, object: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self, name: .toggleOneView, object: nil)
|
||||
}
|
||||
|
||||
public func settings() -> NSView? { return nil }
|
||||
|
||||
@objc private func reinit() {
|
||||
self.subviews.forEach({ $0.removeFromSuperview() })
|
||||
|
||||
let availableModules = modules.filter({ $0.enabled && $0.portal != nil })
|
||||
let pairs = stride(from: 0, to: availableModules.endIndex, by: 2).map {
|
||||
(availableModules[$0], $0 < availableModules.index(before: availableModules.endIndex) ? availableModules[$0.advanced(by: 1)] : nil)
|
||||
}
|
||||
pairs.forEach { (m1: Module, m2: Module?) in
|
||||
let row = NSStackView()
|
||||
row.orientation = .horizontal
|
||||
row.distribution = .fillEqually
|
||||
row.spacing = Constants.Popup.spacing
|
||||
|
||||
if let p = m1.portal {
|
||||
row.addArrangedSubview(p)
|
||||
}
|
||||
if let p = m2?.portal {
|
||||
row.addArrangedSubview(p)
|
||||
}
|
||||
|
||||
self.addArrangedSubview(row)
|
||||
}
|
||||
|
||||
let h = CGFloat(pairs.count) * Constants.Popup.portalHeight + (CGFloat(pairs.count)*Constants.Popup.spacing)
|
||||
self.setFrameSize(NSSize(width: self.frame.width, height: h))
|
||||
self.sizeCallback?(self.frame.size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,8 @@ class SettingsWindow: NSWindow, NSWindowDelegate, NSToolbarDelegate {
|
||||
self.orderFrontRegardless()
|
||||
}
|
||||
|
||||
if let name = notification.userInfo?["module"] as? String {
|
||||
if var name = notification.userInfo?["module"] as? String {
|
||||
if name == "Combined modules" { name = "Dashboard" }
|
||||
self.sidebarView.openMenu(name)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user