1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-12-01 10:02:36 +03:00
vimr/VimR/Workspace/WorkspaceToolButton.swift

183 lines
5.1 KiB
Swift
Raw Normal View History

2016-09-18 21:49:42 +03:00
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
2016-11-17 02:16:03 +03:00
class WorkspaceToolButton: NSView, NSDraggingSource {
2016-11-14 00:16:56 +03:00
2016-09-25 18:50:33 +03:00
static fileprivate let titlePadding = CGSize(width: 8, height: 2)
static fileprivate let dummyButton = WorkspaceToolButton(title: "Dummy")
2016-09-18 21:49:42 +03:00
2016-09-25 18:50:33 +03:00
fileprivate let title: NSAttributedString
fileprivate var trackingArea = NSTrackingArea()
2016-09-25 01:44:10 +03:00
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - API
static let toolUti = "com.qvacua.vimr.tool"
2016-11-16 23:06:23 +03:00
static func ==(left: WorkspaceToolButton, right: WorkspaceToolButton) -> Bool {
guard let leftTool = left.tool, let rightTool = right.tool else {
return false
}
return leftTool == rightTool
}
var location = WorkspaceBarLocation.top
2016-09-18 21:49:42 +03:00
var isSelected: Bool {
return self.tool?.isSelected ?? false
}
weak var tool: WorkspaceTool?
static func dimension() -> CGFloat {
return self.dummyButton.intrinsicContentSize.height
}
static func size(forLocation loc: WorkspaceBarLocation) -> CGSize {
switch loc {
case .top, .bottom:
return self.dummyButton.intrinsicContentSize
case .right, .left:
return CGSize(width: self.dummyButton.intrinsicContentSize.height,
height: self.dummyButton.intrinsicContentSize.width)
}
}
2016-09-25 01:44:10 +03:00
init(title: String) {
self.title = NSAttributedString(string: title, attributes: [
2016-09-25 18:50:33 +03:00
NSFontAttributeName: NSFont.systemFont(ofSize: 11)
2016-09-25 01:44:10 +03:00
])
super.init(frame: CGRect.zero)
self.configureForAutoLayout()
2016-09-25 01:44:10 +03:00
self.wantsLayer = true
}
func highlight() {
2016-09-25 18:50:33 +03:00
self.layer?.backgroundColor = NSColor.controlShadowColor.cgColor
2016-09-18 21:49:42 +03:00
}
2016-09-25 01:44:10 +03:00
func dehighlight() {
2016-09-25 18:50:33 +03:00
self.layer?.backgroundColor = NSColor.clear.cgColor
2016-09-25 01:44:10 +03:00
}
}
// MARK: - NSView
extension WorkspaceToolButton {
2016-09-18 21:49:42 +03:00
override var intrinsicContentSize: NSSize {
let titleSize = self.title.size()
let padding = WorkspaceToolButton.titlePadding
switch self.location {
case .top, .bottom:
return CGSize(width: titleSize.width + 2 * padding.width, height: titleSize.height + 2 * padding.height)
case .right, .left:
return CGSize(width: titleSize.height + 2 * padding.height, height: titleSize.width + 2 * padding.width)
}
}
2016-09-25 18:50:33 +03:00
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
2016-09-18 21:49:42 +03:00
let padding = WorkspaceToolButton.titlePadding
switch self.location {
case .top, .bottom:
2016-09-25 18:50:33 +03:00
self.title.draw(at: CGPoint(x: padding.width, y: padding.height))
2016-09-18 21:49:42 +03:00
case .right:
self.title.draw(at: CGPoint(x: padding.height, y: self.bounds.height - padding.width), angle: -CGFloat(M_PI_2))
case .left:
self.title.draw(at: CGPoint(x: self.bounds.width - padding.height, y: padding.width), angle: CGFloat(M_PI_2))
}
}
override func updateTrackingAreas() {
self.removeTrackingArea(self.trackingArea)
self.trackingArea = NSTrackingArea(rect: self.bounds,
2016-09-25 18:50:33 +03:00
options: [.mouseEnteredAndExited, .activeInActiveApp],
2016-09-18 21:49:42 +03:00
owner: self,
userInfo: nil)
self.addTrackingArea(self.trackingArea)
super.updateTrackingAreas()
}
2016-09-25 18:50:33 +03:00
override func mouseDown(with event: NSEvent) {
2016-11-14 00:16:56 +03:00
guard let nextEvent = self.window!.nextEvent(matching: [NSLeftMouseUpMask, NSLeftMouseDraggedMask]) else {
return
}
switch nextEvent.type {
case NSLeftMouseUp:
self.tool?.toggle()
return
case NSLeftMouseDragged:
let pasteboardItem = NSPasteboardItem()
2016-11-17 02:16:03 +03:00
pasteboardItem.setString(self.tool!.uuid, forType: WorkspaceToolButton.toolUti)
2016-11-14 00:16:56 +03:00
let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
draggingItem.setDraggingFrame(self.bounds, contents:self.snapshot())
2016-11-17 02:16:03 +03:00
self.beginDraggingSession(with: [draggingItem], event: event, source: self)
2016-11-14 00:16:56 +03:00
return
default:
return
}
2016-09-18 21:49:42 +03:00
}
2016-09-25 18:50:33 +03:00
override func mouseEntered(with _: NSEvent) {
2016-09-18 21:49:42 +03:00
if self.isSelected {
return
}
self.highlight()
}
2016-09-25 18:50:33 +03:00
override func mouseExited(with _: NSEvent) {
2016-09-18 21:49:42 +03:00
if self.isSelected {
return
}
self.dehighlight()
}
2016-11-14 00:16:56 +03:00
// https://www.raywenderlich.com/136272/drag-and-drop-tutorial-for-macos
fileprivate func snapshot() -> NSImage {
let pdfData = self.dataWithPDF(inside: self.bounds)
let image = NSImage(data: pdfData)
return image ?? NSImage()
}
}
2016-11-17 02:16:03 +03:00
// MARK: - NSDraggingSource
2016-11-14 00:16:56 +03:00
extension WorkspaceToolButton {
2016-11-17 02:16:03 +03:00
@objc(draggingSession:sourceOperationMaskForDraggingContext:)
func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor ctc: NSDraggingContext) -> NSDragOperation {
return .move
}
2016-11-14 00:16:56 +03:00
2016-11-17 02:16:03 +03:00
@objc(draggingSession:endedAtPoint:operation:)
func draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation) {
guard let pointInWindow = self.window?.convertFromScreen(CGRect(origin: screenPoint, size: .zero)) else {
return
}
2016-11-17 02:16:03 +03:00
let pointInView = self.convert(pointInWindow, from: nil)
// Sometimes if the drag ends, the button does not get dehighlighted.
2016-11-18 00:43:32 +03:00
if !self.frame.contains(pointInView) && !(self.tool?.isSelected ?? false) {
2016-11-17 02:16:03 +03:00
self.dehighlight()
}
2016-11-14 00:16:56 +03:00
}
2016-09-18 21:49:42 +03:00
}