+/*
+ Copyright (C) 2024 Rubén Beltrán del Río
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see https://map.tranquil.systems.
+ */
import SwiftUI
struct MapEditor: View {
@Binding var document: MapDocument
var url: URL?
@State var selectedEvolution: StageType = .behavior
+ @State var isSearching: Bool = false
@AppStorage("viewStyle") var viewStyle: ViewStyle = .horizontal
let zoomRange = Constants.kMinZoom...Constants.kMaxZoom
@AppStorage("zoom") var zoom = 1.0
@State var lastZoom = 1.0
+ @State var searchTerm = ""
+ @State var selectedTerm = 0
+
+ var results: [Range<String.Index>] {
+ if !isSearching || searchTerm.isEmpty {
+ return []
+ }
+ let options: NSString.CompareOptions = [.caseInsensitive, .diacriticInsensitive]
+ var searchRange = document.text.startIndex..<document.text.endIndex
+ var ranges: [Range<String.Index>] = []
+
+ while let range = document.text.range(of: searchTerm, options: options, range: searchRange) {
+ ranges.append(range)
+ searchRange = range.upperBound..<document.text.endIndex
+ }
+
+ return ranges
+
+ }
var body: some View {
VStack(spacing: 0) {
+ if isSearching {
+ SearchBar(
+ term: $searchTerm,
+ onNext: {
+ withAnimation {
+ if results.count > 0 {
+ selectedTerm = (selectedTerm + 1) % results.count
+ }
+ }
+ },
+ onPrevious: {
+ withAnimation {
+ if results.count > 0 {
+ if selectedTerm == 0 {
+ selectedTerm = results.count - 1
+ } else {
+ selectedTerm = (selectedTerm - 1) % results.count
+ }
+ }
+ }
+ },
+ onSubmit: {
+
+ },
+ onDismiss: {
+ withAnimation {
+ isSearching = false
+ }
+ }
+ )
+ .onChange(
+ of: searchTerm,
+ {
+ selectedTerm = 0
+ })
+ Divider()
+ }
adaptiveStack {
ZStack(alignment: .topLeading) {
- MapTextEditor(document: $document)
+ MapTextEditor(document: $document, highlightRanges: results, selectedRange: selectedTerm)
.background(Color.ui.background)
.foregroundColor(Color.ui.foreground)
.frame(minHeight: 96.0)
}.padding(4.0)
}.toolbar {
HStack {
- Button(action: saveImage) {
- Image(systemName: "photo")
- }
- .help("Export Image (⌘E)")
- .padding(.vertical, 4.0).padding(.leading, 4.0).padding(.trailing, 8.0)
+ EvolutionPicker(selectedEvolution: $selectedEvolution)
}
- EvolutionPicker(selectedEvolution: $selectedEvolution)
- }
+ }.focusedSceneValue(\.isSearching, $isSearching)
+ .focusedSceneValue(\.selectedEvolution, $selectedEvolution)
}
@ViewBuilder
}
private func onDragVertex(vertex: Vertex, x: CGFloat, y: CGFloat) {
- print("Dragging: \(vertex), \(x), \(y)")
- }
-
- private func saveImage() {
- if let image = document.exportAsImage(withEvolution: selectedEvolution) {
-
- let filename = url?.deletingPathExtension().lastPathComponent ?? "Untitled"
-
- let savePanel = NSSavePanel()
- savePanel.allowedContentTypes = [.png]
- savePanel.canCreateDirectories = true
- savePanel.isExtensionHidden = false
- savePanel.title = "Save \(filename) as image"
- savePanel.message = "Choose a location to save the image"
- savePanel.nameFieldStringValue = "\(filename).png"
- savePanel.begin { result in
- if result == .OK, let url = savePanel.url {
- if let tiffRepresentation = image.tiffRepresentation {
- let bitmapImage = NSBitmapImageRep(data: tiffRepresentation)
- let pngData = bitmapImage?.representation(using: .png, properties: [:])
- do {
- try pngData?.write(to: url)
- } catch {
- return
- }
- }
- }
- }
- }
}
}