Skip to content

Commit

Permalink
Fix key press modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanbaird committed Sep 7, 2024
1 parent fcea4ec commit 88d7904
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 112 deletions.
138 changes: 64 additions & 74 deletions Ice/UI/Pickers/CustomGradientPicker/CustomGradientPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,6 @@ struct CustomGradientPicker: View {
.onChange(of: gradient) { _, newValue in
gradientChanged(to: newValue)
}
.onKeyDown(key: .escape) {
selectedStop = nil
}
.onKeyDown(key: .delete) {
deleteSelectedStop()
}
.readWindow(window: $window)
}

Expand Down Expand Up @@ -106,7 +100,22 @@ struct CustomGradientPicker: View {
private func selectionReader(geometry: GeometryProxy) -> some View {
Color.clear
.localEventMonitor(mask: .leftMouseDown) { event in
leftMouseDown(with: event, in: geometry)
guard
let window = event.window,
self.window === window
else {
return event
}
let locationInWindow = event.locationInWindow
guard window.contentLayoutRect.contains(locationInWindow) else {
return event
}
let globalFrame = geometry.frame(in: .global)
let flippedLocation = CGPoint(x: locationInWindow.x, y: window.frame.height - locationInWindow.y)
if !globalFrame.contains(flippedLocation) {
selectedStop = nil
}
return event
}
}

Expand All @@ -115,23 +124,20 @@ struct CustomGradientPicker: View {
Color.clear
.contentShape(borderShape)
.gesture(
DragGesture(
minimumDistance: 0,
coordinateSpace: .local
)
.onEnded { value in
guard abs(value.translation.width) <= 2 else {
return
}
let frame = geometry.frame(in: .local)
guard frame.contains(value.location) else {
return
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onEnded { value in
guard abs(value.translation.width) <= 2 else {
return
}
let frame = geometry.frame(in: .local)
guard frame.contains(value.location) else {
return
}
let x = value.location.x
let width = frame.width - 10
let location = (x / width) - (6 / width)
insertStop(at: location, select: true)
}
let x = value.location.x
let width = frame.width - 10
let location = (x / width) - (6 / width)
insertStop(at: location)
}
)
}

Expand All @@ -151,31 +157,26 @@ struct CustomGradientPicker: View {
}
}

/// Inserts a new stop with the appropriate color
/// at the given location in the gradient.
private func insertStop(at location: CGFloat) {
/// Inserts a new stop with the appropriate color at the given location
/// in the gradient.
private func insertStop(at location: CGFloat, select: Bool) {
var location = location.clamped(to: 0...1)
if (0.48...0.52).contains(location) {
location = 0.5
}
let newStop: ColorStop
if
let newStop: ColorStop = if
!gradient.stops.isEmpty,
let color = gradient.color(at: location)
{
newStop = ColorStop(
color: color,
location: location
)
ColorStop(color: color, location: location)
} else {
newStop = ColorStop(
color: CGColor(srgbRed: 0, green: 0, blue: 0, alpha: 1),
location: location
)
ColorStop(color: .black, location: location)
}
gradient.stops.append(newStop)
DispatchQueue.main.async {
self.selectedStop = newStop
if select {
DispatchQueue.main.async {
self.selectedStop = newStop
}
}
}

Expand All @@ -199,42 +200,6 @@ struct CustomGradientPicker: View {
self.gradient = gradient
}
}

private func deleteSelectedStop() {
guard
let selectedStop,
let index = gradient.stops.firstIndex(of: selectedStop)
else {
return
}
gradient.stops.remove(at: index)
self.selectedStop = nil
}

private func leftMouseDown(
with event: NSEvent,
in geometry: GeometryProxy
) -> NSEvent? {
guard
let window = event.window,
self.window === window
else {
return event
}
let locationInWindow = event.locationInWindow
guard window.contentLayoutRect.contains(locationInWindow) else {
return event
}
let globalFrame = geometry.frame(in: .global)
let flippedLocation = CGPoint(
x: locationInWindow.x,
y: window.frame.height - locationInWindow.y
)
if !globalFrame.contains(flippedLocation) {
selectedStop = nil
}
return event
}
}

private struct CustomGradientPickerHandle: View {
Expand All @@ -243,6 +208,7 @@ private struct CustomGradientPickerHandle: View {
@Binding var zOrderedStops: [ColorStop]
@Binding var cancellables: Set<AnyCancellable>
@State private var canActivate = true
@FocusState private var isFocused: Bool

let index: Int
let supportsOpacity: Bool
Expand Down Expand Up @@ -326,6 +292,16 @@ private struct CustomGradientPickerHandle: View {
}
}
}
.focusable()
.focusEffectDisabled()
.focused($isFocused)
.onKeyPress(.escape) {
selectedStop = nil
return .handled
}
.onDeleteCommand {
deleteSelectedStop()
}
}
}

