1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-10-28 03:38:54 +03:00

GH-282 Add Workspace

This commit is contained in:
Tae Won Ha 2016-09-18 20:49:42 +02:00
parent 7ef4fce17a
commit f92387db5d
No known key found for this signature in database
GPG Key ID: E40743465B5B8B44
13 changed files with 1412 additions and 2 deletions

View File

@ -0,0 +1,48 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import PureLayout
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
private var workspace: Workspace = Workspace(mainView: NSView())
@IBAction func toggleBars(sender: AnyObject!) {
workspace.toggleAllTools()
}
@IBAction func toggleButtons(sender: AnyObject!) {
workspace.toggleToolButtons()
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
let contentView = self.window.contentView!
let workspace = Workspace(mainView: self.view(NSColor.yellowColor()))
self.workspace = workspace
contentView.addSubview(workspace)
workspace.autoPinEdgesToSuperviewEdges()
workspace.append(tool: WorkspaceTool(title: "Top-1", view: self.view(NSColor.whiteColor())), location: .top)
workspace.append(tool: WorkspaceTool(title: "Right-1", view: self.view(NSColor.whiteColor())), location: .right)
workspace.append(tool: WorkspaceTool(title: "Right-2", view: self.view(NSColor.greenColor())), location: .right)
workspace.append(tool: WorkspaceTool(title: "Left-1", view: self.view(NSColor.whiteColor())), location: .left)
workspace.append(tool: WorkspaceTool(title: "Left-2", view: self.view(NSColor.greenColor())), location: .left)
workspace.append(tool: WorkspaceTool(title: "Left-3", view: self.view(NSColor.magentaColor())), location: .left)
workspace.append(tool: WorkspaceTool(title: "Bottom-1", view: self.view(NSColor.whiteColor())), location: .bottom)
workspace.append(tool: WorkspaceTool(title: "Bottom-2", view: self.view(NSColor.greenColor())), location: .bottom)
}
private func view(color: NSColor) -> NSView {
let view = NSView(forAutoLayout: ())
view.wantsLayer = true
view.layer?.backgroundColor = color.CGColor
return view
}
}

View File

