3 struct MapEditor: View {
4 @Binding var document: MapDocument
6 @State var selectedEvolution: StageType = .behavior
8 @AppStorage("viewStyle") var viewStyle: ViewStyle = .horizontal
10 let zoomRange = Constants.kMinZoom...Constants.kMaxZoom
11 @AppStorage("zoom") var zoom = 1.0
12 @State var lastZoom = 1.0
17 ZStack(alignment: .topLeading) {
18 MapTextEditor(document: $document)
19 .background(Color.ui.background)
20 .foregroundColor(Color.ui.foreground)
21 .frame(minHeight: 96.0)
22 }.padding(.top, 8.0).padding(.leading, 8.0).background(Color.ui.background).cornerRadius(
24 GeometryReader { geometry in
25 ScrollView([.horizontal, .vertical]) {
27 document: $document, evolution: $selectedEvolution, onDragVertex: onDragVertex
28 ).scaleEffect(zoom, anchor: .center).frame(
29 width: (Dimensions.mapSize.width + 2 * Dimensions.mapPadding) * zoom,
30 height: (Dimensions.mapSize.height + 2 * Dimensions.mapPadding) * zoom)
31 }.background(Color.ui.background)
33 MagnificationGesture()
35 let delta = value / lastZoom
37 zoom = min(max(zoom * delta, zoomRange.lowerBound), zoomRange.upperBound)
49 value: $zoom, in: zoomRange, step: 0.1,
51 Text(formatZoom(zoom))
52 .font(.theme.smallControl)
55 Image(systemName: "minus.magnifyingglass")
56 .font(.theme.smallControl)
57 .help("Zoom Out (⌘-)")
60 Image(systemName: "plus.magnifyingglass")
61 .font(.theme.smallControl)
64 ).frame(width: 200).padding(.trailing, 10.0)
68 Button(action: saveImage) {
69 Image(systemName: "photo")
71 .help("Export Image (⌘E)")
72 .padding(.vertical, 4.0).padding(.leading, 4.0).padding(.trailing, 8.0)
74 EvolutionPicker(selectedEvolution: $selectedEvolution)
79 func adaptiveStack<Content: View>(@ViewBuilder content: () -> Content) -> some View {
80 if viewStyle == .horizontal {
91 private func formatZoom(_ number: CGFloat) -> String {
92 let formatter = NumberFormatter()
93 formatter.numberStyle = .decimal
94 formatter.maximumFractionDigits = 1
95 formatter.minimumFractionDigits = 1
96 return (formatter.string(from: NSNumber(value: number)) ?? "") + "x"
99 private func onDragVertex(vertex: Vertex, x: CGFloat, y: CGFloat) {
102 private func saveImage() {
103 if let image = document.exportAsImage(withEvolution: selectedEvolution) {
105 let filename = url?.deletingPathExtension().lastPathComponent ?? "Untitled"
107 let savePanel = NSSavePanel()
108 savePanel.allowedContentTypes = [.png]
109 savePanel.canCreateDirectories = true
110 savePanel.isExtensionHidden = false
111 savePanel.title = "Save \(filename) as image"
112 savePanel.message = "Choose a location to save the image"
113 savePanel.nameFieldStringValue = "\(filename).png"
114 savePanel.begin { result in
115 if result == .OK, let url = savePanel.url {
116 if let tiffRepresentation = image.tiffRepresentation {
117 let bitmapImage = NSBitmapImageRep(data: tiffRepresentation)
118 let pngData = bitmapImage?.representation(using: .png, properties: [:])
120 try pngData?.write(to: url)
132 MapEditor(document: .constant(MapDocument()), url: URL(filePath: "test.png")!)