Expand Down Expand Up @@ -396,6 +372,8 @@ private struct CustomGradientPickerHandle: View {
zOrderedStops.append(zOrderedStops.remove(at: index))
}

isFocused = true

var c = Set<AnyCancellable>()

NSColorPanel.shared.publisher(for: \.color)
Expand Down Expand Up @@ -433,6 +411,18 @@ private struct CustomGradientPickerHandle: View {
cancellable.cancel()
}
cancellables.removeAll()
isFocused = false
}

private func deleteSelectedStop() {
guard
let selectedStop,
let index = gradient.stops.firstIndex(of: selectedStop)
else {
return
}
gradient.stops.remove(at: index)
self.selectedStop = nil
}
}

Expand Down
36 changes: 23 additions & 13 deletions Ice/UI/SectionedList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct SectionedList<ItemID: Hashable>: View {
@Binding var selection: ItemID?
@State private var itemFrames = [ItemID: CGRect]()
@State private var scrollIndicatorsFlashTrigger = 0
@FocusState private var focused: Bool

let spacing: CGFloat
let items: [SectionedListItem<ItemID>]
Expand Down Expand Up @@ -62,6 +63,28 @@ struct SectionedList<ItemID: Hashable>: View {
}
}
}
.focusable()
.focused($focused)
.focusEffectDisabled()
.onKeyPress(.downArrow) {
if let nextSelectableItem {
selection = nextSelectableItem.id
}
return .handled
}
.onKeyPress(.upArrow) {
if let previousSelectableItem {
selection = previousSelectableItem.id
}
return .handled
}
.onKeyPress(.return) {
items.first { $0.id == selection }?.action?()
return .handled
}
.task {
focused = true
}
}

@ViewBuilder
Expand All @@ -76,19 +99,6 @@ struct SectionedList<ItemID: Hashable>: View {
.id(item.id)
}
}
.onKeyDown(key: .downArrow) {
if let nextSelectableItem {
selection = nextSelectableItem.id
}
}
.onKeyDown(key: .upArrow) {
if let previousSelectableItem {
selection = previousSelectableItem.id
}
}
.onKeyDown(key: .return) {
items.first { $0.id == selection }?.action?()
}
.onChange(of: selection) {
guard
let selection,
Expand Down
31 changes: 17 additions & 14 deletions Ice/UI/ViewModifiers/LocalEventMonitorModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,30 @@

import SwiftUI

private class LocalEventMonitorModifierState: ObservableObject {
let monitor: LocalEventMonitor
@Observable
private class LocalEventMonitorModifierState {
var monitor: LocalEventMonitor

init(mask: NSEvent.EventTypeMask, action: @escaping (NSEvent) -> NSEvent?) {
self.monitor = LocalEventMonitor(mask: mask, handler: action)
self.monitor.start()
}

deinit {
monitor.stop()
}
}

private struct LocalEventMonitorModifier: ViewModifier {
@StateObject private var state: LocalEventMonitorModifierState
private struct LocalEventMonitorView<Content: View>: View {
@State private var state: LocalEventMonitorModifierState

init(mask: NSEvent.EventTypeMask, action: @escaping (NSEvent) -> NSEvent?) {
let state = LocalEventMonitorModifierState(mask: mask, action: action)
self._state = StateObject(wrappedValue: state)
let content: Content

init(mask: NSEvent.EventTypeMask, action: @escaping (NSEvent) -> NSEvent?, @ViewBuilder content: () -> Content) {
self._state = State(wrappedValue: LocalEventMonitorModifierState(mask: mask, action: action))
self.content = content()
}

func body(content: Content) -> some View {
var body: some View {
content
.onAppear {
state.monitor.start()
}
}
}

Expand All @@ -43,6 +44,8 @@ extension View {
mask: NSEvent.EventTypeMask,
action: @escaping (NSEvent) -> NSEvent?
) -> some View {
modifier(LocalEventMonitorModifier(mask: mask, action: action))
LocalEventMonitorView(mask: mask, action: action) {
self
}
}
}
22 changes: 11 additions & 11 deletions Ice/UI/ViewModifiers/OnKeyDown.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
import SwiftUI

extension View {
/// Returns a view that performs the given action when
/// the specified key is pressed.
func onKeyDown(key: KeyCode, action: @escaping () -> Void) -> some View {
localEventMonitor(mask: .keyDown) { event in
if event.keyCode == key.rawValue {
action()
return nil
}
return event
}
}
// /// Returns a view that performs the given action when
// /// the specified key is pressed.
// func onKeyDown(key: KeyCode, action: @escaping () -> Void) -> some View {
// localEventMonitor(mask: .keyDown) { event in
// if event.keyCode == key.rawValue {
// action()
// return nil
// }
// return event
// }
// }
}

0 comments on commit 88d7904

Please sign in to comment.