드래그 앤 드롭으로 콘텐츠 복사를 구현하기 – Cocoa, Swift

많은 코코아 관련 서적에서 복사/붙여넣기를 구현하는 다음 과정으로 드래그 앤 드롭을 소개하는데, 대부분이 어떤 이미지 뷰에 이미지를 끌어다 놓는 부분까지만 소개하고 있다. 아마도 드래그 앤 드롭 자체가 실제로는 상당히 복잡한 매커니즘이라 그런 듯 한데, 이번 글에서는 드래그 앤 드롭을 구현하기 위해서 소스 뷰와 타깃 뷰 그리고 전달되는 데이터 모델에 대해 어떤 클래스와 구현이 필요한지를 살펴보도록 하겠다.

드래그 앤 드롭으로 콘텐츠 복사를 구현하기 – Cocoa, Swift 더보기

NSView의 내용을 PDF로 만들기 (Swift)

뷰로부터 pdf 데이터 얻기

AppKit의 모든 그리기 명령은 PDF로 변환가능하다. 그리고 이렇게 변환된 PDF 데이터는 프린터로 보내지거나 파일에 기록될 수 있다. PDF는 해상도에 의존하지 않기 때문에 어느 기기에서 봐도 제법 괜찮은 품질을 보여준다는 점을 잊지 말자.

draw:를 사용해서 뷰를 그리는 것을 할 수 있다면, PDF는 공짜로 얻을 수 있다. 이 방법은 매우 쉬운데 NSView는 다음과 같은 메소드를 가지고 있다.

  • func dataWithPDF(inside: NSRect) -> Data

이 메소드는 draw(:)를 호출해서 이를 통해 그래픽 데이터를 얻는다. 뷰 그리기 명령에서 얻어지는 모든 내역은 화면이 아닌 데이터 객체로 들어간다. 이렇게 얻은 내용은 간단히 파일에 저장할 수 있다.

@IBAction func savePDF(_ sender: Any) {
    let panel = NSSavePanel()
    panel.allowedFileTypes = ["pdf"]
    panel.allowsOtherFileTypes = false
    panel.beginSheetModal(for: window!) { clicked in
        if clicked == NSFileHandleingPanelOKButton, let url = panel.url {
            let data = self.dataWithPDF(inside: self.bounds)
            do {
                try data.write(to:url)
            } catch {
                let a = NSAlert(error: error as! NSError)
                a.runModal()
            }
        }
    }
}

커스텀 뷰로 만든 UI 컴포넌트의 포커스링 그리기 – Cocoa

포커스 링

코코아 UI 요소에서 현재 포커스를 받은 UI 컴포넌트는 외부에 흐릿한 푸른 색 후광이 그려지며, 현재 포커스를 받고 있는 입력 디바이스라는 점을 시각적으로 피드백한다.  시중의 코코아 관련한 대부분의 책에서는 다음과 같이 draw: 메소드 내에서 포커스링을 그리는 것으로 포커스링을 흉내낼 수 있다고 한다. 1

override func draw(_ dirtyRect: NSRect) {
    // 배경을 칠하고,
    super.draw(dirtyRect)
    self.bgColor.set()
    NSBezierPath.fill(bounds)

    // 자신이 속한 윈도에서 자기가 제1응답자라면?
    if let fr = window?.firstResponder, fr === self {
        // 포커스 컬러로 세팅하여, 자신의 테두리 영역을 그린다.
        NSColor.keyboardFocusIndicatorColor.set()
        NSBezierPath.setDefaultLineWidth(4.0)
        NSBezierPath.strokeRect(bounds)
    }
}

그리고 제 1 응답자가 되었을 때 포커스링을 그리기 위해서는 뷰가 응답자 상태에 진입하거나 빠져나올 때마다 뷰를 새로 그리도록 갱신해야 한다.

override var acceptsFirstResponder: Bool { return true }

override func resignFirstResponder() -> Bool {
    NSLog("Resigning...")
    setNeedsDisplay(bounds)
    return true
}

override func becomeFirstResponder() -> Bool {
    NSLog("Becoming...")
    setNeedsDisplay(bounds)
    return true
}

커스텀 뷰로 만든 UI 컴포넌트의 포커스링 그리기 – Cocoa 더보기