KMEditImagePropertyViewController.swift 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. //
  2. // KMEditImagePropertyViewController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lxy on 2022/12/28.
  6. //
  7. import Cocoa
  8. public enum KMOperationState {
  9. case none
  10. case began
  11. case changed
  12. case ended
  13. }
  14. enum KMEditImagePropertyViewControllerChangeType {
  15. case rotate
  16. case flip
  17. case add
  18. case move
  19. }
  20. protocol KMEditImagePropertyViewControllerDelegate: NSObject {
  21. func editImagePropertyViewControllerDidChanged(controller: KMEditImagePropertyViewController, type: KMEditImagePropertyViewControllerChangeType)
  22. }
  23. class KMEditImagePropertyViewController: NSViewController {
  24. @IBOutlet weak var backgroundView: NSView!
  25. @IBOutlet weak var titleLabel: NSTextField!
  26. @IBOutlet weak var headerBox: NSBox!
  27. @IBOutlet weak var headerBoxHeight: NSLayoutConstraint!
  28. @IBOutlet weak var whTitleLabel: NSTextField!
  29. @IBOutlet weak var wTextFieldItemView: KMCustomTextField!
  30. @IBOutlet weak var whBox: NSBox!
  31. @IBOutlet weak var hTextFieldItemView: KMCustomTextField!
  32. var whVC: KMDesignButton?
  33. @IBOutlet weak var rotateTitleLabel: NSTextField!
  34. @IBOutlet weak var rotateTextFieldItemView: KMDesignTextField!
  35. @IBOutlet weak var leftRotateBox: NSBox!
  36. @IBOutlet weak var rightRotateBox: NSBox!
  37. var leftRotateVC: KMDesignButton?
  38. var rightRotateVC: KMDesignButton?
  39. @IBOutlet weak var opacityTitleLabel: NSTextField!
  40. @IBOutlet weak var opacitySlider: NSSlider!
  41. @IBOutlet weak var opacityBox: NSBox!
  42. @IBOutlet weak var opacityBoxBottomMaginConstraint: NSLayoutConstraint!
  43. @IBOutlet weak var opacityBoxTopConstraint: NSLayoutConstraint!
  44. @IBOutlet weak var turnOverBox: NSBox!
  45. @IBOutlet weak var turnOverTitleLabel: NSTextField!
  46. @IBOutlet weak var reverseXBox: NSView!
  47. @IBOutlet weak var reverseYBox: NSView!
  48. var reverseXVC: KMDesignButton?
  49. var reverseYVC: KMDesignButton?
  50. @IBOutlet weak var cropBox: NSBox!
  51. @IBOutlet weak var confirmBox: NSBox!
  52. @IBOutlet weak var cancelBox: NSBox!
  53. @IBOutlet weak var replaceBox: NSBox!
  54. @IBOutlet weak var exportBox: NSBox!
  55. @IBOutlet weak var opacityBoxHeight: NSLayoutConstraint!
  56. @IBOutlet weak var buttonBoxHeight: NSLayoutConstraint!
  57. @IBOutlet weak var buttonBox: NSBox!
  58. @IBOutlet weak var alignmentView: KMEditPropertyAlignmentView!
  59. @IBOutlet weak var alignmentViewTopConstraint: NSLayoutConstraint!
  60. //NO Image
  61. @IBOutlet weak var noImageView: NSImageView!
  62. @IBOutlet weak var noTitleLabel: NSTextField!
  63. @IBOutlet weak var noSubtitleLabel: NSTextField!
  64. @IBOutlet weak var noBackgroundView: NSView!
  65. var rotateLeftVC: KMDesignPropertySelector?
  66. var rotateRightVC: KMDesignPropertySelector?
  67. var flipHorizontalVC: KMDesignPropertySelector?
  68. var flipVerticalVC: KMDesignPropertySelector?
  69. var opacityVC: KMDesignSelect?
  70. @IBOutlet weak var toolsTitleLabel: NSTextField!
  71. var cropVC: KMDesignButton?
  72. var confirmVC: KMDesignButton?
  73. var cancelVC: KMDesignButton?
  74. var replaceVC: KMDesignButton?
  75. var exportVC: KMDesignButton?
  76. var imagesAreas : [CPDFEditImageArea] = []
  77. var listView : CPDFListView!
  78. var editingAreas: [Any] {
  79. get {
  80. return self.listView.editingAreas() ?? []
  81. }
  82. }
  83. weak var delegate: KMEditImagePropertyViewControllerDelegate?
  84. weak var handdler: KMEditPDfHanddler?
  85. deinit {
  86. KMPrint("KMEditImagePropertyViewController deinit.")
  87. self.removeNotification()
  88. }
  89. override func viewDidLoad() {
  90. super.viewDidLoad()
  91. self.setup()
  92. self.initData()
  93. self.updateLanguage()
  94. self.updateButtonState(hidden: true)
  95. self.reloadData()
  96. self.addNotification()
  97. self.updateUI()
  98. }
  99. func initData() {
  100. self.updateButtonState(hidden: true)
  101. }
  102. func setup() {
  103. self.titleLabel.font = NSFont.SFProTextSemiboldFont(14.0)
  104. self.titleLabel.textColor = KMAppearance.Layout.h0Color()
  105. self.opacityTitleLabel.font = NSFont.SFProTextSemiboldFont(12.0)
  106. self.opacityTitleLabel.textColor = KMAppearance.Layout.h0Color()
  107. self.whTitleLabel.stringValue = NSLocalizedString("Size", comment: "")
  108. self.wTextFieldItemView.backgroundView.wantsLayer = true
  109. self.wTextFieldItemView.backgroundView.layer?.backgroundColor = .white
  110. self.wTextFieldItemView.backgroundView.layer?.borderWidth = 1
  111. self.wTextFieldItemView.backgroundView.layer?.borderColor = NSColor(hex: "#DFE1E5").cgColor
  112. self.wTextFieldItemView.backgroundView.layer?.cornerRadius = 4
  113. self.wTextFieldItemView.delegate = self
  114. self.wTextFieldItemView.offset = 8
  115. self.wTextFieldItemView.rightViewMode = .always
  116. let wRightView = NSView()
  117. wRightView.frame = NSMakeRect(0, 0, 24, 32)
  118. let wIv = NSImageView()
  119. wIv.frame = NSMakeRect(0, 8, 16, 16)
  120. wIv.image = NSImage(named: "KMImageNameEditPDFWidthIcon")
  121. wRightView.addSubview(wIv)
  122. self.wTextFieldItemView.rightView = wRightView
  123. var formatter = NumberFormatter()
  124. formatter.numberStyle = .decimal
  125. // formatter.maximum = NSNumber(value: 999)
  126. // formatter.minimum = NSNumber(value: 1)
  127. self.wTextFieldItemView.textFiled.formatter = formatter
  128. self.hTextFieldItemView.backgroundView.wantsLayer = true
  129. self.hTextFieldItemView.backgroundView.layer?.backgroundColor = .white
  130. self.hTextFieldItemView.backgroundView.layer?.borderWidth = 1
  131. self.hTextFieldItemView.backgroundView.layer?.borderColor = NSColor(hex: "#DFE1E5").cgColor
  132. self.hTextFieldItemView.backgroundView.layer?.cornerRadius = 4
  133. self.hTextFieldItemView.delegate = self
  134. self.hTextFieldItemView.textFiled.formatter = formatter
  135. let hRightView = NSView()
  136. hRightView.frame = NSMakeRect(0, 0, 24, 32)
  137. let hIv = NSImageView()
  138. hIv.frame = NSMakeRect(0, 8, 16, 16)
  139. hIv.image = NSImage(named: "KMImageNameEditPDFHeightIcon")
  140. hRightView.addSubview(hIv)
  141. self.hTextFieldItemView.rightView = hRightView
  142. self.hTextFieldItemView.rightViewMode = .always
  143. self.alignmentView.didChange = {[unowned self] view, areasArray, boundsArray in
  144. self.changeAreasAlign(areas: areasArray, newBounds: boundsArray)
  145. }
  146. self.whVC = KMDesignButton(withType: .Image)
  147. self.whBox.contentView = self.whVC?.view
  148. self.whBox.borderWidth = 0
  149. self.whVC?.target = self
  150. self.whVC?.action = #selector(whAction)
  151. self.whVC?.image = NSImage(named: "KMImageNameEditPDFWhExchange")!
  152. self.whVC?.image_act = NSImage(named: "KMImageNameEditPDFWhExchangeSelected")!
  153. self.whVC?.pagination()
  154. whVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  155. whVC?.borderColor_act = KMAppearance.Interactive.s0Color()
  156. whVC?.borderColor_disabled = KMAppearance.Interactive.s0Color()
  157. whVC?.cornerRadius = 4
  158. whVC?.cornerRadius_hov = 4
  159. whVC?.cornerRadius_act = 4
  160. whVC?.cornerRadius_disabled = 4
  161. whVC?.background_hov = KMAppearance.view_bg_dis_color()
  162. whVC?.background_focus = KMAppearance.Layout.l1Color()
  163. whVC?.background_act = KMAppearance.buttonSelectedColor()
  164. whVC?.background_disabled = KMAppearance.buttonDisabledColor()
  165. self.rotateTitleLabel.stringValue = NSLocalizedString("Rotate", comment: "")
  166. self.rotateTextFieldItemView.delegate = self
  167. self.rotateTextFieldItemView.enterKeyEndEdit = true
  168. self.leftRotateVC = KMDesignButton(withType: .Image)
  169. self.leftRotateBox.contentView = self.leftRotateVC?.view
  170. self.leftRotateBox.borderWidth = 0
  171. self.leftRotateVC?.target = self
  172. self.leftRotateVC?.action = #selector(leftRotationImageAction)
  173. self.leftRotateVC?.image = NSImage(named: "KMImageNameEditPDFRotationLeft")!
  174. self.leftRotateVC?.pagination()
  175. leftRotateVC?.borderColor = KMAppearance.Interactive.s0Color()
  176. leftRotateVC?.background = KMAppearance.Layout.l1Color()
  177. leftRotateVC?.background_hov = KMAppearance.view_bg_dis_color()
  178. leftRotateVC?.background_focus = KMAppearance.Layout.l1Color()
  179. leftRotateVC?.textColor = KMAppearance.Layout.h1Color()
  180. leftRotateVC?.textColor_hov = KMAppearance.Layout.h1Color()
  181. leftRotateVC?.textColor_focus = KMAppearance.Layout.h1Color()
  182. leftRotateVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  183. leftRotateVC?.updateUI()
  184. self.rightRotateVC = KMDesignButton(withType: .Image)
  185. self.rightRotateBox.contentView = self.rightRotateVC?.view
  186. self.rightRotateBox.borderWidth = 0
  187. self.rightRotateVC?.target = self
  188. self.rightRotateVC?.action = #selector(rightRotationImageAction)
  189. self.rightRotateVC?.image = NSImage(named: "KMImageNameEditPDFRotationRight")!
  190. self.rightRotateVC?.pagination()
  191. rightRotateVC?.borderColor = KMAppearance.Interactive.s0Color()
  192. rightRotateVC?.background = KMAppearance.Layout.l1Color()
  193. rightRotateVC?.background_hov = KMAppearance.view_bg_dis_color()
  194. rightRotateVC?.background_focus = KMAppearance.Layout.l1Color()
  195. rightRotateVC?.textColor = KMAppearance.Layout.h1Color()
  196. rightRotateVC?.textColor_hov = KMAppearance.Layout.h1Color()
  197. rightRotateVC?.textColor_focus = KMAppearance.Layout.h1Color()
  198. rightRotateVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  199. rightRotateVC?.updateUI()
  200. opacityVC = KMDesignSelect.init(withType: .PopButton)
  201. opacityBox.contentView = opacityVC?.view
  202. opacityBox.fillColor = KMAppearance.Layout.bgDrakColor()
  203. opacityVC?.addItems(withObjectValues: ["25%","50%","75%","100%"])
  204. opacityVC?.selectItem(at: 0)
  205. opacityVC?.delete = self
  206. opacityVC?.borderColor = KMAppearance.Interactive.s0Color()
  207. opacityVC?.borderColor_disabled = KMAppearance.Interactive.s0Color()
  208. opacityVC?.background = KMAppearance.Layout.l1Color()
  209. opacityVC?.background_hov = KMAppearance.Layout.l1Color()
  210. opacityVC?.background_focus = KMAppearance.Layout.l1Color()
  211. opacityVC?.background_disabled = KMAppearance.Layout.l1Color()
  212. opacityVC?.textColor = KMAppearance.Layout.h1Color()
  213. opacityVC?.textColor_hov = KMAppearance.Layout.h1Color()
  214. opacityVC?.textColor_focus = KMAppearance.Layout.h1Color()
  215. opacityVC?.popViewControllerBackground = KMAppearance.Layout.bgColor()
  216. opacityVC?.popViewControllerTextColor = KMAppearance.Layout.h0Color()
  217. opacityVC?.popViewControllerEnterFillColor = KMAppearance.Interactive.s0Color()
  218. opacityVC?.updateUI()
  219. let customCell = CustomSliderCell()
  220. customCell.knobImage = NSImage(named: "KMImageNameEditPDFSlider")
  221. opacitySlider.cell = customCell
  222. opacitySlider.target = self
  223. opacitySlider.action = #selector(sliderValueChanged(_:))
  224. opacitySlider.isContinuous = false
  225. self.turnOverTitleLabel.stringValue = NSLocalizedString("Flip", comment: "")
  226. self.reverseXVC = KMDesignButton(withType: .Image)
  227. self.reverseXBox.addSubview(self.reverseXVC!.view)
  228. self.reverseXVC?.view.frame = self.reverseXBox.bounds
  229. self.reverseXVC?.view.autoresizingMask = [.width, .height]
  230. self.reverseXVC?.target = self
  231. self.reverseXVC?.action = #selector(flipHorizontalImageAction)
  232. self.reverseXVC?.image = NSImage(named: "KMImageNameEditPDFReverseX")!
  233. self.reverseXVC?.pagination()
  234. reverseXVC?.borderColor = KMAppearance.Interactive.s0Color()
  235. reverseXVC?.background = KMAppearance.Layout.l1Color()
  236. reverseXVC?.background_hov = KMAppearance.view_bg_dis_color()
  237. reverseXVC?.background_focus = KMAppearance.Layout.l1Color()
  238. reverseXVC?.textColor = KMAppearance.Layout.h1Color()
  239. reverseXVC?.textColor_hov = KMAppearance.Layout.h1Color()
  240. reverseXVC?.textColor_focus = KMAppearance.Layout.h1Color()
  241. reverseXVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  242. reverseXVC?.updateUI()
  243. self.reverseYVC = KMDesignButton(withType: .Image)
  244. self.reverseYBox.addSubview(self.reverseYVC!.view)
  245. self.reverseYVC?.view.frame = self.reverseXBox.bounds
  246. self.reverseYVC?.view.autoresizingMask = [.width, .height]
  247. self.reverseYVC?.target = self
  248. self.reverseYVC?.action = #selector(flipVerticalImageAction)
  249. self.reverseYVC?.image = NSImage(named: "KMImageNameEditPDFReverseY")!
  250. self.reverseYVC?.pagination()
  251. reverseYVC?.borderColor = KMAppearance.Interactive.s0Color()
  252. reverseYVC?.background = KMAppearance.Layout.l1Color()
  253. reverseYVC?.background_hov = KMAppearance.view_bg_dis_color()
  254. reverseYVC?.background_focus = KMAppearance.Layout.l1Color()
  255. reverseYVC?.textColor = KMAppearance.Layout.h1Color()
  256. reverseYVC?.textColor_hov = KMAppearance.Layout.h1Color()
  257. reverseYVC?.textColor_focus = KMAppearance.Layout.h1Color()
  258. reverseYVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  259. reverseYVC?.updateUI()
  260. self.toolsTitleLabel.stringValue = NSLocalizedString("Tools", comment: "")
  261. cropVC = KMDesignButton.init(withType: .Text)
  262. cropBox.contentView = cropVC?.view
  263. cropBox.fillColor = NSColor.clear
  264. cropVC?.target = self
  265. cropVC?.action = #selector(cutImageAction)
  266. cropVC?.button(type: .Sec, size: .m)
  267. cropVC?.stringValue = NSLocalizedString("Crop", comment: "")
  268. cropVC?.borderColor = KMAppearance.Interactive.s0Color()
  269. cropVC?.background = KMAppearance.Layout.l1Color()
  270. cropVC?.background_hov = KMAppearance.Layout.l1Color()
  271. cropVC?.background_focus = KMAppearance.Layout.l1Color()
  272. cropVC?.textColor = KMAppearance.Layout.h1Color()
  273. cropVC?.textColor_hov = KMAppearance.Layout.h1Color()
  274. cropVC?.textColor_focus = KMAppearance.Layout.h1Color()
  275. cropVC?.updateUI()
  276. confirmVC = KMDesignButton.init(withType: .Text)
  277. confirmBox.contentView = confirmVC?.view
  278. confirmBox.fillColor = NSColor.clear
  279. confirmVC?.target = self
  280. confirmVC?.action = #selector(confirmVCImageAction)
  281. confirmVC?.button(type: .Cta, size: .m)
  282. confirmVC?.stringValue = NSLocalizedString("Confirm", comment: "")
  283. confirmVC?.updateUI()
  284. cancelVC = KMDesignButton.init(withType: .Text)
  285. cancelBox.contentView = cancelVC?.view
  286. cancelBox.fillColor = NSColor.clear
  287. cancelVC?.target = self
  288. cancelVC?.action = #selector(cancelCutImageAction)
  289. cancelVC?.button(type: .Sec, size: .m)
  290. cancelVC?.stringValue = NSLocalizedString("Cancel", comment: "")
  291. cancelVC?.borderColor = KMAppearance.Interactive.s0Color()
  292. cancelVC?.background = KMAppearance.Layout.l1Color()
  293. cancelVC?.background_hov = KMAppearance.Layout.l1Color()
  294. cancelVC?.background_focus = KMAppearance.Layout.l1Color()
  295. cancelVC?.textColor = KMAppearance.Layout.h1Color()
  296. cancelVC?.textColor_hov = KMAppearance.Layout.h1Color()
  297. cancelVC?.textColor_focus = KMAppearance.Layout.h1Color()
  298. cancelVC?.updateUI()
  299. replaceVC = KMDesignButton.init(withType: .Text)
  300. replaceBox.contentView = replaceVC?.view
  301. replaceBox.fillColor = NSColor.clear
  302. replaceVC?.target = self
  303. replaceVC?.action = #selector(replaceImageAction)
  304. replaceVC?.button(type: .Sec, size: .m)
  305. replaceVC?.stringValue = NSLocalizedString("Replace", comment: "")
  306. replaceVC?.borderColor = KMAppearance.Interactive.s0Color()
  307. replaceVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  308. replaceVC?.borderColor_disabled = KMAppearance.Interactive.s0Color()
  309. replaceVC?.background = KMAppearance.Layout.l1Color()
  310. replaceVC?.background_hov = KMAppearance.Layout.l1Color()
  311. replaceVC?.background_focus = KMAppearance.Layout.l1Color()
  312. replaceVC?.background_disabled = KMAppearance.Layout.l1Color()
  313. replaceVC?.textColor = KMAppearance.Layout.h1Color()
  314. replaceVC?.textColor_hov = KMAppearance.Layout.h1Color()
  315. replaceVC?.textColor_focus = KMAppearance.Layout.h1Color()
  316. replaceVC?.updateUI()
  317. exportVC = KMDesignButton.init(withType: .Text)
  318. exportBox.contentView = exportVC?.view
  319. exportBox.fillColor = NSColor.clear
  320. exportVC?.target = self
  321. exportVC?.action = #selector(exportImageAction)
  322. exportVC?.button(type: .Sec, size: .m)
  323. exportVC?.stringValue = NSLocalizedString("Export", comment: "")
  324. exportVC?.borderColor = KMAppearance.Interactive.s0Color()
  325. exportVC?.borderColor_hov = KMAppearance.Interactive.s0Color()
  326. exportVC?.borderColor_disabled = KMAppearance.Interactive.s0Color()
  327. exportVC?.background = KMAppearance.Layout.l1Color()
  328. exportVC?.background_hov = KMAppearance.Layout.l1Color()
  329. exportVC?.background_focus = KMAppearance.Layout.l1Color()
  330. exportVC?.background_disabled = KMAppearance.Layout.l1Color()
  331. exportVC?.textColor = KMAppearance.Layout.h1Color()
  332. exportVC?.textColor_hov = KMAppearance.Layout.h1Color()
  333. exportVC?.textColor_focus = KMAppearance.Layout.h1Color()
  334. exportVC?.updateUI()
  335. self.noTitleLabel.textColor = KMAppearance.Layout.h1Color()
  336. self.noTitleLabel.font = NSFont.SFProTextRegularFont(14)
  337. self.noImageView.image = NSImage(named: "No_addimage")
  338. self.noImageView.alphaValue = 0.4
  339. let string = self.noSubtitleLabel.stringValue
  340. let paragraphStyle = NSMutableParagraphStyle()
  341. paragraphStyle.lineHeightMultiple = 1.32
  342. paragraphStyle.alignment = .center
  343. self.noSubtitleLabel.attributedStringValue = NSMutableAttributedString(string: NSLocalizedString(string, comment: ""), attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle, .foregroundColor : NSColor.km_init(hex: "#94989C"), NSAttributedString.Key.font: NSFont.SFProTextRegularFont(12.0)])
  344. self.noBackgroundView.backgroundColor(NSColor.km_init(hex: "#F7F8FA"))
  345. }
  346. func addNotification() {
  347. NotificationCenter.default.addObserver(self, selector: #selector(changeEffectiveAppearance), name: NSNotification.Name(rawValue: "kEffectiveAppearance"), object: nil)
  348. }
  349. func removeNotification() {
  350. NotificationCenter.default.removeObserver(self)
  351. DistributedNotificationCenter.default().removeObserver(self)
  352. }
  353. @objc func changeEffectiveAppearance() {
  354. let isDarkModel = KMAdvertisementConfig.isDarkModel()
  355. if isDarkModel {
  356. self.view.appearance = NSAppearance(named: .darkAqua)
  357. } else {
  358. self.view.appearance = NSAppearance(named: .aqua)
  359. }
  360. self.updateUI()
  361. }
  362. func updateUI() {
  363. let isDarkModel = KMAdvertisementConfig.isDarkModel()
  364. if isDarkModel {
  365. self.backgroundView.backgroundColor(NSColor.km_init(hex: "#252526"))
  366. self.noBackgroundView.backgroundColor(NSColor.km_init(hex: "#252526"))
  367. } else {
  368. self.backgroundView.backgroundColor(NSColor.km_init(hex: "#FAFAFA"))
  369. self.noBackgroundView.backgroundColor(NSColor.km_init(hex: "#F7F8FA"))
  370. }
  371. for label in [self.whTitleLabel, self.opacityTitleLabel,
  372. self.turnOverTitleLabel] {
  373. label?.font = NSFont.SFProTextSemiboldFont(12.0)
  374. label?.textColor = NSColor.km_init(hex: "#616469")
  375. }
  376. }
  377. func updateLanguage() {
  378. let areas = self.editingAreas
  379. if imagesAreas.count > 0 && imagesAreas.count != areas.count { //多选图片跟文字
  380. self.titleLabel.stringValue = NSLocalizedString("General Properties", comment: "")
  381. } else {
  382. self.titleLabel.stringValue = NSLocalizedString("Image", comment: "")
  383. }
  384. self.noTitleLabel.stringValue = NSLocalizedString("Add Image", comment: "")
  385. self.opacityTitleLabel.stringValue = NSLocalizedString("Opacity", comment: "")
  386. self.cropVC?.stringValue = NSLocalizedString("Crop", comment: "")
  387. self.confirmVC?.stringValue = NSLocalizedString("Confirm", comment: "")
  388. self.cancelVC?.stringValue = NSLocalizedString("Cancel", comment: "")
  389. self.replaceVC?.stringValue = NSLocalizedString("Replace", comment: "")
  390. self.exportVC?.stringValue = NSLocalizedString("Export", comment: "")
  391. }
  392. func reloadData() {
  393. imagesAreas = []
  394. if self.editingAreas.count > 0 {
  395. self.noBackgroundView.isHidden = true
  396. let areas = self.editingAreas
  397. self.alignmentView.editingAreas = areas
  398. for i in 0 ... areas.count-1 {
  399. if areas[i] is CPDFEditImageArea {
  400. imagesAreas.append(areas[i] as! CPDFEditImageArea)
  401. }
  402. }
  403. if imagesAreas.count == 1 && imagesAreas.count == areas.count{ //单个图片
  404. self.listView.selectImageAreas = imagesAreas.first
  405. self.headerBox.isHidden = false
  406. self.headerBoxHeight.constant = 176
  407. self.opacityBox.isHidden = false
  408. self.opacityBoxHeight.constant = 56
  409. self.opacityBoxBottomMaginConstraint.constant = 66
  410. self.opacityBoxTopConstraint.constant = 16
  411. self.buttonBox.isHidden = false
  412. self.buttonBoxHeight.constant = 112+16+8
  413. self.alignmentViewTopConstraint.constant = 16
  414. let opacity: CGFloat = self.listView.opacity(for: imagesAreas.first)
  415. self.updateImageAreasOpacity(opacity: opacity, state: .ended, needListView: false)
  416. self.turnOverBox.isHidden = false
  417. self.opacityTitleLabel.isHidden = false
  418. self.whVC?.state = .Norm
  419. self.cropVC?.state = .Norm
  420. } else if imagesAreas.count > 1 && imagesAreas.count == areas.count { //多选图片
  421. self.headerBox.isHidden = false
  422. self.headerBoxHeight.constant = 176
  423. self.opacityBox.isHidden = false
  424. self.opacityBoxHeight.constant = 56
  425. self.opacityBoxBottomMaginConstraint.constant = 66
  426. self.opacityBoxTopConstraint.constant = 0
  427. self.buttonBox.isHidden = false
  428. self.buttonBoxHeight.constant = 112+16+8
  429. self.alignmentViewTopConstraint.constant = 16
  430. var opacity = self.listView.opacity(for: imagesAreas.first)
  431. for area in imagesAreas {
  432. let newOpacity = self.listView.opacity(for: area)
  433. if (opacity < newOpacity) {
  434. opacity = newOpacity
  435. }
  436. }
  437. self.updateImageAreasOpacity(opacity: opacity, state: .ended, needListView: false)
  438. self.turnOverBox.isHidden = false
  439. self.opacityTitleLabel.isHidden = false
  440. self.whVC?.state = .Disabled
  441. self.cropVC?.state = .Disabled
  442. if let data = self.handdler?.editAreasOpacityIsEqual(), data {
  443. self.opacitySlider.isEnabled = true
  444. self.opacityVC?.state = .Norm
  445. } else {
  446. self.opacitySlider.isEnabled = false
  447. self.opacityVC?.state = .Disabled
  448. }
  449. } else if imagesAreas.count > 0 && imagesAreas.count != areas.count { //多选图片跟文字
  450. self.opacityBoxBottomMaginConstraint.constant = 8
  451. self.alignmentViewTopConstraint.constant = 0
  452. self.opacityBoxTopConstraint.constant = 0
  453. self.headerBoxHeight.constant = 40
  454. self.opacityBox.isHidden = true
  455. self.opacityBoxHeight.constant = 0
  456. self.buttonBox.isHidden = true
  457. self.buttonBoxHeight.constant = 0
  458. self.turnOverBox.isHidden = true
  459. self.opacityTitleLabel.isHidden = true
  460. }
  461. self.updateLanguage()
  462. } else {
  463. self.noBackgroundView.isHidden = false
  464. }
  465. self.updateWHData()
  466. self.updateRotateData()
  467. }
  468. func updateButtonState(hidden: Bool) {
  469. if hidden {
  470. self.cancelBox.isHidden = true
  471. self.confirmBox.isHidden = true
  472. self.cropBox.isHidden = false
  473. self.replaceVC?.enabled = true
  474. self.exportVC?.enabled = true
  475. self.opacitySlider.isEnabled = true
  476. self.opacityVC?.enabled = true
  477. self.rotateLeftVC?.button.isEnabled = true
  478. self.rotateLeftVC?.view.alphaValue = 1.0
  479. self.rotateRightVC?.button.isEnabled = true
  480. self.rotateRightVC?.view.alphaValue = 1.0
  481. self.flipVerticalVC?.button.isEnabled = true
  482. self.flipVerticalVC?.view.alphaValue = 1.0
  483. self.flipHorizontalVC?.button.isEnabled = true
  484. self.flipHorizontalVC?.view.alphaValue = 1.0
  485. self.wTextFieldItemView.textFiled.isEnabled = true
  486. self.hTextFieldItemView.textFiled.isEnabled = true
  487. self.whVC?.state = .Norm
  488. self.rotateTextFieldItemView.state = .Norm
  489. self.rotateTextFieldItemView.kmEnabled = true
  490. self.leftRotateVC?.state = .Norm
  491. self.rightRotateVC?.state = .Norm
  492. self.reverseXVC?.state = .Norm
  493. self.reverseYVC?.state = .Norm
  494. self.leftRotateVC?.button.isEnabled = true
  495. self.rightRotateVC?.button.isEnabled = true
  496. self.reverseXVC?.button.isEnabled = true
  497. self.reverseYVC?.button.isEnabled = true
  498. } else {
  499. self.cancelBox.isHidden = false
  500. self.confirmBox.isHidden = false
  501. self.cropBox.isHidden = true
  502. self.replaceVC?.enabled = false
  503. self.exportVC?.enabled = false
  504. self.opacitySlider.isEnabled = false
  505. self.opacityVC?.enabled = false
  506. self.rotateLeftVC?.button.isEnabled = false
  507. self.rotateLeftVC?.view.alphaValue = 0.5
  508. self.rotateRightVC?.button.isEnabled = false
  509. self.rotateRightVC?.view.alphaValue = 0.5
  510. self.flipVerticalVC?.button.isEnabled = false
  511. self.flipVerticalVC?.view.alphaValue = 0.5
  512. self.flipHorizontalVC?.button.isEnabled = false
  513. self.flipHorizontalVC?.view.alphaValue = 0.5
  514. self.wTextFieldItemView.textFiled.isEnabled = false
  515. self.hTextFieldItemView.textFiled.isEnabled = false
  516. self.whVC?.state = .Disabled
  517. self.rotateTextFieldItemView.state = .Disabled
  518. self.rotateTextFieldItemView.kmEnabled = false
  519. self.leftRotateVC?.state = .Disabled
  520. self.rightRotateVC?.state = .Disabled
  521. self.reverseXVC?.state = .Disabled
  522. self.reverseYVC?.state = .Disabled
  523. self.leftRotateVC?.button.isEnabled = false
  524. self.rightRotateVC?.button.isEnabled = false
  525. self.reverseXVC?.button.isEnabled = false
  526. self.reverseYVC?.button.isEnabled = false
  527. }
  528. self.reloadData()
  529. }
  530. func updateWHData() {
  531. if let data = self.handdler?.editAreasBoundsIsEqualForWidth(), data {
  532. let areaFrame = self.handdler?.editingAreas.first?.bounds ?? .zero
  533. self.wTextFieldItemView.stringValue = String(format: "%.1f", areaFrame.size.width)
  534. } else {
  535. self.wTextFieldItemView.stringValue = "--"
  536. }
  537. if let data = self.handdler?.editAreasBoundsIsEqualForHeight(), data {
  538. let areaFrame = self.handdler?.editingAreas.first?.bounds ?? .zero
  539. self.hTextFieldItemView.stringValue = String(format: "%.1f", areaFrame.size.height)
  540. } else {
  541. self.hTextFieldItemView.stringValue = "--"
  542. }
  543. }
  544. func updateRotateData() {
  545. if let data = self.handdler?.editAreasRotateIsEqual(), data {
  546. let area = self.handdler?.editingImageAreas.first
  547. let rotate = self.listView.getRotateWith(area)
  548. let stringValue = self.rotateTextFieldItemView.stringValue?.replacingOccurrences(of: "°", with: "")
  549. let number = NSNumber(value: rotate)
  550. let formatter = NumberFormatter()
  551. let string = formatter.string(for: number)
  552. self.rotateTextFieldItemView.stringValue = "\(string ?? "0") °"
  553. } else {
  554. self.rotateTextFieldItemView.stringValue = "--"
  555. }
  556. }
  557. func updateImageAreasOpacity(opacity: CGFloat, state: KMOperationState, needListView: Bool = true) {
  558. if self.editingAreas.count >= 1 {
  559. if needListView {
  560. for area in imagesAreas {
  561. self.listView.setOpacityEditArea(area, opacity: opacity)
  562. }
  563. }
  564. // self.listView.editingAreas()!.count == 1 &&
  565. if (self.listView.editingAreas()?.first is CPDFEditImageArea) {
  566. self.listView.selectImageAreas = self.listView.editingAreas()!.first as? CPDFEditImageArea
  567. // self.editImageView.image = self.listView.selectImageAreas.thumbnailImage
  568. self.opacitySlider.objectValue = self.listView.opacity(for: self.listView.selectImageAreas)
  569. self.opacityVC?.stringValue = Int(opacity * 100).description + "%"
  570. // self.editImageView.alphaValue = opacity
  571. }
  572. }
  573. }
  574. private func changeAreasAlign(areas:[Any],newBounds:[String]) {
  575. var oldBounds : [String] = []
  576. for i in 0 ... areas.count-1 {
  577. let area : CPDFEditArea = areas[i] as! CPDFEditArea
  578. oldBounds.append(NSStringFromRect(area.bounds))
  579. self.listView.setBoundsEditArea(area, withBounds: NSRectFromString(newBounds[i]))
  580. }
  581. self.listView.setNeedsDisplayForVisiblePages()
  582. }
  583. }
  584. //MARK: - Action
  585. extension KMEditImagePropertyViewController {
  586. @objc func sliderValueChanged(_ sender: NSSlider) {
  587. let sliderValue = sender.floatValue
  588. self.updateImageAreasOpacity(opacity:CGFloat(sliderValue), state: .changed)
  589. }
  590. @objc func whAction(_ sender: AnyObject) {
  591. let state = self.whVC?.state ?? .None
  592. if state == .Disabled {
  593. return
  594. }
  595. if state == .Act {
  596. self.whVC?.state = .Norm
  597. self.whVC?.button.toolTip = NSLocalizedString("", comment: "")
  598. } else {
  599. self.whVC?.state = .Act
  600. self.whVC?.toolTip = NSLocalizedString("Constrain Proportions", comment: "")
  601. }
  602. }
  603. @IBAction func rightRotationImageAction(_ sender: Any) {
  604. if self.listView.editingAreas()?.count ?? 0 < 1 {
  605. return
  606. }
  607. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageEdit", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageEdit_Rotate"])
  608. let areas = self.listView.editingAreas()
  609. if areas!.count == 1 && (areas!.first is CPDFEditImageArea) {
  610. let imageArea = areas!.first as! CPDFEditImageArea
  611. self.listView.rotate(with: imageArea, rotate: 90)
  612. self.listView.selectImageAreas = imageArea
  613. // self.editImageView.image = self.listView.selectImageAreas.thumbnailImage
  614. } else if areas!.count > 1 {
  615. for imagesArea in imagesAreas {
  616. self.listView.rotate(with: imagesArea, rotate: 90)
  617. }
  618. }
  619. self.delegate?.editImagePropertyViewControllerDidChanged(controller: self, type: .rotate)
  620. }
  621. @IBAction func leftRotationImageAction(_ sender: Any) {
  622. if self.listView.editingAreas()?.count ?? 0 < 1 {
  623. return
  624. }
  625. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageEdit", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageEdit_Rotate"])
  626. let areas = self.listView.editingAreas()
  627. if areas!.count == 1 && (areas!.first is CPDFEditImageArea) {
  628. self.listView.rotate(with: self.listView.selectImageAreas, rotate: -90)
  629. if self.listView.editingAreas()!.count == 1 && (self.listView.editingAreas()!.first is CPDFEditImageArea) {
  630. self.listView.selectImageAreas = self.listView.editingAreas()!.first as? CPDFEditImageArea
  631. }
  632. // self.editImageView.image = self.listView.selectImageAreas.thumbnailImage
  633. } else {
  634. for imagesArea in imagesAreas {
  635. self.listView.rotate(with: imagesArea, rotate: -90)
  636. }
  637. }
  638. self.delegate?.editImagePropertyViewControllerDidChanged(controller: self, type: .rotate)
  639. }
  640. @IBAction func flipHorizontalImageAction(_ sender: Any) {
  641. if self.listView.editingAreas()?.count ?? 0 < 1 {
  642. return
  643. }
  644. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageEdit", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageEdit_Reverse"])
  645. let areas = self.listView.editingAreas()
  646. if areas != nil {
  647. for item in areas! {
  648. if item is CPDFEditImageArea {
  649. self.listView.horizontalMirror(with: item as? CPDFEditImageArea)
  650. if areas?.count == 1 {
  651. // self.editImageView.image = (item as AnyObject).thumbnailImage
  652. }
  653. } else {
  654. for imagesArea in imagesAreas {
  655. self.listView.horizontalMirror(with: imagesArea)
  656. }
  657. }
  658. }
  659. }
  660. self.delegate?.editImagePropertyViewControllerDidChanged(controller: self, type: .flip)
  661. }
  662. @IBAction func flipVerticalImageAction(_ sender: Any) {
  663. if self.listView.editingAreas()?.count ?? 0 < 1 {
  664. return
  665. }
  666. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageEdit", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageEdit_Reverse"])
  667. let areas = self.listView.editingAreas()
  668. if areas != nil {
  669. for item in areas! {
  670. if item is CPDFEditImageArea {
  671. self.listView.verticalMirror(with: item as? CPDFEditImageArea)
  672. // self.editImageView.image = self.listView.selectImageAreas.thumbnailImage
  673. } else {
  674. for imagesArea in imagesAreas {
  675. self.listView.verticalMirror(with: imagesArea)
  676. }
  677. }
  678. }
  679. }
  680. self.delegate?.editImagePropertyViewControllerDidChanged(controller: self, type: .flip)
  681. }
  682. @IBAction func cutImageAction(_ sender: Any) {
  683. // selectImageAreas
  684. self.handdler?.cropAction()
  685. }
  686. @IBAction func confirmVCImageAction(_ sender: Any) {
  687. self.handdler?.cropComfirmAction()
  688. }
  689. @IBAction func cancelCutImageAction(_ sender: Any) {
  690. self.handdler?.cropCancelAction()
  691. }
  692. @IBAction func restoreCutImageAction(_ sender: Any) {
  693. if self.listView.selectImageAreas == nil {
  694. return
  695. }
  696. self.listView.resetCrop(with: self.listView.selectImageAreas)
  697. }
  698. @IBAction func replaceImageAction(_ sender: NSButton) {
  699. if self.listView.selectImageAreas == nil {
  700. return
  701. }
  702. FMTrackEventManager.defaultManager.trackEvent(event: "SubTbr_PageEdit", withProperties: ["SubTbr_Btn": "Btn_SubTbr_PageEdit_Replace"])
  703. self.handdler?.replaceAction()
  704. }
  705. @IBAction func exportImageAction(_ sender: Any) {
  706. self.handdler?.exportAction()
  707. }
  708. }
  709. // MARK: - KMSelectPopButtonDelegate
  710. extension KMEditImagePropertyViewController: KMSelectPopButtonDelegate {
  711. func km_comboBoxSelectionDidChange(_ obj: KMDesignSelect) {
  712. if obj == opacityVC {
  713. let index = obj.indexOfSelectedItem
  714. var string = obj.items[index]
  715. string = string.replacingOccurrences(of: "%", with: "")
  716. let value = CGFloat(Float(string)! * 0.01)
  717. self.updateImageAreasOpacity(opacity: value, state: .changed)
  718. }
  719. }
  720. func km_controlTextDidEndEditing(_ obj: KMDesignSelect) {
  721. if obj == opacityVC {
  722. let index = obj.indexOfSelectedItem
  723. var string = obj.items[index]
  724. string = string.replacingOccurrences(of: "%", with: "")
  725. let value = CGFloat(Float(string)! * 0.01)
  726. self.updateImageAreasOpacity(opacity: value, state: .ended)
  727. }
  728. }
  729. }
  730. // MARK: - KMTextFieldDelegate
  731. extension KMEditImagePropertyViewController: KMTextFieldDelegate {
  732. func km_didBecomeFirstResponder(textField: AnyObject) {
  733. if self.wTextFieldItemView.isEqual(to: textField) {
  734. self.wTextFieldItemView.backgroundView.layer?.backgroundColor = .white
  735. self.wTextFieldItemView.backgroundView.layer?.borderWidth = 1
  736. self.wTextFieldItemView.backgroundView.layer?.borderColor = NSColor(hex: "#4982E6").cgColor
  737. self.wTextFieldItemView.backgroundView.layer?.cornerRadius = 4
  738. } else if self.hTextFieldItemView.isEqual(to: textField) {
  739. self.hTextFieldItemView.backgroundView.layer?.borderColor = NSColor(hex: "#4982E6").cgColor
  740. }
  741. }
  742. func km_controlTextDidEndEditing(textField: AnyObject) {
  743. if self.wTextFieldItemView.isEqual(to: textField) {
  744. self.wTextFieldItemView.backgroundView.layer?.backgroundColor = .white
  745. self.wTextFieldItemView.backgroundView.layer?.borderWidth = 1
  746. self.wTextFieldItemView.backgroundView.layer?.borderColor = NSColor(hex: "#DFE1E5").cgColor
  747. self.wTextFieldItemView.backgroundView.layer?.cornerRadius = 4
  748. let value = self.wTextFieldItemView.stringValue?.stringToCGFloat() ?? 0
  749. let ss = String(format: "%.1f", value)
  750. self.wTextFieldItemView.stringValue = ss
  751. } else if self.hTextFieldItemView.isEqual(to: textField) {
  752. self.hTextFieldItemView.backgroundView.layer?.borderColor = NSColor(hex: "#DFE1E5").cgColor
  753. let value = self.hTextFieldItemView.stringValue?.stringToCGFloat() ?? 0
  754. let ss = String(format: "%.1f", value)
  755. self.hTextFieldItemView.stringValue = ss
  756. } else if self.rotateTextFieldItemView.isEqual(to: textField) {
  757. let stringValue = self.rotateTextFieldItemView.stringValue?.replacingOccurrences(of: "°", with: "")
  758. let formatter = NumberFormatter()
  759. let number = NSNumber(value: Int(stringValue ?? "") ?? 0)
  760. let string = formatter.string(for: number)
  761. self.rotateTextFieldItemView.stringValue = "\(string ?? "0") °"
  762. let areas = self.handdler?.editingImageAreas ?? []
  763. for area in areas {
  764. let rotate = self.listView.getRotateWith(area)
  765. let rotate2 = string?.stringToCGFloat() ?? 0
  766. let offset = rotate2-rotate
  767. if offset != 0 {
  768. self.listView.rotate(with: area, rotate: offset)
  769. }
  770. }
  771. }
  772. }
  773. func km_controlTextDidChange(textField: AnyObject) {
  774. if self.wTextFieldItemView.isEqual(to: textField) {
  775. let number = NSNumber(value: Int(self.wTextFieldItemView.stringValue ?? "") ?? 0)
  776. let string = self.wTextFieldItemView.textFiled.formatter?.string(for: number)
  777. self.wTextFieldItemView.stringValue = string ?? ""
  778. let areas = self.handdler?.editingImageAreas ?? []
  779. self.listView.editAreaBoundUpdating = true
  780. for area in areas {
  781. let state = self.whVC?.state ?? .None
  782. var bounds = area.bounds
  783. let width = string?.stringToCGFloat() ?? 0
  784. if width == 0 {
  785. return
  786. }
  787. // bounds.origin.x = max(0, bounds.origin.x-width*0.5)
  788. if state == .Act { // 寛高约束
  789. var scale: CGFloat = 0
  790. if bounds.size.width != 0 {
  791. scale = width / bounds.size.width
  792. }
  793. bounds.size.height *= scale
  794. bounds.size.width = width
  795. let value = String(format: "%.1f", bounds.size.height)
  796. self.hTextFieldItemView.stringValue = value
  797. } else {
  798. bounds.size.width = width
  799. }
  800. self.listView.setBoundsEditArea(area, withBounds: bounds)
  801. }
  802. } else if self.hTextFieldItemView.isEqual(to: textField) {
  803. let number = NSNumber(value: Int(self.hTextFieldItemView.stringValue ?? "") ?? 0)
  804. let string = self.hTextFieldItemView.textFiled.formatter?.string(for: number)
  805. self.hTextFieldItemView.stringValue = string ?? ""
  806. // let areas = self.listView?.editingAreas() as? [CPDFEditArea] ?? []
  807. let areas = self.handdler?.editingImageAreas ?? []
  808. self.listView.editAreaBoundUpdating = true
  809. for area in areas {
  810. // if let area = areas.first as? CPDFEditImageArea {
  811. let state = self.whVC?.state ?? .None
  812. var bounds = area.bounds
  813. let height = string?.stringToCGFloat() ?? 0
  814. if height == 0 {
  815. return
  816. }
  817. if state == .Act { // 寛高约束
  818. var scale: CGFloat = 0
  819. if bounds.size.height != 0 {
  820. scale = height / bounds.size.height
  821. }
  822. bounds.size.width *= scale
  823. bounds.size.height = height
  824. let value = String(format: "%.1f", bounds.size.width)
  825. self.wTextFieldItemView.stringValue = value
  826. } else {
  827. bounds.size.height = height
  828. }
  829. self.listView.setBoundsEditArea(area, withBounds: bounds)
  830. }
  831. } else if self.rotateTextFieldItemView.isEqual(to: textField) {
  832. // let stringValue = self.rotateTextFieldItemView.stringValue
  833. // let number = NSNumber(value: Int(stringValue ?? "") ?? 0)
  834. // let formatter = NumberFormatter()
  835. // let string = formatter.string(for: stringValue)
  836. // let string = self.rotateTextFieldItemView.kFormatter?.string(for: number)
  837. // self.rotateTextFieldItemView.stringValue = string
  838. }
  839. }
  840. }
  841. class CustomSliderCell: NSSliderCell {
  842. var knobImage: NSImage?
  843. override func drawKnob(_ knobRect: NSRect) {
  844. if let image = knobImage {
  845. let imageSize = NSSize(width: knobRect.size.height, height: knobRect.size.height)
  846. let imageRect = NSRect(origin: knobRect.origin, size: imageSize)
  847. image.draw(in: imageRect)
  848. } else {
  849. super.drawKnob(knobRect)
  850. }
  851. }
  852. }