.../Source/App/SearchAndPreview/SearchAndPreviewViewBase.swift
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // SearchPreviewViewBase.swift |
3 | | // CutBox |
4 | | // |
5 | | // Created by Jason Milkins on 20/5/18. |
6 | | // Copyright © 2018-2023 ocodo. All rights reserved. |
7 | | // |
8 | | |
9 | | import RxSwift |
10 | | import RxCocoa |
11 | | import Cocoa |
12 | | import CoreImage |
13 | | |
14 | | let useTextCommands: [Selector] = [ |
15 | | "deleteBackwards:", |
16 | | "deleteForwards:", |
17 | | "deleteWord:", |
18 | | "deleteWordBackwards:", |
19 | | "cut", |
20 | | "copy", |
21 | | "paste", |
22 | | "undo", |
23 | | "redo", |
24 | | "selectAll" |
25 | 10 | ].map { Selector($0) } |
26 | | |
27 | | class SearchAndPreviewViewBase: CutBoxBaseView { |
28 | | |
29 | | @IBOutlet weak var searchContainer: CutBoxBaseBox! |
30 | | @IBOutlet weak var searchTextContainer: CutBoxBaseBox! |
31 | | @IBOutlet weak var searchTextPlaceholder: CutBoxBaseTextField! |
32 | | @IBOutlet weak var searchText: SearchTextView! |
33 | | @IBOutlet weak var itemsList: NSTableView! |
34 | | @IBOutlet weak var preview: CutBoxBaseTextView! |
35 | | @IBOutlet weak var previewContainer: CutBoxBaseBox! |
36 | | @IBOutlet weak var iconImageView: NSImageView! |
37 | | @IBOutlet weak var searchScopeImageButton: CutBoxBaseButton! |
38 | | @IBOutlet weak var mainContainer: CutBoxBaseStackView! |
39 | | @IBOutlet weak var container: CutBoxBaseStackView! |
40 | | @IBOutlet weak var bottomBar: CutBoxBaseView! |
41 | | |
42 | | @IBOutlet weak var searchTextContainerHeight: NSLayoutConstraint! |
43 | | @IBOutlet weak var mainTopConstraint: NSLayoutConstraint! |
44 | | @IBOutlet weak var mainLeadingConstraint: NSLayoutConstraint! |
45 | | @IBOutlet weak var mainTrailingConstraint: NSLayoutConstraint! |
46 | | @IBOutlet weak var mainBottomConstraint: NSLayoutConstraint! |
47 | | |
48 | | var searchTextHeight: CGFloat { |
49 | 1 | get { |
50 | 1 | return searchTextContainerHeight.constant |
51 | 1 | } |
52 | 51 | set { |
53 | 51 | searchTextContainerHeight.constant = newValue |
54 | 51 | } |
55 | | } |
56 | | |
57 | | var spacing: CGFloat { |
58 | 52 | get { |
59 | 52 | return mainContainer.spacing |
60 | 52 | } |
61 | 51 | set { |
62 | 51 | mainContainer.spacing = newValue |
63 | 51 | container.spacing = newValue |
64 | 51 | mainTopConstraint.constant = newValue |
65 | 51 | mainLeadingConstraint.constant = newValue |
66 | 51 | mainTrailingConstraint.constant = newValue |
67 | 51 | mainBottomConstraint.constant = newValue |
68 | 51 | } |
69 | | } |
70 | | |
71 | 154 | var filterTextPublisher = PublishSubject<String>() |
72 | | |
73 | | var placeHolderTextString = "" |
74 | | |
75 | 154 | let disposeBag = DisposeBag() |
76 | 154 | var prefs = CutBoxPreferencesService.shared |
77 | | |
78 | 82 | override init(frame: NSRect) { |
79 | 82 | super.init(frame: frame) |
80 | 82 | } |
81 | | |
82 | 72 | required init?(coder decoder: NSCoder) { |
83 | 72 | super.init(coder: decoder) |
84 | 72 | } |
85 | | |
86 | 1 | override var acceptsFirstResponder: Bool { |
87 | 1 | return true |
88 | 1 | } |
89 | | |
90 | 2 | var selectedItems: IndexSet? { |
91 | 2 | self.itemsList? |
92 | 2 | .selectedRowIndexes |
93 | 2 | } |
94 | | |
95 | | var menuDelegate: NSMenuDelegate? { |
96 | 1 | get { |
97 | 1 | self.itemsList? |
98 | 1 | .menu?.delegate |
99 | 1 | } |
100 | | |
101 | 75 | set { |
102 | 75 | self.itemsList? |
103 | 75 | .menu?.delegate = newValue |
104 | 75 | } |
105 | | } |
106 | | |
107 | | var itemsDelegate: NSTableViewDelegate? { |
108 | 1 | get { |
109 | 1 | self.itemsList?.delegate |
110 | 1 | } |
111 | | |
112 | 75 | set { |
113 | 75 | self.itemsList?.delegate = newValue |
114 | 75 | } |
115 | | } |
116 | | |
117 | | var itemsDataSource: NSTableViewDataSource? { |
118 | 1 | get { |
119 | 1 | self.itemsList?.dataSource |
120 | 1 | } |
121 | | |
122 | 75 | set { |
123 | 75 | self.itemsList?.dataSource = newValue |
124 | 75 | } |
125 | | } |
126 | | |
127 | | var previewString: String? { |
128 | 1 | get { |
129 | 1 | self.preview?.string |
130 | 1 | } |
131 | | |
132 | 4 | set { |
133 | 4 | self.preview?.string = newValue! |
134 | 4 | } |
135 | | } |
136 | | |
137 | 4 | func setTextScale() { |
138 | 4 | self.preview?.font = prefs.searchViewClipPreviewFont |
139 | 4 | } |
140 | | |
141 | 4 | func hideSearchResults(_ bool: Bool) { |
142 | 4 | self.bottomBar?.isHidden = bool |
143 | 4 | self.container?.isHidden = bool |
144 | 4 | } |
145 | | |
146 | 1.15k | func hidePreview(_ bool: Bool) { |
147 | 1.15k | self.previewContainer?.isHidden = bool |
148 | 1.15k | } |
149 | | |
150 | 72 | func setupPlaceholder() { |
151 | 72 | filterTextPublisher |
152 | 72 | .map { $0.isEmpty ? self.placeHolderTextString : "" } |
153 | 72 | .bind(to: searchTextPlaceholder.rx.text) |
154 | 72 | .disposed(by: disposeBag) |
155 | 72 | } |
156 | | |
157 | 2 | func scrollRowToVisible(_ row: Int) { |
158 | 2 | self.itemsList?.scrollRowToVisible(row) |
159 | 2 | } |
160 | | |
161 | 17 | func reloadData() { |
162 | 17 | self.itemsList?.reloadData() |
163 | 17 | } |
164 | | |
165 | 5 | func selectRowIndexes(_ indexes: IndexSet, byExtendingSelection extend: Bool) { |
166 | 5 | self.itemsList?.selectRowIndexes(indexes, byExtendingSelection: extend) |
167 | 5 | } |
168 | | |
169 | 4 | var selectedRowIndexes: IndexSet? { |
170 | 4 | self.itemsList?.selectedRowIndexes |
171 | 4 | } |
172 | | |
173 | 72 | override func awakeFromNib() { |
174 | 72 | self.preview.textContainer!.widthTracksTextView = false |
175 | 72 | |
176 | 72 | self.preview.textContainer!.containerSize = CGSize( |
177 | 72 | width: CGFloat.greatestFiniteMagnitude, |
178 | 72 | height: CGFloat.greatestFiniteMagnitude |
179 | 72 | ) |
180 | 72 | |
181 | 72 | setupPlaceholder() |
182 | 72 | } |
183 | | |
184 | | func colorizeMagnifier(image: NSImage = CutBoxImageRef.magnitude.image(), |
185 | | tooltip: String = "search_scope_tooltip_all".l7n, |
186 | | alpha: Double = 0.75, |
187 | 150 | color: NSColor = NSColor.white) { |
188 | 150 | |
189 | 150 | let image = image |
190 | 150 | let blended = image.tint(color: color) |
191 | 150 | |
192 | 150 | self.searchScopeImageButton?.alphaValue = alpha |
193 | 150 | self.searchScopeImageButton?.image = blended |
194 | 150 | self.searchScopeImageButton?.toolTip = toolTip |
195 | 150 | } |
196 | | |
197 | 51 | func applyTheme() { |
198 | 51 | let theme = prefs.currentTheme |
199 | 51 | |
200 | 51 | colorizeMagnifier(color: theme.searchText.placeholderTextColor) |
201 | 51 | |
202 | 51 | self.spacing = theme.spacing |
203 | 51 | self.searchTextHeight = 60 - (spacing * 2.0) |
204 | 51 | |
205 | 51 | preview?.font = prefs.searchViewClipPreviewFont |
206 | 51 | searchTextPlaceholder?.font = prefs.searchViewTextFieldFont |
207 | 51 | searchText?.font = prefs.searchViewTextFieldFont |
208 | 51 | |
209 | 51 | itemsList?.backgroundColor = theme.clip.backgroundColor |
210 | 51 | |
211 | 51 | searchContainer?.fillColor = theme.popupBackgroundColor |
212 | 51 | |
213 | 51 | searchText?.textColor = theme.searchText.textColor |
214 | 51 | searchText?.insertionPointColor = theme.searchText.cursorColor |
215 | 51 | searchTextContainer?.fillColor = theme.searchText.backgroundColor |
216 | 51 | searchTextPlaceholder?.textColor = theme.searchText.placeholderTextColor |
217 | 51 | |
218 | 51 | preview?.backgroundColor = theme.preview.backgroundColor |
219 | 51 | previewContainer?.fillColor = theme.preview.backgroundColor |
220 | 51 | preview?.textColor = theme.preview.textColor |
221 | 51 | |
222 | 51 | preview?.selectedTextAttributes[.backgroundColor] = theme.preview.selectedTextBackgroundColor |
223 | 51 | preview?.selectedTextAttributes[.foregroundColor] = theme.preview.selectedTextColor |
224 | 51 | } |
225 | | } |