// // KMPDFAnnotationChoiceWidgetSub.swift // PDF Reader Pro // // Created by wanjun on 2024/1/31. // import Cocoa class KMPDFAnnotationChoiceWidgetSub: CPDFChoiceWidgetAnnotation { var formType: CAnnotationType = .unkown override func draw(with box: CPDFDisplayBox, in context: CGContext!) { let listChoice: Bool = isListChoice if listChoice { if hasAppearanceStream() { super.draw(with: box, in: context) } else { super.draw(with: box, in: context) transformContext(for: page, displayBox: box) context.setStrokeColor(red: 0, green: 0, blue: 0, alpha: 1.0) context.setLineWidth(1.0) context.addRect(CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height)) context.strokePath() } } else { if hasAppearanceStream() { super.draw(with: box, in: context) } else { var stabilizeHeight = bounds.size.height if stabilizeHeight > 25.0 { stabilizeHeight = 25.0 } var actualRect = CGRect.zero actualRect = CGRect(x: bounds.origin.x, y: bounds.minY + (bounds.height - stabilizeHeight) / 2, width: bounds.size.width, height: stabilizeHeight) let borderWidth: CGFloat = 0.5 var rightPartWidthChangePointValue = bounds.size.width / 2 if rightPartWidthChangePointValue > 30 { rightPartWidthChangePointValue = 30 } let radius: CGFloat = 2.0 // 画外框 context.saveGState() context.move(to: CGPoint(x: actualRect.maxX - rightPartWidthChangePointValue, y: actualRect.minY + borderWidth)) context.addLine(to: CGPoint(x: actualRect.minX + borderWidth, y: actualRect.minY + borderWidth)) context.addLine(to: CGPoint(x: actualRect.minX + borderWidth, y: actualRect.maxY - borderWidth)) context.addLine(to: CGPoint(x: actualRect.maxX - rightPartWidthChangePointValue + 2 * borderWidth, y: actualRect.maxY - borderWidth)) context.addLine(to: CGPoint(x: actualRect.maxX - rightPartWidthChangePointValue + 2 * borderWidth, y: actualRect.minY + borderWidth)) context.setStrokeColor(NSColor.lightGray.cgColor) context.setLineWidth(borderWidth) context.setFillColor(self.backgroundColor.cgColor) context.drawPath(using: .fillStroke) context.restoreGState() context.saveGState() context.move(to: CGPoint(x: actualRect.maxX - rightPartWidthChangePointValue, y: actualRect.maxY)) context.addLine(to: CGPoint(x: actualRect.maxX - rightPartWidthChangePointValue, y: actualRect.minY)) context.addLine(to: CGPoint(x: actualRect.maxX - radius, y: actualRect.minY)) context.addArc(center: CGPoint(x: actualRect.maxX - radius, y: actualRect.minY + radius), radius: radius, startAngle: CGFloat(3 * Double.pi / 2), endAngle: CGFloat(2 * Double.pi), clockwise: false) context.addLine(to: CGPoint(x: actualRect.maxX, y: actualRect.maxY - radius)) context.addArc(center: CGPoint(x: actualRect.maxX - radius, y: actualRect.maxY - radius), radius: radius, startAngle: CGFloat(2 * Double.pi), endAngle: CGFloat(Double.pi / 2), clockwise: false) context.addLine(to: CGPoint(x: actualRect.maxX - rightPartWidthChangePointValue, y: actualRect.maxY)) context.setFillColor(NSColor(red: 37/255.0, green: 139/255.0, blue: 251/255.0, alpha: 1.0).cgColor) context.drawPath(using: .fill) context.restoreGState() // 画等边三角形 let triangleWidth = min(rightPartWidthChangePointValue, actualRect.height) / 2.0 let triangleHeight = triangleWidth * sqrt(3.0) / 2 let centerPointUpGap = triangleHeight / 3.0 context.saveGState() let startPointX = actualRect.maxX - rightPartWidthChangePointValue + (rightPartWidthChangePointValue - triangleWidth) / 2 let startPointY = actualRect.midY + centerPointUpGap context.move(to: CGPoint(x: startPointX, y: startPointY)) context.addLine(to: CGPoint(x: startPointX + triangleWidth, y: startPointY)) context.addLine(to: CGPoint(x: startPointX + triangleWidth / 2.0, y: actualRect.midY - 2 * centerPointUpGap)) context.closePath() context.setFillColor(NSColor.white.cgColor) context.drawPath(using: .fill) context.restoreGState() context.saveGState() // 画文字 var attributes = [NSAttributedString.Key: Any]() if let font = self.font { attributes[.font] = font } if let fontColor = self.fontColor { attributes[.foregroundColor] = fontColor } let stringRect = self.string().boundingRect(with: CGSize(width: actualRect.size.width - rightPartWidthChangePointValue, height: actualRect.size.height), options: .usesLineFragmentOrigin, attributes: attributes) self.string().draw(in: CGRect(x: actualRect.origin.x, y: (actualRect.size.height - stringRect.size.height) / 2 + actualRect.origin.y, width: stringRect.size.width, height: stringRect.size.height), withAttributes: attributes) // context.restoreGState() } } } func transformContext(for page: CPDFPage, displayBox box: CPDFDisplayBox) { var transform = NSAffineTransform() // Identity. transform = NSAffineTransform() // Bounds for page. let boxRect = page.bounds(for: box) // Handle rotation. let rotation = page.rotation switch rotation { case 90: transform.rotate(byDegrees: -90) transform.translateX(by: -boxRect.size.width, yBy: 0.0) case 180: transform.rotate(byDegrees: 180) transform.translateX(by: -boxRect.size.width, yBy: -boxRect.size.height) case 270: transform.rotate(byDegrees: 90) transform.translateX(by: 0.0, yBy: -boxRect.size.height) default: break } // Origin. transform.translateX(by: -boxRect.origin.x, yBy: -boxRect.origin.y) // Concatenate. transform.concat() } func keysForValuesToObserveForUndo() -> Set { return [] } }