Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import SwiftUI
import Cocoa

final class UtilityAreaTerminal: ObservableObject, Identifiable, Equatable {
let id: UUID
Expand Down Expand Up @@ -36,6 +37,12 @@ struct UtilityAreaTerminalView: View {
private var darkAppearance
@AppSettings(\.theme.useThemeBackground)
private var useThemeBackground
@AppSettings(\.textEditing.font)
private var textEditingFont
@AppSettings(\.terminal.font)
private var terminalFont
@AppSettings(\.terminal.useTextEditorFont)
private var useTextEditorFont

@Environment(\.colorScheme)
private var colorScheme
Expand All @@ -52,6 +59,10 @@ struct UtilityAreaTerminalView: View {

@State private var popoverSource: CGRect = .zero

var font: NSFont {
useTextEditorFont == true ? textEditingFont.current : terminalFont.current
}

private func initializeTerminals() {
let id = UUID()

Expand Down Expand Up @@ -101,31 +112,52 @@ struct UtilityAreaTerminalView: View {
utilityAreaViewModel.terminals.move(fromOffsets: source, toOffset: destination)
}

func fontTotalHeight(nsFont: NSFont) -> CGFloat {
let ctFont = nsFont as CTFont
let ascent = CTFontGetAscent(ctFont)
let descent = CTFontGetDescent(ctFont)
let leading = CTFontGetLeading(ctFont)

return ascent + descent + leading
}

var body: some View {
UtilityAreaTabView(model: utilityAreaViewModel.tabViewModel) { tabState in
ZStack {
if utilityAreaViewModel.selectedTerminals.isEmpty {
CEContentUnavailableView("No Selection")
}
ForEach(utilityAreaViewModel.terminals) { terminal in
TerminalEmulatorView(
url: terminal.url!,
shellType: terminal.shell,
onTitleChange: { [weak terminal] newTitle in
guard let id = terminal?.id else { return }
// This can be called whenever, even in a view update so it needs to be dispatched.
DispatchQueue.main.async { [weak utilityAreaViewModel] in
utilityAreaViewModel?.updateTerminal(id, title: newTitle)
} else {
GeometryReader { geometry in
let containerHeight = geometry.size.height
let totalFontHeight = fontTotalHeight(nsFont: font).rounded(.up)
let constrainedHeight = containerHeight - containerHeight.truncatingRemainder(
dividingBy: totalFontHeight
)
ForEach(utilityAreaViewModel.terminals) { terminal in
VStack(spacing: 0) {
Spacer(minLength: 0)
.frame(minHeight: 0)
TerminalEmulatorView(
url: terminal.url!,
shellType: terminal.shell,
onTitleChange: { [weak terminal] newTitle in
guard let id = terminal?.id else { return }
// This can be called whenever, even in a view update
// so it needs to be dispatched.
DispatchQueue.main.async { [weak utilityAreaViewModel] in
utilityAreaViewModel?.updateTerminal(id, title: newTitle)
}
}
)
.frame(height: constrainedHeight - totalFontHeight + 1)
}
.disabled(terminal.id != utilityAreaViewModel.selectedTerminals.first)
.opacity(terminal.id == utilityAreaViewModel.selectedTerminals.first ? 1 : 0)
}
)
.padding(.top, 10)
.padding(.horizontal, 10)
.contentShape(Rectangle())
.disabled(terminal.id != utilityAreaViewModel.selectedTerminals.first)
.opacity(terminal.id == utilityAreaViewModel.selectedTerminals.first ? 1 : 0)
}
}
}
.padding(.horizontal, 10)
.paneToolbar {
PaneToolbarSection {
UtilityAreaTerminalPicker(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ class UtilityAreaViewModel: ObservableObject {
}

func togglePanel() {
withAnimation {
self.isCollapsed.toggle()
}
self.isMaximized = false
self.isCollapsed.toggle()
}

/// Update a terminal's title.
Expand Down
10 changes: 3 additions & 7 deletions CodeEdit/Features/UtilityArea/Views/PaneToolbar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ struct PaneToolbar<Content: View>: View {
.frame(width: 24)
}
.opacity(0)
Divider().opacity(0)
}
content
if model.hasTrailingSidebar
Expand All @@ -35,16 +34,13 @@ struct PaneToolbar<Content: View>: View {
&& model.trailingSidebarIsCollapsed)
|| paneArea == .trailing
) || !model.hasTrailingSidebar {
Divider().opacity(0)
PaneToolbarSection {
if model.hasTrailingSidebar {
if model.hasTrailingSidebar {
PaneToolbarSection {
Spacer()
.frame(width: 24)
}
Spacer()
.frame(width: 24)
.opacity(0)
}
.opacity(0)
}
}
.buttonStyle(.icon(size: 24))
Expand Down
23 changes: 0 additions & 23 deletions CodeEdit/Features/UtilityArea/Views/UtilityAreaView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,5 @@ struct UtilityAreaView: View {
.overlay(Color(nsColor: colorScheme == .dark ? .black : .clear))
}
}
.overlay(alignment: .bottomTrailing) {
HStack(spacing: 5) {
Divider()
HStack(spacing: 0) {
Button {
utilityAreaViewModel.isMaximized.toggle()
} label: {
Image(systemName: "arrowtriangle.up.square")
}
.buttonStyle(.icon(isActive: utilityAreaViewModel.isMaximized, size: 24))
}
}
.colorScheme(
utilityAreaViewModel.selectedTerminals.isEmpty
? colorScheme
: matchAppearance && darkAppearance
? themeModel.selectedDarkTheme?.appearance == .dark ? .dark : .light
: themeModel.selectedTheme?.appearance == .dark ? .dark : .light
)
.padding(.horizontal, 5)
.padding(.vertical, 8)
.frame(maxHeight: 27)
}
}
}
75 changes: 63 additions & 12 deletions CodeEdit/WorkspaceView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ struct WorkspaceView: View {
@State private var showingAlert = false
@State private var terminalCollapsed = true
@State private var editorCollapsed = false
@State private var editorsHeight: CGFloat = 0
@State private var drawerHeight: CGFloat = 0

private let statusbarHeight: CGFloat = 29

private var keybindings: KeybindingManager = .shared

Expand All @@ -36,28 +40,75 @@ struct WorkspaceView: View {
VStack {
SplitViewReader { proxy in
SplitView(axis: .vertical) {
EditorLayoutView(
layout: editorManager.isFocusingActiveEditor
? editorManager.activeEditor.getEditorLayout() ?? editorManager.editorLayout
: editorManager.editorLayout,
focus: $focusedEditor
)
ZStack {
GeometryReader { geo in
EditorLayoutView(
layout: editorManager.isFocusingActiveEditor
? editorManager.activeEditor.getEditorLayout() ?? editorManager.editorLayout
: editorManager.editorLayout,
focus: $focusedEditor
)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onChange(of: geo.size.height) { newHeight in
editorsHeight = newHeight
}
.onAppear {
editorsHeight = geo.size.height
}
}
}
.frame(minHeight: 170 + 29 + 29)
.collapsable()
.collapsed($utilityAreaViewModel.isMaximized)
.frame(minHeight: 170 + 29 + 29)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.holdingPriority(.init(1))
.safeAreaInset(edge: .bottom, spacing: 0) {
StatusBarView(proxy: proxy)
}
UtilityAreaView()
Rectangle()
.collapsable()
.collapsed($utilityAreaViewModel.isCollapsed)
.opacity(0)
.frame(idealHeight: 260)
.frame(minHeight: 100)
.background {
GeometryReader { geo in
Rectangle()
.opacity(0)
.onChange(of: geo.size.height) { newHeight in
drawerHeight = newHeight
}
.onAppear {
drawerHeight = geo.size.height
}
}
}
}
.edgesIgnoringSafeArea(.top)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.overlay(alignment: .top) {
ZStack(alignment: .top) {
UtilityAreaView()
.frame(height: utilityAreaViewModel.isMaximized ? nil : drawerHeight)
.frame(maxHeight: utilityAreaViewModel.isMaximized ? .infinity : nil)
.padding(.top, utilityAreaViewModel.isMaximized ? statusbarHeight + 1 : 0)
.offset(y: utilityAreaViewModel.isMaximized ? 0 : editorsHeight + 1)
VStack(spacing: 0) {
StatusBarView(proxy: proxy)
if utilityAreaViewModel.isMaximized {
PanelDivider()
}
}
.offset(y: utilityAreaViewModel.isMaximized ? 0 : editorsHeight - statusbarHeight)
}
}
.onChange(of: focusedEditor) { newValue in
/// update active tab group only if the new one is not the same with it.
if let newValue, editorManager.activeEditor != newValue {
editorManager.activeEditor = newValue
}
}
.onChange(of: editorManager.activeEditor) { newValue in
if newValue != focusedEditor {
focusedEditor = newValue
}
}
.task {
themeModel.colorScheme = colorScheme

Expand Down