Commit 6cb5debb74
Verified · cmc
Layout: unified · split
App/Sources/ScaleScreen.swift +23 −7
| @@ -15,6 +15,22 @@ struct ScaleScreen: View { | ||
| 15 | 15 | |
| 16 | 16 | private var width: Double { pow(10, exponent) } |
| 17 | 17 | |
| 18 | /// Zooms by a factor of ten per tap, snapping to the nearest whole power of ten first. | |
| 19 | private func zoomButton(_ symbol: String, _ label: String, by step: Double) -> some View { | |
| 20 | Button { | |
| 21 | withAnimation(.easeInOut(duration: 0.35)) { | |
| 22 | let snapped = step < 0 ? ceil(exponent) - 1 : floor(exponent) + 1 | |
| 23 | exponent = min(max(snapped, range.lowerBound), range.upperBound) | |
| 24 | } | |
| 25 | } label: { | |
| 26 | Image(systemName: symbol).font(.title3).frame(width: 48, height: 48) | |
| 27 | .background(ink.opacity(0.1), in: Circle()) | |
| 28 | } | |
| 29 | .buttonStyle(.plain) | |
| 30 | .accessibilityLabel(label) | |
| 31 | .disabled(step < 0 ? exponent <= range.lowerBound : exponent >= range.upperBound) | |
| 32 | } | |
| 33 | ||
| 18 | 34 | /// The width to two significant figures, for the label. |
| 19 | 35 | private var roundedWidth: Double { |
| 20 | 36 | let p = pow(10, floor(exponent) - 1) |
| @@ -41,7 +57,7 @@ struct ScaleScreen: View { | ||
| 41 | 57 | selected = o.page.flatMap { Library.page(id: $0) } |
| 42 | 58 | } label: { |
| 43 | 59 | VStack(spacing: 6) { |
| 44 | Circle().fill(o.page == nil ? ink.opacity(0.18) : ink.opacity(0.55)) | |
| 60 | Circle().fill(o.page == nil ? ink.opacity(0.18) : (Color(hex: o.page.flatMap { Library.page(id: $0) }?.drawing?.color) ?? ink.opacity(0.55))) | |
| 45 | 61 | .overlay(Circle().stroke(ink.opacity(0.5), lineWidth: 0.5)) |
| 46 | 62 | .frame(width: d, height: d) |
| 47 | 63 | Text(o.name).font(.caption2).lineLimit(1) |
| @@ -67,13 +83,13 @@ struct ScaleScreen: View { | ||
| 67 | 83 | exponent = min(max(pinchStart! - log10(g.magnification), range.lowerBound), range.upperBound) |
| 68 | 84 | } |
| 69 | 85 | .onEnded { _ in pinchStart = nil }) |
| 70 | Slider(value: $exponent, in: range) { Text("Width shown") } minimumValueLabel: { | |
| 71 | Image(systemName: "plus.magnifyingglass") | |
| 72 | } maximumValueLabel: { | |
| 73 | Image(systemName: "minus.magnifyingglass") | |
| 86 | HStack(spacing: 12) { | |
| 87 | zoomButton("plus.magnifyingglass", "Zoom in", by: -1) | |
| 88 | Slider(value: $exponent, in: range) { Text("Width shown") } | |
| 89 | .accessibilityValue(Library.formatSize(roundedWidth)) | |
| 90 | zoomButton("minus.magnifyingglass", "Zoom out", by: 1) | |
| 74 | 91 | } |
| 75 | .accessibilityValue(Library.formatSize(roundedWidth)) | |
| 76 | Text("The slider spans 300 m to the observable universe; each tenth of it is a factor of ten. Pinch to zoom. Objects without a Library page are drawn faint.") | |
| 92 | Text("Each tap of + or − is a factor of ten. You can also drag the slider or pinch. Objects without a Library page are drawn faint.") | |
| 77 | 93 | .font(.caption2).dimmed(0.5) |
| 78 | 94 | } |
| 79 | 95 | .padding(20) |