diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index f0604eb48c..61e7b24f3d 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -10,15 +10,155 @@ import SwiftUI import CodeFile import Overlays -class CodeEditWindowController: NSWindowController { +class CodeEditWindowController: NSWindowController, NSToolbarDelegate { var workspace: WorkspaceDocument? var quickOpenPanel: OverlayPanel? + + private var splitViewController: NSSplitViewController! { + get { return contentViewController as? NSSplitViewController } + set { contentViewController = newValue } + } + + init(window: NSWindow, workspace: WorkspaceDocument) { + super.init(window: window) + self.workspace = workspace + + setupSplitView(with: workspace) + setupToolbar() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupSplitView(with workspace: WorkspaceDocument) { + let splitVC = NSSplitViewController() + + let navigatorView = NavigatorSidebar(workspace: workspace, windowController: self) + let navigator = NSSplitViewItem( + sidebarWithViewController: NSHostingController(rootView: navigatorView) + ) + navigator.minimumThickness = 260 + splitVC.addSplitViewItem(navigator) + + let workspaceView = WorkspaceView(windowController: self, workspace: workspace) + let mainContent = NSSplitViewItem( + viewController: NSHostingController(rootView: workspaceView) + ) + splitVC.addSplitViewItem(mainContent) + + let inspectorView = InspectorSidebar(workspace: workspace, windowController: self) + let inspector = NSSplitViewItem( + viewController: NSHostingController(rootView: inspectorView) + ) + inspector.minimumThickness = 260 + inspector.maximumThickness = 260 + inspector.isCollapsed = true + inspector.collapseBehavior = .preferResizingSiblingsWithFixedSplitView + splitVC.addSplitViewItem(inspector) + + self.splitViewController = splitVC + } + + private func setupToolbar() { + let toolbar = NSToolbar(identifier: UUID().uuidString) + toolbar.delegate = self + toolbar.displayMode = .labelOnly + self.window?.toolbarStyle = .unifiedCompact + self.window?.titlebarSeparatorStyle = .none + self.window?.toolbar = toolbar + } + + // MARK: - Toolbar + + func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [ + .toggleFirstSidebarItem, + .sidebarTrackingSeparator, + .flexibleSpace, + .flexibleSpace, + .toggleLastSidebarItem + ] + } + + func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { + return [ + .toggleFirstSidebarItem, + .sidebarTrackingSeparator, + .flexibleSpace, + .itemListTrackingSeparator, + .toggleLastSidebarItem + ] + } + + // swiftlint:disable all + func toolbar( + _ toolbar: NSToolbar, + itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, + willBeInsertedIntoToolbar flag: Bool + ) -> NSToolbarItem? { + switch itemIdentifier { + case .itemListTrackingSeparator: + if ((splitViewController) != nil) { + return NSTrackingSeparatorToolbarItem( + identifier: .itemListTrackingSeparator, + splitView: splitViewController.splitView, + dividerIndex: 1 + ) + } else { + return nil + } + case .toggleFirstSidebarItem: + let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier.toggleFirstSidebarItem) + toolbarItem.label = "Navigator Sidebar" + toolbarItem.paletteLabel = " Navigator Sidebar" + toolbarItem.toolTip = "Hide or show the Navigator" + toolbarItem.isBordered = true + toolbarItem.target = self + toolbarItem.action = #selector(self.toggleFirstPanel) + toolbarItem.image = NSImage( + systemSymbolName: "sidebar.leading", + accessibilityDescription: nil + )?.withSymbolConfiguration(.init(scale: .large)) + + return toolbarItem + case .toggleLastSidebarItem: + let toolbarItem = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier.toggleFirstSidebarItem) + toolbarItem.label = "Inspector Sidebar" + toolbarItem.paletteLabel = "Inspector Sidebar" + toolbarItem.toolTip = "Hide or show the Inspectors" + toolbarItem.isBordered = true + toolbarItem.target = self + toolbarItem.action = #selector(self.toggleLastPanel) + toolbarItem.image = NSImage( + systemSymbolName: "sidebar.trailing", + accessibilityDescription: nil + )?.withSymbolConfiguration(.init(scale: .large)) + + return toolbarItem + default: + return NSToolbarItem(itemIdentifier: itemIdentifier) + } + } + override func windowDidLoad() { super.windowDidLoad() + } + + @objc func toggleFirstPanel() { + guard let firstSplitView = splitViewController.splitViewItems.first else { return } + firstSplitView.animator().isCollapsed.toggle() + } - // Implement this method to handle any initialization after your window controller's - // window has been loaded from its nib file. + @objc func toggleLastPanel() { + guard let lastSplitView = splitViewController.splitViewItems.last else { return } + lastSplitView.animator().isCollapsed.toggle() + if lastSplitView.animator().isCollapsed { + window?.toolbar?.removeItem(at: 3) + } else { + window?.toolbar?.insertItem(withItemIdentifier: .itemListTrackingSeparator, at: 3) + } } private func getSelectedCodeFile() -> CodeFileDocument? { @@ -57,3 +197,9 @@ class CodeEditWindowController: NSWindowController { } } } + +private extension NSToolbarItem.Identifier { + static let toggleFirstSidebarItem: NSToolbarItem.Identifier = NSToolbarItem.Identifier("ToggleFirstSidebarItem") + static let toggleLastSidebarItem: NSToolbarItem.Identifier = NSToolbarItem.Identifier("ToggleLastSidebarItem") + static let itemListTrackingSeparator = NSToolbarItem.Identifier("ItemListTrackingSeparator") +} diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index 8ca68bea4c..b1f3ac1082 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -107,15 +107,11 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { backing: .buffered, defer: false ) window.center() - window.toolbar = NSToolbar(identifier: UUID().uuidString) - window.toolbarStyle = .unifiedCompact - window.titlebarSeparatorStyle = .line - window.toolbar?.displayMode = .iconOnly - window.toolbar?.insertItem(withItemIdentifier: .toggleSidebar, at: 0) - let windowController = CodeEditWindowController(window: window) - windowController.workspace = self - let contentView = WorkspaceView(windowController: windowController, workspace: self) - window.contentView = NSHostingView(rootView: contentView) + window.minSize = .init(width: 1000, height: 600) + let windowController = CodeEditWindowController( + window: window, + workspace: self + ) self.addWindowController(windowController) } diff --git a/CodeEdit/InspectorSidebar/InspectorSidebar.swift b/CodeEdit/InspectorSidebar/InspectorSidebar.swift index 418198a71a..7b10140084 100644 --- a/CodeEdit/InspectorSidebar/InspectorSidebar.swift +++ b/CodeEdit/InspectorSidebar/InspectorSidebar.swift @@ -31,6 +31,7 @@ struct InspectorSidebar: View { } .frame( minWidth: 250, + idealWidth: 260, minHeight: 0, maxHeight: .infinity, alignment: .center diff --git a/CodeEdit/NavigatorSidebar/FindNavigator/FindNavigatorResultList.swift b/CodeEdit/NavigatorSidebar/FindNavigator/FindNavigatorResultList.swift index b431abd167..c4c52f7c4e 100644 --- a/CodeEdit/NavigatorSidebar/FindNavigator/FindNavigatorResultList.swift +++ b/CodeEdit/NavigatorSidebar/FindNavigator/FindNavigatorResultList.swift @@ -33,7 +33,9 @@ struct FindNavigatorResultList: View { state.workspace.openFile(item: foundFile.file) } } - }.onChange(of: selectedResult) { newValue in + } + .listStyle(.sidebar) + .onChange(of: selectedResult) { newValue in if let file = newValue?.file { state.workspace.openFile(item: file) } diff --git a/CodeEdit/NavigatorSidebar/ProjectNavigator/ProjectNavigator.swift b/CodeEdit/NavigatorSidebar/ProjectNavigator/ProjectNavigator.swift index 3edbfedc66..5f2c12b45a 100644 --- a/CodeEdit/NavigatorSidebar/ProjectNavigator/ProjectNavigator.swift +++ b/CodeEdit/NavigatorSidebar/ProjectNavigator/ProjectNavigator.swift @@ -42,6 +42,7 @@ struct ProjectNavigator: View { .padding(.vertical, 8) } } + .listStyle(.sidebar) .listRowInsets(.init()) .onChange(of: selection) { newValue in guard let id = newValue, diff --git a/CodeEdit/WorkspaceView.swift b/CodeEdit/WorkspaceView.swift index 621b9bb6d9..6ae26260c5 100644 --- a/CodeEdit/WorkspaceView.swift +++ b/CodeEdit/WorkspaceView.swift @@ -35,14 +35,21 @@ struct WorkspaceView: View { var showInspector = true var body: some View { - NavigationView { + ZStack { if workspace.workspaceClient != nil { - content + WorkspaceCodeFileView(windowController: windowController, workspace: workspace) + .safeAreaInset(edge: .bottom) { + if let url = workspace.fileURL { + StatusBarView(workspaceURL: url) + } + } + .overlay(alignment: .top) { + Divider() + } } else { EmptyView() } } - .frame(minWidth: 1000, minHeight: 600) .alert(alertTitle, isPresented: $showingAlert, actions: { Button( action: { showingAlert = false }, @@ -55,27 +62,6 @@ struct WorkspaceView: View { } } } - - @ViewBuilder - private var content: some View { - NavigatorSidebar(workspace: workspace, windowController: windowController) - .frame(minWidth: 250) - - HSplitView { - ZStack { - WorkspaceCodeFileView(windowController: windowController, workspace: workspace) - .frame(minWidth: 500, maxHeight: .infinity) - } - .safeAreaInset(edge: .bottom) { - if let url = workspace.fileURL { - StatusBarView(workspaceURL: url) - } - } - .layoutPriority(1) - InspectorSidebar(workspace: workspace, windowController: windowController) - .frame(minWidth: 260, idealWidth: 300, maxHeight: .infinity) - } - } } struct WorkspaceView_Previews: PreviewProvider {