KMLineWell.swift 32 KB

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