Reuse table rows.

This commit is contained in:
2025-02-07 09:47:10 -08:00
parent cf2b5b8cec
commit 58aa0487dc

View File

@@ -11,13 +11,14 @@ struct ProgramWeighted {
let weight: Int let weight: Int
} }
class SearchViewController: NSViewController, NSTextFieldDelegate, fileprivate let maxItems = 10
NSPopoverDelegate, NSTableViewDataSource, NSTableViewDelegate
{ class SearchViewController: NSViewController, NSTextFieldDelegate, NSPopoverDelegate, NSTableViewDataSource, NSTableViewDelegate {
private var keyboardEvents: EventMonitor? private var keyboardEvents: EventMonitor?
private var programsList: [Program] = Array(repeating: Program(), count: 10)
private var listIndex = 0 private var listIndex = 0
private var programsList: [Program] = Array(repeating: Program(), count: maxItems)
private var programsListCells: [ProgramsTableViewCell] = []
private var programsTableViewSelection = 0 private var programsTableViewSelection = 0
@@ -109,8 +110,7 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
table.allowsColumnReordering = false table.allowsColumnReordering = false
table.allowsColumnResizing = false table.allowsColumnResizing = false
table.allowsColumnSelection = false table.allowsColumnSelection = false
table.addTableColumn(NSTableColumn( table.addTableColumn(NSTableColumn(identifier: NSUserInterfaceItemIdentifier("Program")))
identifier: NSUserInterfaceItemIdentifier("Program")))
table.doubleAction = #selector(tableDoubleClick) table.doubleAction = #selector(tableDoubleClick)
@@ -168,6 +168,11 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
// Initialize an array of reusable cells.
for _ in 0..<maxItems {
programsListCells.append(ProgramsTableViewCell())
}
view.wantsLayer = true view.wantsLayer = true
view.layer?.backgroundColor = NSColor.clear.cgColor view.layer?.backgroundColor = NSColor.clear.cgColor
@@ -270,8 +275,7 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
let url = URL(fileURLWithPath: program.path).appendingPathComponent(program.name+program.ext) let url = URL(fileURLWithPath: program.path).appendingPathComponent(program.name+program.ext)
let config = NSWorkspace.OpenConfiguration() let config = NSWorkspace.OpenConfiguration()
// NOTE: This needs a window! Do not just copy-paste // NOTE: This needs a window! Do not just copy-paste this block elsewhere.
// this block elsewhere.
NSWorkspace.shared.openApplication(at: url, configuration: config) { [weak self] application, error in NSWorkspace.shared.openApplication(at: url, configuration: config) { [weak self] application, error in
if let error = error { if let error = error {
print("\(error.localizedDescription)") print("\(error.localizedDescription)")
@@ -287,15 +291,14 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
} }
func controlTextDidChange(_ obj: Notification) { func controlTextDidChange(_ obj: Notification) {
guard let searchInput = obj.object as? EditableNSTextField guard let searchInput = obj.object as? EditableNSTextField else { return }
else { return }
listIndex = 0 listIndex = 0
if !searchInput.stringValue.isEmpty { if !searchInput.stringValue.isEmpty {
outerloop: for path in PathManager.shared.paths { outerloop: for path in PathManager.shared.paths {
for i in path.value.indices { for i in path.value.indices {
var prog = path.value[i] if listIndex >= maxItems { break outerloop }
if listIndex >= 10 { break outerloop } let prog = path.value[i]
if prog.name.lowercased().contains(searchInput.stringValue.lowercased()) { if prog.name.lowercased().contains(searchInput.stringValue.lowercased()) {
programsList[listIndex].path = prog.path programsList[listIndex].path = prog.path
@@ -325,8 +328,7 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
} else if commandSelector == #selector(NSResponder.insertTab(_:)) { } else if commandSelector == #selector(NSResponder.insertTab(_:)) {
return true return true
} else if commandSelector == #selector(NSResponder.moveUp(_:)) || commandSelector == #selector(NSResponder.moveDown(_:)) { } else if commandSelector == #selector(NSResponder.moveUp(_:)) || commandSelector == #selector(NSResponder.moveDown(_:)) {
// Ignore arrows keys up or down because we use those to // Ignore arrows up and down because we use those to navigate the programs list.
// navigate the programs list.
return true return true
} }
@@ -351,17 +353,10 @@ class SearchViewController: NSViewController, NSTextFieldDelegate,
return ProgramsTableRowView() return ProgramsTableRowView()
} }
func tableView(_ tableView: NSTableView, func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? let cell = programsListCells[row]
{
let cell = ProgramsTableViewCell()
let program = programsList[row] let program = programsList[row]
// PERF: This is very slow, even with 10 items on the list! It has
// to be the image of concern. UIKit has reusable cells,
// is that possible? Or is fetching an image is slow?
// searchInput.stringValue
let app = program.name + program.ext let app = program.name + program.ext
let rangeToHighlight = (app.lowercased() as NSString).range(of: searchInput.stringValue.lowercased()) let rangeToHighlight = (app.lowercased() as NSString).range(of: searchInput.stringValue.lowercased())
let attributedString = NSMutableAttributedString(string: app) let attributedString = NSMutableAttributedString(string: app)