VMToolbarOrnamentModifier.swift 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. //
  2. // Copyright © 2023 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. import SwiftUI
  17. struct VMToolbarOrnamentModifier: ViewModifier {
  18. @Binding var state: VMWindowState
  19. @EnvironmentObject private var session: VMSessionState
  20. @AppStorage("ToolbarIsCollapsed") private var isCollapsed: Bool = false
  21. func body(content: Content) -> some View {
  22. content.ornament(visibility: isCollapsed ? .hidden : .visible, attachmentAnchor: .scene(.top)) {
  23. HStack {
  24. Button {
  25. if session.vm.state == .started {
  26. state.alert = .powerDown
  27. } else {
  28. state.alert = .terminateApp
  29. }
  30. } label: {
  31. Label(state.isRunning ? "Power Off" : "Quit", systemImage: state.isRunning ? "power" : "xmark")
  32. }
  33. .disabled(state.isBusy)
  34. Button {
  35. session.pauseResume()
  36. } label: {
  37. Label(state.isRunning ? "Pause" : "Play", systemImage: state.isRunning ? "pause" : "play")
  38. }
  39. .disabled(state.isBusy)
  40. Button {
  41. state.alert = .restart
  42. } label: {
  43. Label("Restart", systemImage: "restart")
  44. }
  45. .disabled(state.isBusy)
  46. Divider()
  47. if case .serial(_, _) = state.device {
  48. Button {
  49. let template = session.qemuConfig.serials[state.device!.configIndex].terminal?.resizeCommand
  50. state.toggleDisplayResize(command: template)
  51. } label: {
  52. Label("Zoom", systemImage: state.isViewportChanged ? "arrow.down.right.and.arrow.up.left" : "arrow.up.left.and.arrow.down.right")
  53. }
  54. .disabled(state.isBusy)
  55. }
  56. #if WITH_USB
  57. if session.vm.hasUsbRedirection {
  58. VMToolbarUSBMenuView()
  59. .disabled(state.isBusy)
  60. }
  61. #endif
  62. VMToolbarDriveMenuView(config: session.qemuConfig)
  63. .disabled(state.isBusy)
  64. VMToolbarDisplayMenuView(state: $state)
  65. .disabled(state.isBusy)
  66. Button {
  67. state.isKeyboardRequested = true
  68. } label: {
  69. Label("Keyboard", systemImage: "keyboard")
  70. }
  71. .disabled(state.isBusy)
  72. Divider()
  73. Button {
  74. isCollapsed = true
  75. } label: {
  76. Label("Hide Controls", systemImage: "chevron.right")
  77. }
  78. }
  79. .modifier(ToolbarOrnamentViewModifier())
  80. }
  81. .ornament(visibility: isCollapsed ? .visible : .hidden, attachmentAnchor: .scene(.topTrailing)) {
  82. Button {
  83. isCollapsed = false
  84. } label: {
  85. Label("Show Controls", systemImage: "chevron.left")
  86. }
  87. .modifier(ToolbarOrnamentViewModifier())
  88. }
  89. }
  90. }
  91. // the following was suggested by Apple via Feedback to look close to .toolbar() with .bottomOrnament
  92. private struct ToolbarOrnamentViewModifier: ViewModifier {
  93. func body(content: Content) -> some View {
  94. content
  95. .buttonBorderShape(.capsule)
  96. .buttonStyle(.borderless)
  97. .labelStyle(.iconOnly)
  98. .padding(12)
  99. .glassBackgroundEffect()
  100. }
  101. }