@ -0,0 +1,58 @@
{
"images" : [
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "16x16",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "32x32",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "128x128",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "256x256",
"scale" : "2x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "1x"
},
{
"idiom" : "mac",
"size" : "512x512",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="VimR_Workspace_Demo" customModuleProvider="target">
<connections>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="VimR-Workspace-Demo" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="VimR-Workspace-Demo" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About VimR-Workspace-Demo" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide VimR-Workspace-Demo" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit VimR-Workspace-Demo" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Debug" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Debug" id="bib-Uj-vzu">
<items>
<menuItem title="Toggle Tools" keyEquivalent="\" id="IAo-SY-fd9">
<connections>
<action selector="toggleBars:" target="-1" id="XTB-Vl-cqN"/>
</connections>
</menuItem>
<menuItem title="Toggle Bar Buttons" keyEquivalent="=" id="yUM-CD-4Ay">
<connections>
<action selector="toggleButtons:" target="-1" id="B2v-Vc-Vky"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<window title="VimR-Workspace-Demo" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="vimr-workspace-demo-main-window" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</window>
</objects>
</document>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Tae Won Ha. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View File

@ -41,6 +41,7 @@
4B22F7F21D7C6B9000929B0E /* ImageAndTextTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B22F7F11D7C6B9000929B0E /* ImageAndTextTableCell.swift */; };
4B238BE11D3BF24200CBDD98 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B238BE01D3BF24200CBDD98 /* Application.swift */; };
4B238BEC1D3ED54D00CBDD98 /* AppearancePrefPane.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B238BEB1D3ED54D00CBDD98 /* AppearancePrefPane.swift */; };
4B280EFF1D945DA5003FE725 /* AppKitCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70931D60E04200E12030 /* AppKitCommons.swift */; };
4B2A2BEC1D02261F0074CE9A /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B2A2BE21D0225800074CE9A /* RxCocoa.framework */; };
4B2A2BED1D02261F0074CE9A /* RxCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4B2A2BE21D0225800074CE9A /* RxCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4B2A2BEE1D02261F0074CE9A /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B2A2BE31D0225800074CE9A /* RxSwift.framework */; };
@ -62,6 +63,17 @@
4B56F29D1D29926600C1F92E /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B56F29B1D29926600C1F92E /* Nimble.framework */; };
4B570DC21D303CAF006EDC21 /* NeoVimAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B570DC01D303CAF006EDC21 /* NeoVimAgent.h */; settings = {ATTRIBUTES = (Public, ); }; };
4B570DC31D303CAF006EDC21 /* NeoVimAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B570DC11D303CAF006EDC21 /* NeoVimAgent.m */; };
4B6423961D8EFD7100FC78C8 /* Workspace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423951D8EFD7100FC78C8 /* Workspace.swift */; };
4B6423981D8EFDE000FC78C8 /* WorkspaceBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423971D8EFDE000FC78C8 /* WorkspaceBar.swift */; };
4B64239A1D8EFE3000FC78C8 /* WorkspaceTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */; };
4B6423A21D8EFE7500FC78C8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423A11D8EFE7500FC78C8 /* AppDelegate.swift */; };
4B6423A41D8EFE7500FC78C8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B6423A31D8EFE7500FC78C8 /* Assets.xcassets */; };
4B6423A71D8EFE7500FC78C8 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B6423A51D8EFE7500FC78C8 /* MainMenu.xib */; };
4B6423AC1D8EFE9800FC78C8 /* PureLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B401B131D0454DC00D99EDC /* PureLayout.framework */; };
4B6423AD1D8EFE9800FC78C8 /* PureLayout.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4B401B131D0454DC00D99EDC /* PureLayout.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4B6423AF1D8EFEA800FC78C8 /* Workspace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423951D8EFD7100FC78C8 /* Workspace.swift */; };
4B6423B01D8EFEA800FC78C8 /* WorkspaceBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423971D8EFDE000FC78C8 /* WorkspaceBar.swift */; };
4B6423B11D8EFEA800FC78C8 /* WorkspaceTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */; };
4B6A70941D60E04200E12030 /* AppKitCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70931D60E04200E12030 /* AppKitCommons.swift */; };
4B6A70961D6100E300E12030 /* SwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A70951D6100E300E12030 /* SwiftCommons.swift */; };
4B6A70991D65058A00E12030 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B56F29B1D29926600C1F92E /* Nimble.framework */; };
@ -73,6 +85,8 @@
4BAD81D51D80B5D8004F91AE /* OpenQuicklyFileViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BAD81D41D80B5D8004F91AE /* OpenQuicklyFileViewRow.swift */; };
4BAD84E81D7CA8FC00A79CC3 /* OpenQuicklyFilterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BAD84E71D7CA8FC00A79CC3 /* OpenQuicklyFilterOperation.swift */; };
4BB1BEA91D48773200463C29 /* RxSwiftCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB1BEA81D48773200463C29 /* RxSwiftCommons.swift */; };
4BB489421D952CF6005BB0E8 /* WorkspaceToolButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB489411D952CF6005BB0E8 /* WorkspaceToolButton.swift */; };
4BB489431D952CF6005BB0E8 /* WorkspaceToolButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB489411D952CF6005BB0E8 /* WorkspaceToolButton.swift */; };
4BCADE081D11ED12004DAD0F /* CocoaExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCADE071D11ED12004DAD0F /* CocoaExtensions.swift */; };
4BD3BF931D32A95800082605 /* MainWindowComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD3BF921D32A95800082605 /* MainWindowComponent.swift */; };
4BD3BF971D32B0DB00082605 /* MainWindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD3BF961D32B0DB00082605 /* MainWindowManager.swift */; };
@ -161,6 +175,17 @@
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
4B6423AE1D8EFE9800FC78C8 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
4B6423AD1D8EFE9800FC78C8 /* PureLayout.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
4B6A709B1D65079600E12030 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@ -256,6 +281,14 @@
4B56F29B1D29926600C1F92E /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/Mac/Nimble.framework; sourceTree = SOURCE_ROOT; };
4B570DC01D303CAF006EDC21 /* NeoVimAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NeoVimAgent.h; sourceTree = "<group>"; };
4B570DC11D303CAF006EDC21 /* NeoVimAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NeoVimAgent.m; sourceTree = "<group>"; };
4B6423951D8EFD7100FC78C8 /* Workspace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Workspace.swift; path = Workspace/Workspace.swift; sourceTree = "<group>"; };
4B6423971D8EFDE000FC78C8 /* WorkspaceBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WorkspaceBar.swift; path = Workspace/WorkspaceBar.swift; sourceTree = "<group>"; };
4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WorkspaceTool.swift; path = Workspace/WorkspaceTool.swift; sourceTree = "<group>"; };
4B64239F1D8EFE7500FC78C8 /* VimR-Workspace-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "VimR-Workspace-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
4B6423A11D8EFE7500FC78C8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4B6423A31D8EFE7500FC78C8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
4B6423A61D8EFE7500FC78C8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
4B6423A81D8EFE7500FC78C8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4B6A70931D60E04200E12030 /* AppKitCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppKitCommons.swift; sourceTree = "<group>"; };
4B6A70951D6100E300E12030 /* SwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftCommons.swift; sourceTree = "<group>"; };
4B854A1A1D31447C00E08DE1 /* NeoVimServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = NeoVimServer; sourceTree = BUILT_PRODUCTS_DIR; };
@ -264,6 +297,7 @@
4BAD81D41D80B5D8004F91AE /* OpenQuicklyFileViewRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyFileViewRow.swift; sourceTree = "<group>"; };
4BAD84E71D7CA8FC00A79CC3 /* OpenQuicklyFilterOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenQuicklyFilterOperation.swift; sourceTree = "<group>"; };
4BB1BEA81D48773200463C29 /* RxSwiftCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxSwiftCommons.swift; sourceTree = "<group>"; };
4BB489411D952CF6005BB0E8 /* WorkspaceToolButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WorkspaceToolButton.swift; path = Workspace/WorkspaceToolButton.swift; sourceTree = "<group>"; };
4BCADE071D11ED12004DAD0F /* CocoaExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CocoaExtensions.swift; sourceTree = "<group>"; };
4BCF638F1D323CFD00F15CE4 /* nvim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = nvim; path = neovim/src/nvim; sourceTree = SOURCE_ROOT; };
4BD3BF921D32A95800082605 /* MainWindowComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowComponent.swift; sourceTree = "<group>"; };
@ -321,6 +355,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B64239C1D8EFE7500FC78C8 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4B6423AC1D8EFE9800FC78C8 /* PureLayout.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4B854A171D31447C00E08DE1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -437,6 +479,28 @@
path = SwiftNeoVimTests;
sourceTree = "<group>";
};
4B6423941D8EFD6100FC78C8 /* Workspace */ = {
isa = PBXGroup;
children = (
4B6423951D8EFD7100FC78C8 /* Workspace.swift */,
4B6423971D8EFDE000FC78C8 /* WorkspaceBar.swift */,
4B6423991D8EFE3000FC78C8 /* WorkspaceTool.swift */,
4BB489411D952CF6005BB0E8 /* WorkspaceToolButton.swift */,
);
name = Workspace;
sourceTree = "<group>";
};
4B6423A01D8EFE7500FC78C8 /* VimR-Workspace-Demo */ = {
isa = PBXGroup;
children = (
4B6423A11D8EFE7500FC78C8 /* AppDelegate.swift */,
4B6423A31D8EFE7500FC78C8 /* Assets.xcassets */,
4B6423A51D8EFE7500FC78C8 /* MainMenu.xib */,
4B6423A81D8EFE7500FC78C8 /* Info.plist */,
);
path = "VimR-Workspace-Demo";
sourceTree = "<group>";
};
4B854A151D31444800E08DE1 /* resources */ = {
isa = PBXGroup;
children = (
@ -538,6 +602,7 @@
4B2A2BF81D0351810074CE9A /* SwiftNeoVim */,
4B56F2911D29903F00C1F92E /* SwiftNeoVimTests */,
4B854A1B1D31447C00E08DE1 /* NeoVimServer */,
4B6423A01D8EFE7500FC78C8 /* VimR-Workspace-Demo */,
4B2A2BE61D0225840074CE9A /* Frameworks */,
4BEBA5061CFF374B00673FDF /* Products */,
);
@ -551,6 +616,7 @@
4B2A2BF71D0351810074CE9A /* SwiftNeoVim.framework */,
4B56F2901D29903F00C1F92E /* SwiftNeoVimTests.xctest */,
4B854A1A1D31447C00E08DE1 /* NeoVimServer */,
4B64239F1D8EFE7500FC78C8 /* VimR-Workspace-Demo.app */,
);
name = Products;
sourceTree = "<group>";
@ -565,6 +631,7 @@
4BDF50111D760B1100D8FBC3 /* File Items */,
4BF8EED91D858C4400CAC08A /* Utils */,
4BDF50101D760AB700D8FBC3 /* Commons */,
4B6423941D8EFD6100FC78C8 /* Workspace */,
4B97E2CF1D33F92200FC0660 /* resources */,
);
path = VimR;
@ -668,6 +735,24 @@
productReference = 4B56F2901D29903F00C1F92E /* SwiftNeoVimTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
4B64239E1D8EFE7500FC78C8 /* VimR-Workspace-Demo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4B6423A91D8EFE7500FC78C8 /* Build configuration list for PBXNativeTarget "VimR-Workspace-Demo" */;
buildPhases = (
4B64239B1D8EFE7500FC78C8 /* Sources */,
4B64239C1D8EFE7500FC78C8 /* Frameworks */,
4B64239D1D8EFE7500FC78C8 /* Resources */,
4B6423AE1D8EFE9800FC78C8 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "VimR-Workspace-Demo";
productName = "VimR-Workspace-Demo";
productReference = 4B64239F1D8EFE7500FC78C8 /* VimR-Workspace-Demo.app */;
productType = "com.apple.product-type.application";
};
4B854A191D31447C00E08DE1 /* NeoVimServer */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4B854A1E1D31447C00E08DE1 /* Build configuration list for PBXNativeTarget "NeoVimServer" */;
@ -741,6 +826,9 @@
4B56F28F1D29903F00C1F92E = {
CreatedOnToolsVersion = 7.3.1;
};
4B64239E1D8EFE7500FC78C8 = {
CreatedOnToolsVersion = 7.3.1;
};
4B854A191D31447C00E08DE1 = {
CreatedOnToolsVersion = 7.3.1;
};
@ -771,6 +859,7 @@
4B2A2BF61D0351810074CE9A /* SwiftNeoVim */,
4B56F28F1D29903F00C1F92E /* SwiftNeoVimTests */,
4B854A191D31447C00E08DE1 /* NeoVimServer */,
4B64239E1D8EFE7500FC78C8 /* VimR-Workspace-Demo */,
);
};
/* End PBXProject section */
@ -791,6 +880,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B64239D1D8EFE7500FC78C8 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B6423A41D8EFE7500FC78C8 /* Assets.xcassets in Resources */,
4B6423A71D8EFE7500FC78C8 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4BEBA5031CFF374B00673FDF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -859,6 +957,19 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
4B64239B1D8EFE7500FC78C8 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4B280EFF1D945DA5003FE725 /* AppKitCommons.swift in Sources */,
4B6423AF1D8EFEA800FC78C8 /* Workspace.swift in Sources */,
4B6423B01D8EFEA800FC78C8 /* WorkspaceBar.swift in Sources */,
4BB489431D952CF6005BB0E8 /* WorkspaceToolButton.swift in Sources */,
4B6423B11D8EFEA800FC78C8 /* WorkspaceTool.swift in Sources */,
4B6423A21D8EFE7500FC78C8 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
4B854A161D31447C00E08DE1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -876,12 +987,14 @@
buildActionMask = 2147483647;
files = (
4B238BE11D3BF24200CBDD98 /* Application.swift in Sources */,
4B6423961D8EFD7100FC78C8 /* Workspace.swift in Sources */,
4B22F7F21D7C6B9000929B0E /* ImageAndTextTableCell.swift in Sources */,
4BDF50141D7617EA00D8FBC3 /* OpenQuicklyWindowComponent.swift in Sources */,
4B6A70941D60E04200E12030 /* AppKitCommons.swift in Sources */,
4BD3BF971D32B0DB00082605 /* MainWindowManager.swift in Sources */,
4B238BEC1D3ED54D00CBDD98 /* AppearancePrefPane.swift in Sources */,
4BD3BF931D32A95800082605 /* MainWindowComponent.swift in Sources */,
4B6423981D8EFDE000FC78C8 /* WorkspaceBar.swift in Sources */,
4BB1BEA91D48773200463C29 /* RxSwiftCommons.swift in Sources */,
4BAD81D51D80B5D8004F91AE /* OpenQuicklyFileViewRow.swift in Sources */,
4B4546871D468CEC00A1E27F /* PrefStore.swift in Sources */,
@ -892,6 +1005,7 @@
4BEBA5091CFF374B00673FDF /* AppDelegate.swift in Sources */,
1929B165820D7177743B537A /* Component.swift in Sources */,
1929B93DBAD09835E428F610 /* PrefPane.swift in Sources */,
4B64239A1D8EFE3000FC78C8 /* WorkspaceTool.swift in Sources */,
4BDF501B1D77596500D8FBC3 /* OpenQuicklyWindowManager.swift in Sources */,
1929B462CD4935AFF6D69457 /* FileItem.swift in Sources */,
1929B6388EAF16C190B82955 /* FileItemIgnorePattern.swift in Sources */,
@ -900,6 +1014,7 @@
1929B3F5743967125F357C9F /* Matcher.swift in Sources */,
1929B53876E6952D378C2B30 /* ScoredFileItem.swift in Sources */,
1929BD3F9E609BFADB27584B /* Scorer.swift in Sources */,
4BB489421D952CF6005BB0E8 /* WorkspaceToolButton.swift in Sources */,
4BAD84E81D7CA8FC00A79CC3 /* OpenQuicklyFilterOperation.swift in Sources */,
1929B0E0C3BC59F52713D5A2 /* FoundationCommons.swift in Sources */,
);
@ -960,6 +1075,14 @@
name = PrefWindow.xib;
sourceTree = "<group>";
};
4B6423A51D8EFE7500FC78C8 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
4B6423A61D8EFE7500FC78C8 /* Base */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
4B97E2CE1D33F53D00FC0660 /* MainWindow.xib */ = {
isa = PBXVariantGroup;
children = (
@ -1072,6 +1195,38 @@
};
name = Release;
};
4B6423AA1D8EFE7500FC78C8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
INFOPLIST_FILE = "VimR-Workspace-Demo/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
4B6423AB1D8EFE7500FC78C8 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/Mac",
);
INFOPLIST_FILE = "VimR-Workspace-Demo/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.qvacua.VimR-Workspace-Demo";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
4B854A1F1D31447C00E08DE1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1297,6 +1452,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4B6423A91D8EFE7500FC78C8 /* Build configuration list for PBXNativeTarget "VimR-Workspace-Demo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4B6423AA1D8EFE7500FC78C8 /* Debug */,
4B6423AB1D8EFE7500FC78C8 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4B854A1E1D31447C00E08DE1 /* Build configuration list for PBXNativeTarget "NeoVimServer" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4B64239E1D8EFE7500FC78C8"
BuildableName = "VimR-Workspace-Demo.app"
BlueprintName = "VimR-Workspace-Demo"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4B64239E1D8EFE7500FC78C8"
BuildableName = "VimR-Workspace-Demo.app"
BlueprintName = "VimR-Workspace-Demo"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4B64239E1D8EFE7500FC78C8"
BuildableName = "VimR-Workspace-Demo.app"
BlueprintName = "VimR-Workspace-Demo"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4B64239E1D8EFE7500FC78C8"
BuildableName = "VimR-Workspace-Demo.app"
BlueprintName = "VimR-Workspace-Demo"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4BEBA5131CFF374B00673FDF"
BuildableName = "VimRTests.xctest"
BlueprintName = "VimRTests"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4BEBA5131CFF374B00673FDF"
BuildableName = "VimRTests.xctest"
BlueprintName = "VimRTests"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4BEBA5131CFF374B00673FDF"
BuildableName = "VimRTests.xctest"
BlueprintName = "VimRTests"
ReferencedContainer = "container:VimR.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -18,9 +18,28 @@ extension NSButton {
}
}
// From https://developer.apple.com/library/mac/qa/qa1487/_index.html
extension NSAttributedString {
func draw(at point: CGPoint, angle: CGFloat) {
let translation = NSAffineTransform()
let rotation = NSAffineTransform()
translation.translateXBy(point.x, yBy: point.y)
rotation.rotateByRadians(angle)
translation.concat()
rotation.concat()
self.drawAtPoint(CGPoint.zero)
rotation.invert()
translation.invert()
rotation.concat()
translation.concat()
}
// From https://developer.apple.com/library/mac/qa/qa1487/_index.html
static func link(withUrl url: NSURL, text: String, font: NSFont? = nil) -> NSAttributedString {
let attrString = NSMutableAttributedString(string: text)
let range = NSRange(location: 0, length: attrString.length)
@ -43,6 +62,17 @@ extension NSAttributedString {
}
}
extension NSView {
func removeAllSubviews() {
self.subviews.forEach { $0.removeFromSuperview() }
}
func removeAllConstraints() {
self.removeConstraints(self.constraints)
}
}
extension NSTableView {
static func standardTableView() -> NSTableView {

View File

@ -0,0 +1,117 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import PureLayout
enum WorkspaceBarLocation {
case top
case right
case bottom
case left
}
class Workspace: NSView {
var mainView: NSView
private(set) var isBarVisible = true {
didSet {
self.needsDisplay = true
}
}
private let bars: [WorkspaceBarLocation: WorkspaceBar]
init(mainView: NSView) {
self.mainView = mainView
self.bars = [
.top: WorkspaceBar(location: .top),
.right: WorkspaceBar(location: .right),
.bottom: WorkspaceBar(location: .bottom),
.left: WorkspaceBar(location: .left)
]
super.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
self.relayout()
}
private func relayout() {
// FIXME: I did not investigate why toggleButtons does not work correctly if we store all constraints in an array
// and remove them here by self.removeConstraints(${all constraints). The following seems to work...
self.subviews.forEach { $0.removeAllConstraints() }
self.removeAllSubviews()
let mainView = self.mainView
self.addSubview(mainView)
guard self.isBarVisible else {
mainView.autoPinEdgesToSuperviewEdges()
return
}
let topBar = self.bars[.top]!
let rightBar = self.bars[.right]!
let bottomBar = self.bars[.bottom]!
let leftBar = self.bars[.left]!
self.addSubview(topBar)
self.addSubview(rightBar)
self.addSubview(bottomBar)
self.addSubview(leftBar)
topBar.autoPinEdgeToSuperviewEdge(.Top)
topBar.autoPinEdgeToSuperviewEdge(.Right)
topBar.autoPinEdgeToSuperviewEdge(.Left)
rightBar.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar)
rightBar.autoPinEdgeToSuperviewEdge(.Right)
rightBar.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar)
bottomBar.autoPinEdgeToSuperviewEdge(.Right)
bottomBar.autoPinEdgeToSuperviewEdge(.Bottom)
bottomBar.autoPinEdgeToSuperviewEdge(.Left)
leftBar.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar)
leftBar.autoPinEdgeToSuperviewEdge(.Left)
leftBar.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar)
NSLayoutConstraint.autoSetPriority(NSLayoutPriorityDragThatCannotResizeWindow) {
topBar.dimensionConstraint = topBar.autoSetDimension(.Height, toSize: 50)
rightBar.dimensionConstraint = rightBar.autoSetDimension(.Width, toSize: 50)
bottomBar.dimensionConstraint = bottomBar.autoSetDimension(.Height, toSize: 50)
leftBar.dimensionConstraint = leftBar.autoSetDimension(.Width, toSize: 50)
}
self.bars.values.forEach { $0.relayout() }
mainView.autoPinEdge(.Top, toEdge: .Bottom, ofView: topBar)
mainView.autoPinEdge(.Right, toEdge: .Left, ofView: rightBar)
mainView.autoPinEdge(.Bottom, toEdge: .Top, ofView: bottomBar)
mainView.autoPinEdge(.Left, toEdge: .Right, ofView: leftBar)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - API
extension Workspace {
func append(tool tool: WorkspaceTool, location: WorkspaceBarLocation) {
self.bars[location]?.append(tool: tool)
}
func toggleAllTools() {
self.isBarVisible = !self.isBarVisible
self.relayout()
}
func toggleToolButtons() {
self.bars.values.forEach { $0.isButtonVisible = !$0.isButtonVisible }
}
}

View File

@ -0,0 +1,509 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import PureLayout
class WorkspaceBar: NSView, WorkspaceToolDelegate {
static private let separatorColor = NSColor.controlShadowColor()
static private let separatorThickness = CGFloat(1)
let location: WorkspaceBarLocation
var isButtonVisible = true {
didSet {
self.relayout()
}
}
var dimensionConstraint = NSLayoutConstraint()
private var tools = [WorkspaceTool]()
private weak var selectedTool: WorkspaceTool?
private var isMouseDownOngoing = false
private var dragIncrement = CGFloat(1)
private var layoutConstraints = [NSLayoutConstraint]()
init(location: WorkspaceBarLocation) {
self.location = location
super.init(frame: CGRect.zero)
super.translatesAutoresizingMaskIntoConstraints = false
self.wantsLayer = true
self.layer!.backgroundColor = NSColor.windowBackgroundColor().CGColor
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
if self.isButtonVisible {
self.drawInnerSeparator(dirtyRect)
}
if self.isOpen() {
self.drawOuterSeparator(dirtyRect)
}
}
private func drawInnerSeparator(dirtyRect: NSRect) {
WorkspaceBar.separatorColor.set()
let innerLineRect = self.innerSeparatorRect()
if dirtyRect.intersects(innerLineRect) {
NSRectFill(innerLineRect)
}
}
private func drawOuterSeparator(dirtyRect: NSRect) {
WorkspaceBar.separatorColor.set()
let outerLineRect = self.outerSeparatorRect()
if dirtyRect.intersects(outerLineRect) {
NSRectFill(outerLineRect)
}
}
private func buttonSize() -> CGSize {
if self.isEmpty() {
return CGSize.zero
}
return self.tools.first!.button.intrinsicContentSize
}
private func innerSeparatorRect() -> CGRect {
let bounds = self.bounds
let thickness = WorkspaceBar.separatorThickness
let bar = self.buttonSize()
switch self.location {
case .top:
return CGRect(x: 0, y: bounds.height - bar.height - thickness, width: bounds.width, height: thickness)
case .right:
return CGRect(x: bounds.width - bar.width - thickness, y: 0, width: thickness, height: bounds.height)
case .bottom:
return CGRect(x: 0, y: bar.height, width: bounds.width, height: thickness)
case .left:
return CGRect(x: bar.width, y: 0, width: thickness, height: bounds.height)
}
}
override func mouseDown(event: NSEvent) {
guard self.isOpen() else {
return
}
if self.isMouseDownOngoing {
return
}
let initialMouseLoc = self.convertPoint(event.locationInWindow, fromView: nil)
let mouseInResizeRect = NSMouseInRect(initialMouseLoc, self.resizeRect(), self.flipped)
guard mouseInResizeRect && event.type == .LeftMouseDown else {
super.mouseDown(event)
return
}
self.isMouseDownOngoing = true
var dragged = false
var curEvent = event
let nextEventMask: NSEventMask = [
NSEventMask.LeftMouseDraggedMask,
NSEventMask.LeftMouseDownMask,
NSEventMask.LeftMouseUpMask
]
while curEvent.type != .LeftMouseUp {
let nextEvent = NSApp.nextEventMatchingMask(Int(nextEventMask.rawValue),
untilDate: NSDate.distantFuture(),
inMode: NSEventTrackingRunLoopMode,
dequeue: true)
guard nextEvent != nil else {
break
}
curEvent = nextEvent!
guard curEvent.type == .LeftMouseDragged else {
break
}
let curMouseLoc = self.convertPoint(curEvent.locationInWindow, fromView: nil)
let distance = sq(initialMouseLoc.x - curMouseLoc.x) + sq(initialMouseLoc.y - curMouseLoc.y)
guard dragged || distance >= 1 else {
continue
}
let locInSuperview = self.superview!.convertPoint(curEvent.locationInWindow, fromView: nil)
let newDimension = self.newDimension(forLocationInSuperview: locInSuperview)
self.set(dimension: newDimension)
self.window?.invalidateCursorRectsForView(self)
dragged = true
}
self.isMouseDownOngoing = false
}
override func resetCursorRects() {
guard self.isOpen() else {
return
}
switch self.location {
case .top, .bottom:
self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeUpDownCursor())
case .right, .left:
self.addCursorRect(self.resizeRect(), cursor: NSCursor.resizeLeftRightCursor())
}
}
private func newDimension(forLocationInSuperview locInSuperview: CGPoint) -> CGFloat {
let dimension = self.dimension(forLocationInSuperview: locInSuperview)
return self.dragIncrement * floor(dimension / self.dragIncrement)
}
private func dimension(forLocationInSuperview locInSuperview: CGPoint) -> CGFloat {
let superviewBounds = self.superview!.bounds
switch self.location {
case .top:
return superviewBounds.height - locInSuperview.y
case .right:
return superviewBounds.width - locInSuperview.x
case .bottom:
return locInSuperview.y
case .left:
return locInSuperview.x
}
}
private func sq(number: CGFloat) -> CGFloat {
return number * number
}
private func outerSeparatorRect() -> CGRect {
let thickness = WorkspaceBar.separatorThickness
switch self.location {
case .top:
return CGRect(x: 0, y: 0, width: self.bounds.width, height: thickness)
case .right:
return CGRect(x: 0, y: 0, width: thickness, height: self.bounds.height)
case .bottom:
return CGRect(x: 0, y: self.bounds.height - thickness, width: self.bounds.width, height: thickness)
case .left:
return CGRect(x: self.bounds.width - thickness, y: 0, width: thickness, height: self.bounds.height)
}
}
private func resizeRect() -> CGRect {
let separatorRect = self.outerSeparatorRect()
let clickDimension = CGFloat(4)
switch self.location {
case .top:
return separatorRect.offsetBy(dx: 0, dy: clickDimension).union(separatorRect)
case .right:
return separatorRect.offsetBy(dx: clickDimension, dy: 0).union(separatorRect)
case .bottom:
return separatorRect.offsetBy(dx: 0, dy: -clickDimension).union(separatorRect)
case .left:
return separatorRect.offsetBy(dx: -clickDimension, dy: 0).union(separatorRect)
}
}
private func set(dimension dimension: CGFloat) {
self.dimensionConstraint.constant = dimension
let toolDimension = self.toolDimension(fromBarDimension: dimension)
if self.isOpen() {
self.selectedTool?.dimension = toolDimension
}
}
private func isEmpty() -> Bool {
return self.tools.isEmpty
}
private func hasTools() -> Bool {
return !self.isEmpty()
}
private func isOpen() -> Bool {
return self.selectedTool != nil
}
}
// MARK: - Layout
extension WorkspaceBar {
func relayout() {
self.removeConstraints(self.layoutConstraints)
self.removeAllSubviews()
if self.isEmpty() {
self.set(dimension: 0)
return
}
if self.isButtonVisible {
self.layoutButtons()
if self.isOpen() {
let curTool = self.selectedTool!
self.layout(tool: curTool)
let newDimension = self.barDimension(withToolDimension: curTool.dimension)
self.set(dimension: newDimension)
} else {
self.set(dimension: self.barDimensionWithButtonsWithoutTool())
}
} else {
if self.isOpen() {
let curTool = self.selectedTool!
self.layoutWithoutButtons(tool: curTool)
let newDimension = self.barDimensionWithoutButtons(withToolDimension: curTool.dimension)
self.set(dimension: newDimension)
} else {
self.set(dimension: 0)
}
}
self.needsDisplay = true
}
private func layoutWithoutButtons(tool tool: WorkspaceTool) {
let view = tool.view
let thickness = WorkspaceBar.separatorThickness
self.addSubview(view)
switch self.location {
case .top:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top),
view.autoPinEdgeToSuperviewEdge(.Right),
view.autoPinEdgeToSuperviewEdge(.Bottom, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
case .right:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top),
view.autoPinEdgeToSuperviewEdge(.Right),
view.autoPinEdgeToSuperviewEdge(.Bottom),
view.autoPinEdgeToSuperviewEdge(.Left, withInset: thickness),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
case .bottom:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Right),
view.autoPinEdgeToSuperviewEdge(.Bottom),
view.autoPinEdgeToSuperviewEdge(.Left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
case .left:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top),
view.autoPinEdgeToSuperviewEdge(.Right, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Bottom),
view.autoPinEdgeToSuperviewEdge(.Left),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
}
}
private func layout(tool tool: WorkspaceTool) {
let view = tool.view
let button = tool.button
let thickness = WorkspaceBar.separatorThickness
self.addSubview(view)
switch self.location {
case .top:
self.layoutConstraints.appendContentsOf([
view.autoPinEdge(.Top, toEdge: .Bottom, ofView: button, withOffset: thickness),
view.autoPinEdgeToSuperviewEdge(.Right),
view.autoPinEdgeToSuperviewEdge(.Bottom, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
case .right:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top),
view.autoPinEdge(.Right, toEdge: .Left, ofView: button, withOffset: -thickness), // Offset is count l -> r,
view.autoPinEdgeToSuperviewEdge(.Bottom),
view.autoPinEdgeToSuperviewEdge(.Left, withInset: thickness),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
case .bottom:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Right),
view.autoPinEdge(.Bottom, toEdge: .Top, ofView: button, withOffset: -thickness), // Offset is count t -> b,
view.autoPinEdgeToSuperviewEdge(.Left),
view.autoSetDimension(.Height, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
case .left:
self.layoutConstraints.appendContentsOf([
view.autoPinEdgeToSuperviewEdge(.Top),
view.autoPinEdgeToSuperviewEdge(.Right, withInset: thickness),
view.autoPinEdgeToSuperviewEdge(.Bottom),
view.autoPinEdge(.Left, toEdge: .Right, ofView: button, withOffset: thickness),
view.autoSetDimension(.Width, toSize: tool.minimumDimension, relation: .GreaterThanOrEqual)
])
}
}
private func layoutButtons() {
guard let firstTool = self.tools.first else {
return
}
self.tools
.map { $0.button }
.forEach(self.addSubview)
let firstButton = firstTool.button
switch self.location {
case .top:
self.layoutConstraints.appendContentsOf([
firstButton.autoPinEdgeToSuperviewEdge(.Top),
firstButton.autoPinEdgeToSuperviewEdge(.Left),
])
case .right:
self.layoutConstraints.appendContentsOf([
firstButton.autoPinEdgeToSuperviewEdge(.Top),
firstButton.autoPinEdgeToSuperviewEdge(.Right),
])
case .bottom:
self.layoutConstraints.appendContentsOf([
firstButton.autoPinEdgeToSuperviewEdge(.Left),
firstButton.autoPinEdgeToSuperviewEdge(.Bottom),
])
case .left:
self.layoutConstraints.appendContentsOf([
firstButton.autoPinEdgeToSuperviewEdge(.Top),
firstButton.autoPinEdgeToSuperviewEdge(.Left),
])
}
var lastButton = firstButton
for button in self.tools[1..<self.tools.count].map({ $0.button }) {
switch self.location {
case .top:
self.layoutConstraints.appendContentsOf([
button.autoPinEdgeToSuperviewEdge(.Top),
button.autoPinEdge(.Left, toEdge: .Right, ofView: lastButton),
])
case .right:
self.layoutConstraints.appendContentsOf([
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: lastButton),
button.autoPinEdgeToSuperviewEdge(.Right),
])
case .bottom:
self.layoutConstraints.appendContentsOf([
button.autoPinEdge(.Left, toEdge: .Right, ofView: lastButton),
button.autoPinEdgeToSuperviewEdge(.Bottom),
])
case .left:
self.layoutConstraints.appendContentsOf([
button.autoPinEdge(.Top, toEdge: .Bottom, ofView: lastButton),
button.autoPinEdgeToSuperviewEdge(.Left),
])
}
lastButton = button
}
}
private func barDimensionWithButtonsWithoutTool() -> CGFloat {
switch self.location {
case .top, .bottom:
return self.buttonSize().height + WorkspaceBar.separatorThickness
case .right, .left:
return self.buttonSize().width + WorkspaceBar.separatorThickness
}
}
private func barDimensionWithoutButtons(withToolDimension toolDimension: CGFloat) -> CGFloat {
return toolDimension + WorkspaceBar.separatorThickness
}
private func barDimension(withToolDimension toolDimension: CGFloat) -> CGFloat {
return self.barDimensionWithButtonsWithoutTool() + toolDimension + WorkspaceBar.separatorThickness
}
private func toolDimension(fromBarDimension barDimension: CGFloat) -> CGFloat {
if self.isButtonVisible {
return barDimension - WorkspaceBar.separatorThickness - barDimensionWithButtonsWithoutTool()
}
return barDimension - WorkspaceBar.separatorThickness
}
}
// MARK: - API
extension WorkspaceBar {
func append(tool tool: WorkspaceTool) {
tool.delegate = self
tool.location = self.location
tools.append(tool)
if self.isOpen() {
self.selectedTool?.isSelected = false
self.selectedTool = tool
}
self.relayout()
}
}
// MARK: - WorkspaceToolDelegate
extension WorkspaceBar {
func toggle(tool tool: WorkspaceTool) {
if self.isOpen() {
let curTool = self.selectedTool!
if curTool === tool {
// In this case, curTool.isSelected is already set to false in WorkspaceTool.toggle()
self.selectedTool = nil
} else {
curTool.isSelected = false
self.selectedTool = tool
}
} else {
self.selectedTool = tool
}
self.relayout()
}
}

View File

@ -0,0 +1,51 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
protocol WorkspaceToolDelegate: class {
func toggle(tool tool: WorkspaceTool)
}
class WorkspaceTool {
let title: String
let view: NSView
let button: WorkspaceToolButton
var location = WorkspaceBarLocation.left {
didSet {
self.button.location = self.location
}
}
var isSelected = false {
didSet {
if self.isSelected {
self.button.highlight()
} else {
self.button.dehighlight()
}
}
}
weak var delegate: WorkspaceToolDelegate?
let minimumDimension = CGFloat(30)
var dimension = CGFloat(50)
init(title: String, view: NSView) {
self.title = title
self.view = view
self.button = WorkspaceToolButton(title: title)
self.button.tool = self
}
func toggle() {
self.delegate?.toggle(tool: self)
self.isSelected = !self.isSelected
}
}

View File

@ -0,0 +1,106 @@
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
class WorkspaceToolButton: NSView {
static private let titlePadding = CGSize(width: 8, height: 2)
var location = WorkspaceBarLocation.left
var isSelected: Bool {
return self.tool?.isSelected ?? false
}
weak var tool: WorkspaceTool?
override var fittingSize: NSSize {
return self.intrinsicContentSize
}
override var intrinsicContentSize: NSSize {
let titleSize = self.title.size()
let padding = WorkspaceToolButton.titlePadding
switch self.location {
case .top, .bottom:
return CGSize(width: titleSize.width + 2 * padding.width, height: titleSize.height + 2 * padding.height)
case .right, .left:
return CGSize(width: titleSize.height + 2 * padding.height, height: titleSize.width + 2 * padding.width)
}
}
private let title: NSAttributedString
private var trackingArea = NSTrackingArea()
init(title: String) {
self.title = NSAttributedString(string: title, attributes: [
NSFontAttributeName: NSFont.systemFontOfSize(11)
])
super.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
self.wantsLayer = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
let padding = WorkspaceToolButton.titlePadding
switch self.location {
case .top, .bottom:
self.title.drawAtPoint(CGPoint(x: padding.width, y: padding.height))
case .right:
self.title.draw(at: CGPoint(x: padding.height, y: self.bounds.height - padding.width), angle: -CGFloat(M_PI_2))
case .left:
self.title.draw(at: CGPoint(x: self.bounds.width - padding.height, y: padding.width), angle: CGFloat(M_PI_2))
}
}
override func updateTrackingAreas() {
self.removeTrackingArea(self.trackingArea)
self.trackingArea = NSTrackingArea(rect: self.bounds,
options: [.MouseEnteredAndExited, .ActiveInActiveApp],
owner: self,
userInfo: nil)
self.addTrackingArea(self.trackingArea)
super.updateTrackingAreas()
}
override func mouseDown(event: NSEvent) {
self.tool?.toggle()
}
override func mouseEntered(_: NSEvent) {
if self.isSelected {
return
}
self.highlight()
}
override func mouseExited(_: NSEvent) {
if self.isSelected {
return
}
self.dehighlight()
}
func highlight() {
self.layer?.backgroundColor = NSColor.controlShadowColor().CGColor
}
func dehighlight() {
self.layer?.backgroundColor = NSColor.clearColor().CGColor
}
}

2
neovim

@ -1 +1 @@
Subproject commit a0b5d77b4391ca50f9e7a0ee7a01127c229c037f
Subproject commit 0919d0cceabc0903caf8f0bf62bbefdd1771f07c