KMLineWell.swift 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. //
  2. // KMLineWell.swift
  3. // PDF Master
  4. //
  5. // Created by tangchao on 2023/11/6.
  6. //
  7. import Cocoa
  8. private let SKPasteboardTypeLineStyle = "net.sourceforge.skim-app.pasteboard.line-style"
  9. private let SKLineWellLineWidthKey = "lineWidth"
  10. private let SKLineWellStyleKey = "style"
  11. private let SKLineWellDashPatternKey = "dashPattern"
  12. private let SKLineWellStartLineStyleKey = "startLineStyle"
  13. private let SKLineWellEndLineStyleKey = "endLineStyle"
  14. private let ACTION_KEY = "action"
  15. private let TARGET_KEY = "target"
  16. private let DISPLAYSTYLE_KEY = "lwFlagsdisplayStyle"
  17. private let ACTIVE_KEY = "active"
  18. private let SKLineWellWillBecomeActiveNotification = "SKLineWellWillBecomeActiveNotification"
  19. private let EXCLUSIVE_KEY = "exclusive"
  20. enum KMLineWellDisplayStyle: Int {
  21. case line = 0
  22. case simpleLine
  23. case rectangle
  24. case oval
  25. }
  26. class KMLineWell: NSControl {
  27. public static let widthKey = SKLineWellLineWidthKey
  28. public static let styleKey = SKLineWellStyleKey
  29. public static let dashPatternKey = SKLineWellDashPatternKey
  30. public static let startLineStyleKey = SKLineWellStartLineStyleKey
  31. public static let endLineStyleKey = SKLineWellEndLineStyleKey
  32. private var _lineWidth: CGFloat = 2
  33. var lineWidth: CGFloat {
  34. get {
  35. return self._lineWidth
  36. }
  37. set {
  38. if (fabs(self._lineWidth - newValue) > 0.00001) {
  39. self._lineWidth = newValue
  40. self._changedValue(forKey: SKLineWellLineWidthKey)
  41. }
  42. }
  43. }
  44. private var _style: CPDFBorderStyle = .solid
  45. var style: CPDFBorderStyle {
  46. get {
  47. return self._style
  48. }
  49. set {
  50. if (newValue != self._style) {
  51. self._style = newValue
  52. self._changedValue(forKey: SKLineWellStyleKey)
  53. }
  54. }
  55. }
  56. private var _startLineStyle: CPDFLineStyle = .none
  57. var startLineStyle: CPDFLineStyle {
  58. get {
  59. return self._startLineStyle
  60. }
  61. set {
  62. if (newValue != self._startLineStyle) {
  63. self._startLineStyle = newValue
  64. self._changedValue(forKey: SKLineWellStartLineStyleKey)
  65. }
  66. }
  67. }
  68. private var _endLineStyle: CPDFLineStyle = .none
  69. var endLineStyle: CPDFLineStyle {
  70. get {
  71. return self._endLineStyle
  72. }
  73. set {
  74. if (newValue != self._endLineStyle) {
  75. self._endLineStyle = newValue
  76. self._changedValue(forKey: SKLineWellEndLineStyleKey)
  77. }
  78. }
  79. }
  80. private var _dashPattern: NSArray?
  81. var dashPattern: NSArray? {
  82. get {
  83. return self._dashPattern
  84. }
  85. set {
  86. var _pattern: NSArray? = newValue
  87. if (NSIsControllerMarker(_pattern)) {
  88. _pattern = nil
  89. }
  90. if _pattern?.isEqual(to: self._dashPattern) == false && _pattern != nil || self._dashPattern != nil {
  91. self._dashPattern = _pattern
  92. self._changedValue(forKey: SKLineWellDashPatternKey)
  93. }
  94. }
  95. }
  96. var displayStyle: KMLineWellDisplayStyle {
  97. get {
  98. return KMLineWellDisplayStyle(rawValue: Int(__lwFlags.displayStyle)) ?? .line
  99. }
  100. set {
  101. if __lwFlags.displayStyle != newValue.rawValue {
  102. __lwFlags.displayStyle = UInt8(newValue.rawValue)
  103. self.needsDisplay = true
  104. }
  105. }
  106. }
  107. private struct _lwFlags {
  108. var displayStyle: UInt8 = 0
  109. var active = false
  110. var canActivate = false
  111. var existsActiveLineWell: UInt8 = 0
  112. var highlighted: Bool = false
  113. }
  114. private var __lwFlags = _lwFlags()
  115. /*
  116. - (void)lineInspectorLineAttributeChanged:(NSNotification *)notification;
  117. */
  118. var canActivate: Bool {
  119. get {
  120. return __lwFlags.canActivate
  121. }
  122. set {
  123. if __lwFlags.canActivate != newValue {
  124. __lwFlags.canActivate = newValue
  125. if self.isActive && __lwFlags.canActivate == false {
  126. self._deactivate()
  127. }
  128. }
  129. }
  130. }
  131. var isActive: Bool {
  132. get {
  133. return __lwFlags.active
  134. }
  135. }
  136. override var isHighlighted: Bool {
  137. get {
  138. return self.__lwFlags.highlighted
  139. }
  140. set {
  141. if self.__lwFlags.highlighted != newValue {
  142. self.__lwFlags.highlighted = newValue
  143. }
  144. }
  145. }
  146. deinit {
  147. KMPrint("KMLineWell deinit.")
  148. NotificationCenter.default.removeObserver(self)
  149. }
  150. override init(frame frameRect: NSRect) {
  151. super.init(frame: frameRect)
  152. lineWidth = 1.0
  153. style = .solid
  154. dashPattern = nil;
  155. startLineStyle = .none
  156. endLineStyle = .none
  157. __lwFlags.displayStyle = UInt8(KMLineWellDisplayStyle.line.rawValue)
  158. __lwFlags.active = false
  159. __lwFlags.canActivate = false
  160. __lwFlags.existsActiveLineWell = 0
  161. self.target = nil
  162. self.action = nil
  163. self._commonInit()
  164. }
  165. required init?(coder: NSCoder) {
  166. super.init(coder: coder)
  167. lineWidth = coder.decodeDouble(forKey: SKLineWellLineWidthKey)
  168. style = CPDFBorderStyle(rawValue: coder.decodeInteger(forKey: SKLineWellStyleKey)) ?? .solid
  169. dashPattern = coder.decodeObject(forKey: SKLineWellDashPatternKey) as? NSArray
  170. startLineStyle = CPDFLineStyle(rawValue: coder.decodeInteger(forKey: SKLineWellStartLineStyleKey)) ?? .none
  171. endLineStyle = CPDFLineStyle(rawValue: coder.decodeInteger(forKey: SKLineWellEndLineStyleKey)) ?? .none
  172. __lwFlags.displayStyle = UInt8(coder.decodeInteger(forKey: DISPLAYSTYLE_KEY))
  173. __lwFlags.active = coder.decodeBool(forKey: ACTIVE_KEY)
  174. action = NSSelectorFromString(coder.decodeObject(forKey: ACTION_KEY) as? String ?? "")
  175. target = coder.decodeObject(forKey: TARGET_KEY) as AnyObject?
  176. self._commonInit()
  177. }
  178. override func encode(with coder: NSCoder) {
  179. super.encode(with: coder)
  180. coder.encode(lineWidth, forKey: SKLineWellLineWidthKey)
  181. coder.encode(style.rawValue, forKey: SKLineWellStyleKey)
  182. coder.encode(dashPattern, forKey: SKLineWellDashPatternKey)
  183. coder.encode(startLineStyle.rawValue, forKey: SKLineWellStartLineStyleKey)
  184. coder.encode(endLineStyle.rawValue, forKey: SKLineWellEndLineStyleKey)
  185. coder.encode(__lwFlags.displayStyle, forKey: DISPLAYSTYLE_KEY)
  186. coder.encode(__lwFlags.active, forKey: ACTIVE_KEY)
  187. if let data = self.action {
  188. coder.encode(NSStringFromSelector(data), forKey: ACTION_KEY)
  189. }
  190. coder.encode(target, forKey: TARGET_KEY)
  191. }
  192. override var isOpaque: Bool {
  193. return true
  194. }
  195. override var acceptsFirstResponder: Bool {
  196. return self.canActivate
  197. }
  198. override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
  199. return self.canActivate
  200. }
  201. override func viewWillMove(toWindow newWindow: NSWindow?) {
  202. self._deactivate()
  203. super.viewWillMove(toWindow: newWindow)
  204. }
  205. override func draw(_ dirtyRect: NSRect) {
  206. super.draw(dirtyRect)
  207. let bounds = self.bounds
  208. KMDrawTextFieldBezel(bounds, self)
  209. if (self.isActive) {
  210. NSGraphicsContext.saveGraphicsState()
  211. NSColor.selectedControlColor.setFill()
  212. bounds.fill(using: .plusDarker)
  213. NSGraphicsContext.restoreGraphicsState()
  214. }
  215. if (self.isHighlighted) {
  216. NSGraphicsContext.saveGraphicsState()
  217. NSColor(calibratedWhite: 0, alpha: 0.1).setFill()
  218. self.bounds.frame(withWidth: 1, using: .plusDarker)
  219. NSGraphicsContext.restoreGraphicsState()
  220. }
  221. if (lineWidth > 0.0) {
  222. NSGraphicsContext.saveGraphicsState()
  223. NSBezierPath(rect: NSInsetRect(bounds, 2.0, 2.0)).addClip()
  224. NSColor.black.setStroke()
  225. self._path().stroke()
  226. NSGraphicsContext.restoreGraphicsState()
  227. }
  228. if self.refusesFirstResponder == false && NSApp.isActive && self.window!.isKeyWindow && self.window!.firstResponder == self {
  229. NSGraphicsContext.saveGraphicsState()
  230. // NSSetFocusRingStyle(NSFocusRingOnly);
  231. bounds.fill()
  232. NSGraphicsContext.restoreGraphicsState()
  233. }
  234. }
  235. override func mouseDown(with event: NSEvent) {
  236. if (self.isEnabled) {
  237. self.setKeyboardFocusRingNeedsDisplay(self.bounds)
  238. self.needsDisplay = true
  239. // NSUInteger modifiers = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
  240. var modifiers = event.modifierFlags
  241. modifiers.insert(.deviceIndependentFlagsMask)
  242. var keepOn = true
  243. var _event: NSEvent = event
  244. while (keepOn) {
  245. // theEvent = [[self window] nextEventMatchingMask: NSLeftMouseUpMask | NSLeftMouseDraggedMask];
  246. if let data = self.window?.nextEvent(matching: [.leftMouseUp, .leftMouseDragged]) {
  247. _event = data
  248. switch (_event.type) {
  249. case .leftMouseDragged:
  250. // {
  251. // NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  252. // [NSNumber numberWithDouble:lineWidth], , [NSNumber numberWithInteger:style], , dashPattern, , nil];
  253. var dict = [SKLineWellLineWidthKey : NSNumber(value: self.lineWidth),
  254. SKLineWellStyleKey : NSNumber(value: self.style.rawValue),
  255. SKLineWellDashPatternKey : self.dashPattern ?? []]
  256. if self.displayStyle == .line {
  257. // if ([self displayStyle] == SKLineWellDisplayStyleLine) {
  258. dict[SKLineWellStartLineStyleKey] = NSNumber(value: self.startLineStyle.rawValue)
  259. dict[SKLineWellEndLineStyleKey] = NSNumber(value: self.endLineStyle.rawValue)
  260. }
  261. let pboard = NSPasteboard(name: .drag)
  262. pboard.clearContents()
  263. pboard.setPropertyList(dict, forType: NSPasteboard.PasteboardType(rawValue: SKPasteboardTypeLineStyle))
  264. let bounds = self.bounds
  265. /*beginDraggingSessionWithItems:event:source: instead*/
  266. // [self dragImage:[self dragImage] at:bounds.origin offset:NSZeroSize event:theEvent pasteboard:pboard source:self slideBack:YES];
  267. keepOn = false
  268. break;
  269. // }
  270. case .leftMouseUp:
  271. if (self.isActive) {
  272. self._deactivate()
  273. } else {
  274. // [self activate:(modifiers & NSShiftKeyMask) == 0];
  275. self._activate(modifiers.contains(.shift) == false)
  276. }
  277. keepOn = false
  278. break;
  279. default:
  280. break;
  281. }
  282. }
  283. }
  284. }
  285. }
  286. /*
  287. + (void)initialize {
  288. // SKINITIALIZE;
  289. [self exposeBinding:SKLineWellLineWidthKey];
  290. [self exposeBinding:SKLineWellStyleKey];
  291. [self exposeBinding:SKLineWellDashPatternKey];
  292. [self exposeBinding:SKLineWellStartLineStyleKey];
  293. [self exposeBinding:SKLineWellEndLineStyleKey];
  294. }
  295. - (Class)valueClassForBinding:(NSString *)binding {
  296. if ([binding isEqualToString:SKLineWellDashPatternKey])
  297. return [NSArray class];
  298. else
  299. return [NSNumber class];
  300. }
  301. - (void)dealloc {
  302. // SKENSURE_MAIN_THREAD(
  303. [self unbind:SKLineWellLineWidthKey];
  304. [self unbind:SKLineWellStyleKey];
  305. [self unbind:SKLineWellDashPatternKey];
  306. [self unbind:SKLineWellStartLineStyleKey];
  307. [self unbind:SKLineWellEndLineStyleKey];
  308. // );
  309. [[NSNotificationCenter defaultCenter] removeObserver:self];
  310. // SKDESTROY(dashPattern);
  311. // [super dealloc];
  312. }
  313. - (void)takeValueForKey:(NSString *)key from:(id)object {
  314. [self setValue:[object valueForKey:key] forKey:key];
  315. NSDictionary *info = [self infoForBinding:key];
  316. [[info objectForKey:NSObservedObjectKey] setValue:[self valueForKey:key] forKeyPath:[info objectForKey:NSObservedKeyPathKey]];
  317. }
  318. - (void)performClick:(id)sender {
  319. if ([self isEnabled]) {
  320. if ([self isActive])
  321. [self deactivate];
  322. else
  323. [self activate:YES];
  324. }
  325. }
  326. - (void)lineInspectorWindowWillClose:(NSNotification *)notification {
  327. [self deactivate];
  328. }
  329. #pragma mark Accessors
  330. - (SEL)action { return action; }
  331. - (void)setAction:(SEL)newAction { action = newAction; }
  332. - (id)target { return target; }
  333. - (void)setTarget:(id)newTarget { target = newTarget; }
  334. - (void)setNilValueForKey:(NSString *)key {
  335. if ([key isEqualToString:SKLineWellLineWidthKey] || [key isEqualToString:SKLineWellStyleKey] ||
  336. [key isEqualToString:SKLineWellStartLineStyleKey] || [key isEqualToString:SKLineWellEndLineStyleKey]) {
  337. [self setValue:[NSNumber numberWithInteger:0] forKey:key];
  338. } else {
  339. [super setNilValueForKey:key];
  340. }
  341. }
  342. #pragma mark Notification handlers
  343. - (void)lineInspectorLineAttributeChanged:(NSNotification *)notification {
  344. // SKLineInspector *inspector = [notification object];
  345. // NSString *key = nil;
  346. // switch ([inspector currentLineChangeAction]) {
  347. // case SKLineChangeActionLineWidth:
  348. // key = SKLineWellLineWidthKey;
  349. // break;
  350. // case SKLineChangeActionStyle:
  351. // key = SKLineWellStyleKey;
  352. // break;
  353. // case SKLineChangeActionDashPattern:
  354. // key = SKLineWellDashPatternKey;
  355. // break;
  356. // case SKLineChangeActionStartLineStyle:
  357. // if ([self displayStyle] == SKLineWellDisplayStyleLine)
  358. // key = SKLineWellStartLineStyleKey;
  359. // break;
  360. // case SKLineChangeActionEndLineStyle:
  361. // if ([self displayStyle] == SKLineWellDisplayStyleLine)
  362. // key = SKLineWellEndLineStyleKey;
  363. // break;
  364. // case SKNoLineChangeAction:
  365. // break;
  366. // }
  367. // if (key) {
  368. // [self takeValueForKey:key from:inspector];
  369. // [self sendAction:[self action] to:[self target]];
  370. // }
  371. }
  372. #pragma mark NSDraggingSource protocol
  373. - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
  374. return NSDragOperationGeneric;
  375. }
  376. #pragma mark NSDraggingDestination protocol
  377. - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
  378. if ([self isEnabled] && [sender draggingSource] != self && [[sender draggingPasteboard] canReadItemWithDataConformingToTypes:[NSArray arrayWithObjects:SKPasteboardTypeLineStyle, nil]]) {
  379. [self setHighlighted:YES];
  380. [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]];
  381. [self setNeedsDisplay:YES];
  382. return NSDragOperationEvery;
  383. } else
  384. return NSDragOperationNone;
  385. }
  386. - (void)draggingExited:(id <NSDraggingInfo>)sender {
  387. if ([self isEnabled] && [sender draggingSource] != self && [[sender draggingPasteboard] canReadItemWithDataConformingToTypes:[NSArray arrayWithObjects:SKPasteboardTypeLineStyle, nil]]) {
  388. [self setHighlighted:NO];
  389. [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]];
  390. [self setNeedsDisplay:YES];
  391. }
  392. }
  393. - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
  394. return [self isEnabled] && [sender draggingSource] != self && [[sender draggingPasteboard] canReadItemWithDataConformingToTypes:[NSArray arrayWithObjects:SKPasteboardTypeLineStyle, nil]];
  395. }
  396. - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender{
  397. NSPasteboard *pboard = [sender draggingPasteboard];
  398. [pboard types];
  399. NSDictionary *dict = [pboard propertyListForType:SKPasteboardTypeLineStyle];
  400. if ([dict objectForKey:SKLineWellLineWidthKey])
  401. [self takeValueForKey:SKLineWellLineWidthKey from:dict];
  402. if ([dict objectForKey:SKLineWellStyleKey])
  403. [self takeValueForKey:SKLineWellStyleKey from:dict];
  404. [self takeValueForKey:SKLineWellDashPatternKey from:dict];
  405. if ([self displayStyle] == SKLineWellDisplayStyleLine) {
  406. if ([dict objectForKey:SKLineWellStartLineStyleKey])
  407. [self takeValueForKey:SKLineWellStartLineStyleKey from:dict];
  408. if ([dict objectForKey:SKLineWellEndLineStyleKey])
  409. [self takeValueForKey:SKLineWellEndLineStyleKey from:dict];
  410. }
  411. [self sendAction:[self action] to:[self target]];
  412. [self setHighlighted:NO];
  413. [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]];
  414. [self setNeedsDisplay:YES];
  415. return dict != nil;
  416. }
  417. #pragma mark Accessibility
  418. - (NSArray *)accessibilityAttributeNames {
  419. static NSArray *attributes = nil;
  420. if (attributes == nil) {
  421. attributes = [[NSArray alloc] initWithObjects:
  422. NSAccessibilityRoleAttribute,
  423. NSAccessibilityRoleDescriptionAttribute,
  424. NSAccessibilityValueAttribute,
  425. NSAccessibilityTitleAttribute,
  426. NSAccessibilityHelpAttribute,
  427. NSAccessibilityFocusedAttribute,
  428. NSAccessibilityParentAttribute,
  429. NSAccessibilityWindowAttribute,
  430. NSAccessibilityTopLevelUIElementAttribute,
  431. NSAccessibilityPositionAttribute,
  432. NSAccessibilitySizeAttribute,
  433. nil];
  434. }
  435. return attributes;
  436. }
  437. - (id)accessibilityAttributeValue:(NSString *)attribute {
  438. if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
  439. return NSAccessibilityCheckBoxRole;
  440. } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
  441. return NSAccessibilityRoleDescription(NSAccessibilityCheckBoxRole, nil);
  442. } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
  443. return [NSNumber numberWithInteger:[self isActive]];
  444. } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
  445. return [NSString stringWithFormat:@"%@ %ld", NSLocalizedString(@"line width", @"Accessibility description"), (long)[self lineWidth]];
  446. } else if ([attribute isEqualToString:NSAccessibilityHelpAttribute]) {
  447. return [self toolTip];
  448. } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
  449. // Just check if the app thinks we're focused.
  450. id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
  451. return [NSNumber numberWithBool:[focusedElement isEqual:self]];
  452. } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
  453. return NSAccessibilityUnignoredAncestor([self superview]);
  454. } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
  455. // We're in the same window as our parent.
  456. return [NSAccessibilityUnignoredAncestor([self superview]) accessibilityAttributeValue:NSAccessibilityWindowAttribute];
  457. } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) {
  458. // We're in the same top level element as our parent.
  459. return [NSAccessibilityUnignoredAncestor([self superview]) accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
  460. } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
  461. return [NSValue valueWithPoint:[[self window] convertBaseToScreen:[self convertPoint:[self bounds].origin toView:nil]]];
  462. } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
  463. return [NSValue valueWithSize:[self convertSize:[self bounds].size toView:nil]];
  464. } else {
  465. return nil;
  466. }
  467. }
  468. - (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
  469. if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
  470. return [self canActivate];
  471. } else {
  472. return NO;
  473. }
  474. }
  475. - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
  476. if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
  477. [[self window] makeFirstResponder:self];
  478. }
  479. }
  480. // actions
  481. - (NSArray *)accessibilityActionNames {
  482. return [NSArray arrayWithObject:NSAccessibilityPressAction];
  483. }
  484. - (NSString *)accessibilityActionDescription:(NSString *)anAction {
  485. return NSAccessibilityActionDescription(anAction);
  486. }
  487. - (void)accessibilityPerformAction:(NSString *)anAction {
  488. if ([anAction isEqualToString:NSAccessibilityPressAction])
  489. [self performClick:self];
  490. }
  491. // misc
  492. - (BOOL)accessibilityIsIgnored {
  493. return NO;
  494. }
  495. - (id)accessibilityHitTest:(NSPoint)point {
  496. return NSAccessibilityUnignoredAncestor(self);
  497. }
  498. - (id)accessibilityFocusedUIElement {
  499. return NSAccessibilityUnignoredAncestor(self);
  500. }
  501. @end
  502. */
  503. }
  504. // MARK: - Private Methods
  505. extension KMLineWell {
  506. private func _commonInit() {
  507. __lwFlags.canActivate = true
  508. __lwFlags.existsActiveLineWell = 0
  509. // [self registerForDraggedTypes:[NSArray arrayWithObjects:SKPasteboardTypeLineStyle, nil]];
  510. }
  511. private func _deactivate() {
  512. if self.isActive {
  513. NotificationCenter.default.removeObserver(self)
  514. __lwFlags.active = false
  515. self.setKeyboardFocusRingNeedsDisplay(self.bounds)
  516. self.needsDisplay = true
  517. }
  518. }
  519. private func _changedValue(forKey key: String) {
  520. // if ([self isActive])
  521. // [[SKLineInspector sharedLineInspector] setValue:[self valueForKey:key] forKey:key];
  522. self.needsDisplay = true
  523. }
  524. private func _dragImage() -> NSImage? {
  525. let bounds = self.bounds
  526. let path = self.lineWidth > 0.0 ? self._path() : nil
  527. // CGFloat scale = [self backingScale];
  528. let scale = 1.0
  529. let image = NSImage.bitmapImage(with: bounds.size, scale: scale) { rect in
  530. KMContextSetAlpha(NSGraphicsContext.current?.cgContext, 0.7)
  531. NSColor.darkGray.setFill()
  532. _ = NSRect.fill(NSInsetRect(rect, 1.0, 1.0))
  533. NSColor.controlBackgroundColor.setFill()
  534. _ = NSRect.fill(NSInsetRect(rect, 2.0, 2.0))
  535. NSColor.black.setStroke()
  536. path?.stroke()
  537. }
  538. return image
  539. }
  540. private func _path() -> NSBezierPath {
  541. let path = NSBezierPath()
  542. let bounds = self.bounds
  543. if self.displayStyle == .line {
  544. let offset = 0.5 * lineWidth - floor(0.5 * lineWidth)
  545. let startPoint = NSMakePoint(NSMinX(bounds) + ceil(0.5 * NSHeight(bounds)), round(NSMidY(bounds)) - offset)
  546. let endPoint = NSMakePoint(NSMaxX(bounds) - ceil(0.5 * NSHeight(bounds)), round(NSMidY(bounds)) - offset)
  547. switch (self.startLineStyle) {
  548. case .none:
  549. break
  550. case .square:
  551. path.appendRect(NSMakeRect(startPoint.x - 1.5 * lineWidth, startPoint.y - 1.5 * lineWidth, 3 * lineWidth, 3 * lineWidth))
  552. break
  553. case .circle:
  554. path.appendOval(in: NSMakeRect(startPoint.x - 1.5 * lineWidth, startPoint.y - 1.5 * lineWidth, 3 * lineWidth, 3 * lineWidth))
  555. break
  556. case .diamond:
  557. path.move(to: NSMakePoint(startPoint.x - 1.5 * lineWidth, startPoint.y))
  558. path.line(to: NSMakePoint(startPoint.x, startPoint.y + 1.5 * lineWidth))
  559. path.line(to: NSMakePoint(startPoint.x + 1.5 * lineWidth, startPoint.y))
  560. path.line(to: NSMakePoint(startPoint.x, startPoint.y - 1.5 * lineWidth))
  561. path.close()
  562. break
  563. case .openArrow:
  564. path.move(to: NSMakePoint(startPoint.x + 3.0 * lineWidth, startPoint.y - 1.5 * lineWidth))
  565. path.line(to: NSMakePoint(startPoint.x, startPoint.y))
  566. path.line(to: NSMakePoint(startPoint.x + 3.0 * lineWidth, startPoint.y + 1.5 * lineWidth))
  567. break
  568. case .closedArrow:
  569. path.move(to: NSMakePoint(startPoint.x + 3.0 * lineWidth, startPoint.y - 1.5 * lineWidth))
  570. path.line(to: NSMakePoint(startPoint.x, startPoint.y))
  571. path.line(to: NSMakePoint(startPoint.x + 3.0 * lineWidth, startPoint.y + 1.5 * lineWidth))
  572. path.close()
  573. break
  574. @unknown default:
  575. fatalError()
  576. }
  577. path.move(to: startPoint)
  578. path.line(to: endPoint)
  579. switch (self.endLineStyle) {
  580. case .none:
  581. break
  582. case .square:
  583. path.appendRect(NSMakeRect(endPoint.x - 1.5 * lineWidth, endPoint.y - 1.5 * lineWidth, 3 * lineWidth, 3 * lineWidth))
  584. break
  585. case .circle:
  586. path.appendOval(in: NSMakeRect(endPoint.x - 1.5 * lineWidth, endPoint.y - 1.5 * lineWidth, 3 * lineWidth, 3 * lineWidth))
  587. break
  588. case .diamond:
  589. path.move(to: NSMakePoint(endPoint.x + 1.5 * lineWidth, endPoint.y))
  590. path.line(to: NSMakePoint(endPoint.x, endPoint.y + 1.5 * lineWidth))
  591. path.line(to: NSMakePoint(endPoint.x - 1.5 * lineWidth, endPoint.y))
  592. path.line(to: NSMakePoint(endPoint.x, endPoint.y - 1.5 * lineWidth))
  593. path.close()
  594. break
  595. case .openArrow:
  596. path.move(to: NSMakePoint(endPoint.x - 3.0 * lineWidth, endPoint.y + 1.5 * lineWidth))
  597. path.line(to: NSMakePoint(endPoint.x, endPoint.y))
  598. path.line(to: NSMakePoint(endPoint.x - 3.0 * lineWidth, endPoint.y - 1.5 * lineWidth))
  599. break
  600. case .closedArrow:
  601. path.move(to: NSMakePoint(endPoint.x - 3.0 * lineWidth, endPoint.y + 1.5 * lineWidth))
  602. path.line(to: NSMakePoint(endPoint.x, endPoint.y))
  603. path.line(to: NSMakePoint(endPoint.x - 3.0 * lineWidth, endPoint.y - 1.5 * lineWidth))
  604. path.close()
  605. break
  606. @unknown default:
  607. fatalError()
  608. }
  609. } else if self.displayStyle == .simpleLine {
  610. let offset = 0.5 * lineWidth - floor(0.5 * lineWidth)
  611. path.move(to: NSMakePoint(NSMinX(bounds) + ceil(0.5 * NSHeight(bounds)), round(NSMidY(bounds)) - offset))
  612. path.line(to: NSMakePoint(NSMaxX(bounds) - ceil(0.5 * NSHeight(bounds)), round(NSMidY(bounds)) - offset))
  613. } else if self.displayStyle == .rectangle {
  614. let inset = 7.0 + 0.5 * lineWidth
  615. path.appendRect(NSInsetRect(bounds, inset, inset))
  616. } else {
  617. let inset = 7.0 + 0.5 * lineWidth
  618. path.appendOval(in: NSInsetRect(bounds, inset, inset))
  619. }
  620. path.lineWidth = self.lineWidth
  621. if self.style == .dashed {
  622. path.setLineDash(self.dashPattern as? [CGFloat], count: self.dashPattern!.count, phase: 0)
  623. }
  624. return path
  625. }
  626. private func _activate(_ exclusive: Bool) {
  627. if (self.canActivate) {
  628. let nc = NotificationCenter.default
  629. // SKLineInspector *inspector = [SKLineInspector sharedLineInspector];
  630. __lwFlags.existsActiveLineWell = 0
  631. nc.post(name: NSNotification.Name(rawValue: SKLineWellWillBecomeActiveNotification), object: self, userInfo: [EXCLUSIVE_KEY : NSNumber(value: exclusive)])
  632. if (__lwFlags.existsActiveLineWell != 0) {
  633. // [self takeValueForKey:SKLineWellLineWidthKey from:inspector];
  634. // [self takeValueForKey:SKLineWellDashPatternKey from:inspector];
  635. // [self takeValueForKey:SKLineWellStyleKey from:inspector];
  636. if (self.displayStyle == .line) {
  637. // [self takeValueForKey:SKLineWellStartLineStyleKey from:inspector];
  638. // [self takeValueForKey:SKLineWellEndLineStyleKey from:inspector];
  639. }
  640. } else {
  641. // [inspector setLineWidth:[self lineWidth]];
  642. // [inspector setDashPattern:[self dashPattern]];
  643. // [inspector setStyle:[self style]];
  644. if (self.displayStyle == .line) {
  645. // [inspector setStartLineStyle:[self startLineStyle]];
  646. // [inspector setEndLineStyle:[self endLineStyle]];
  647. }
  648. }
  649. // [[inspector window] orderFront:self];
  650. nc.addObserver(self, selector: #selector(_lineWellWillBecomeActive), name: NSNotification.Name(SKLineWellWillBecomeActiveNotification), object: nil)
  651. // [nc addObserver:self selector:@selector(lineInspectorWindowWillClose:)
  652. // name:NSWindowWillCloseNotification object:[inspector window]];
  653. // [nc addObserver:self selector:@selector(lineInspectorLineAttributeChanged:)
  654. // name:SKLineInspectorLineAttributeDidChangeNotification object:inspector];
  655. __lwFlags.active = true
  656. self.setKeyboardFocusRingNeedsDisplay(self.bounds)
  657. self.needsDisplay = true
  658. }
  659. }
  660. @objc private func _lineWellWillBecomeActive(_ notification: NSNotification) {
  661. let sender = notification.object
  662. if (self.isEqual(to: sender) == false && self.isActive) {
  663. if let data = notification.userInfo?[EXCLUSIVE_KEY] as? NSNumber, data.boolValue {
  664. self._deactivate()
  665. } else {
  666. (sender as? KMLineWell)?._existsActiveLineWell()
  667. }
  668. }
  669. }
  670. private func _existsActiveLineWell() {
  671. __lwFlags.existsActiveLineWell = 1
  672. }
  673. /*
  674. */
  675. }