├── .gitignore ├── AffinityUI.sln ├── AffinityUI ├── AffinityUI.csproj ├── Area.cs ├── AssemblyInfo.cs ├── AutoSpace.cs ├── BindableContent.cs ├── BindableProperty.cs ├── Binder.cs ├── Box.cs ├── Button.cs ├── Composite.cs ├── ContentControl.cs ├── Control.cs ├── Extensions.cs ├── HorizontalPanel.cs ├── HorizontalSlider.cs ├── Label.cs ├── PasswordField.cs ├── ScrollView.cs ├── SelectionGrid.cs ├── TabControl.cs ├── TextArea.cs ├── TextField.cs ├── Toggle.cs ├── Tooltip.cs ├── TooltipRenderer.cs ├── TypedControl.cs ├── UI.cs ├── VerticalPanel.cs ├── VerticalSlider.cs └── Window.cs ├── KspExample ├── AssemblyInfo.cs ├── ExampleGUI.cs ├── KspExample.csproj └── res │ ├── icon.png │ └── license.txt ├── LICENSE.md ├── README.md └── lib ├── Assembly-CSharp.dll └── UnityEngine.dll /.gitignore: -------------------------------------------------------------------------------- 1 | *proj.user 2 | **/obj/* 3 | **/bin/* 4 | *.ncb 5 | *.suo 6 | AffinityUI.userprefs 7 | AffinityUI.pidb 8 | -------------------------------------------------------------------------------- /AffinityUI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AffinityUI", "AffinityUI\AffinityUI.csproj", "{22A4E171-AA2B-4150-A8A0-348D8134F706}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KspExample", "KspExample\KspExample.csproj", "{99F0CB38-DBCD-4177-AFBF-A8264CE1D669}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {22A4E171-AA2B-4150-A8A0-348D8134F706}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {22A4E171-AA2B-4150-A8A0-348D8134F706}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {22A4E171-AA2B-4150-A8A0-348D8134F706}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {22A4E171-AA2B-4150-A8A0-348D8134F706}.Release|Any CPU.Build.0 = Release|Any CPU 18 | {99F0CB38-DBCD-4177-AFBF-A8264CE1D669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {99F0CB38-DBCD-4177-AFBF-A8264CE1D669}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {99F0CB38-DBCD-4177-AFBF-A8264CE1D669}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {99F0CB38-DBCD-4177-AFBF-A8264CE1D669}.Release|Any CPU.Build.0 = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(MonoDevelopProperties) = preSolution 24 | Policies = $0 25 | $0.TextStylePolicy = $1 26 | $1.FileWidth = 120 27 | $1.inheritsSet = VisualStudio 28 | $1.inheritsScope = text/plain 29 | $1.scope = text/x-csharp 30 | $0.CSharpFormattingPolicy = $2 31 | $2.IndentSwitchBody = True 32 | $2.IndentBlocksInsideExpressions = True 33 | $2.AnonymousMethodBraceStyle = NextLine 34 | $2.PropertyBraceStyle = NextLine 35 | $2.PropertyGetBraceStyle = NextLine 36 | $2.PropertySetBraceStyle = NextLine 37 | $2.EventBraceStyle = NextLine 38 | $2.EventAddBraceStyle = NextLine 39 | $2.EventRemoveBraceStyle = NextLine 40 | $2.StatementBraceStyle = NextLine 41 | $2.ElseNewLinePlacement = NewLine 42 | $2.CatchNewLinePlacement = NewLine 43 | $2.FinallyNewLinePlacement = NewLine 44 | $2.WhileNewLinePlacement = DoNotCare 45 | $2.ArrayInitializerWrapping = DoNotChange 46 | $2.ArrayInitializerBraceStyle = NextLine 47 | $2.BeforeMethodDeclarationParentheses = False 48 | $2.BeforeMethodCallParentheses = False 49 | $2.BeforeConstructorDeclarationParentheses = False 50 | $2.NewLineBeforeConstructorInitializerColon = NewLine 51 | $2.NewLineAfterConstructorInitializerColon = SameLine 52 | $2.BeforeDelegateDeclarationParentheses = False 53 | $2.NewParentheses = False 54 | $2.SpacesBeforeBrackets = False 55 | $2.inheritsSet = Mono 56 | $2.inheritsScope = text/x-csharp 57 | $2.scope = text/x-csharp 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /AffinityUI/AffinityUI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {22A4E171-AA2B-4150-A8A0-348D8134F706} 9 | Library 10 | Properties 11 | AffinityUI 12 | AffinityUI 13 | v3.5 14 | 512 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | bin\Debug\AffinityUI.XML 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | bin\Release\AffinityUI.XML 35 | 36 | 37 | 38 | 39 | 40 | ..\lib\UnityEngine.dll 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | I 102 | 103 | 104 | 105 | 106 | Attribute 107 | 108 | 109 | 110 | 111 | EventArgs 112 | 113 | 114 | 115 | 116 | Exception 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | T 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /AffinityUI/Area.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | 6 | namespace AffinityUI 7 | { 8 | /// 9 | /// Contains a block in a fixed screen area. 10 | /// 11 | public class Area : Composite 12 | { 13 | Rect dimensions; 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The dimensions. 19 | public Area(Rect dimensions) 20 | : base() 21 | { 22 | this.dimensions = dimensions; 23 | } 24 | 25 | public Area Dimensions(Rect dimensions) 26 | { 27 | this.dimensions = dimensions; 28 | return this; 29 | } 30 | 31 | public Rect Dimensions() 32 | { 33 | return dimensions; 34 | } 35 | 36 | /// 37 | /// Called when layout begins when using GUILayout. 38 | /// 39 | protected override void OnBeginLayout_GUILayout() 40 | { 41 | GUILayout.BeginArea(dimensions, Label()); 42 | } 43 | 44 | /// 45 | /// Called when layout ends when using GUILayout. 46 | /// 47 | protected override void OnEndLayout_GUILayout() 48 | { 49 | GUILayout.EndArea(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AffinityUI/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AffinityUI")] 9 | [assembly: AssemblyDescription("AffinityUI for Unity")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AffinityUI")] 13 | [assembly: AssemblyCopyright("Copyright © Matt Olenik")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("48d7d6e2-d08e-48c4-a641-b2942dee8502")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.1.0.0")] 36 | [assembly: AssemblyFileVersion("0.1.0.0")] 37 | -------------------------------------------------------------------------------- /AffinityUI/AutoSpace.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace AffinityUI 5 | { 6 | public class AutoSpace : Control 7 | { 8 | BindableProperty size; 9 | 10 | public AutoSpace() 11 | : this(0) 12 | { 13 | } 14 | 15 | public AutoSpace(int size) 16 | : base() 17 | { 18 | this.size = new BindableProperty(this, size); 19 | } 20 | 21 | public AutoSpace Size(int size) 22 | { 23 | this.size.Value = size; 24 | return this; 25 | } 26 | 27 | public BindableProperty Size() 28 | { 29 | return size; 30 | } 31 | 32 | protected override void Layout_GUILayout() 33 | { 34 | if (size == 0) 35 | { 36 | GUILayout.FlexibleSpace(); 37 | } 38 | else 39 | { 40 | GUILayout.Space(size); 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /AffinityUI/BindableContent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | 6 | namespace AffinityUI 7 | { 8 | /// 9 | /// A bindable drop-in for GUIContent 10 | /// 11 | public class BindableContent 12 | { 13 | TOwner owner; 14 | BindableProperty label; 15 | GUIContent content; 16 | 17 | public TOwner OK { get { return owner; } } 18 | 19 | public BindableProperty Label() 20 | { 21 | return label; 22 | } 23 | 24 | public BindableContent Label(string text) 25 | { 26 | label.Value = text; 27 | return this; 28 | } 29 | 30 | public GUIContent Content() 31 | { 32 | return content; 33 | } 34 | 35 | public BindableContent Content(GUIContent content) 36 | { 37 | this.content = content; 38 | return this; 39 | } 40 | 41 | public Texture Image() 42 | { 43 | return content.image; 44 | } 45 | 46 | public BindableContent Image(Texture image) 47 | { 48 | content.image = image; 49 | return this; 50 | } 51 | 52 | public BindableContent(TOwner owner) 53 | : this(owner, new GUIContent()) 54 | { 55 | } 56 | 57 | public BindableContent(TOwner owner, GUIContent content) 58 | { 59 | this.owner = owner; 60 | this.content = content; 61 | label = new BindableProperty(owner); 62 | label.OnPropertyChanged(((src, old, nw) => content.text = nw)); 63 | } 64 | 65 | public void UpdateBinding() 66 | { 67 | label.UpdateBinding(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /AffinityUI/BindableProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace AffinityUI 5 | { 6 | /// 7 | /// Change notification function signature. 8 | /// 9 | public delegate void PropertyChangedEventHandler(TSource src, TValue old, TValue nw); 10 | 11 | /// 12 | /// Encapsulates databinding and update notification functionality for control properties. 13 | /// 14 | /// The type of the owner control. 15 | /// The type of the property. 16 | public class BindableProperty 17 | { 18 | TProperty value; 19 | TOwner owner; 20 | Binder binder; 21 | 22 | /// 23 | /// Occurs when the property's value changes. 24 | /// 25 | public event PropertyChangedEventHandler PropertyChanged; 26 | 27 | /// 28 | /// Gets the binding direction. Throws an if the property is not bound. 29 | /// 30 | /// The direction. 31 | public BindingDirection Direction 32 | { 33 | get 34 | { 35 | if (binder != null) 36 | { 37 | return binder.Direction; 38 | } 39 | throw new InvalidOperationException("Property is not bound."); 40 | } 41 | } 42 | 43 | /// 44 | /// Initializes a new instance of the class. 45 | /// 46 | /// The owner control. 47 | public BindableProperty(TOwner owner) 48 | { 49 | this.owner = owner; 50 | } 51 | 52 | /// 53 | /// Initializes a new instance of the class. 54 | /// 55 | /// The owner control. 56 | /// The default value. 57 | public BindableProperty(TOwner owner, TProperty defaultValue) 58 | : this(owner) 59 | { 60 | value = defaultValue; 61 | } 62 | 63 | /// 64 | /// Gets or sets the value. 65 | /// 66 | /// The value. 67 | public TProperty Value 68 | { 69 | get 70 | { 71 | UpdateBinding(); 72 | return value; 73 | } 74 | set 75 | { 76 | if (AreDifferent(this.value, value)) 77 | { 78 | DispatchPropertyChanged(this.value, value); 79 | if (binder != null && 80 | (binder.Direction == BindingDirection.TwoWay || binder.Direction == BindingDirection.OneWayToSource)) 81 | { 82 | binder.Value = value; 83 | } 84 | } 85 | this.value = value; 86 | } 87 | } 88 | 89 | public static implicit operator TProperty(BindableProperty instance) 90 | { 91 | return instance.Value; 92 | } 93 | 94 | /// 95 | /// Sets the value but ignores databinding. 96 | /// 97 | /// The value. 98 | /// the owner control 99 | public TOwner SetIgnoreBinding(TProperty value) 100 | { 101 | this.value = value; 102 | return owner; 103 | } 104 | 105 | /// 106 | /// Binds this property using two way binding. 107 | /// 108 | /// The getter. 109 | /// The setter. 110 | /// the owner control 111 | public TOwner BindTwoWay(Func getter, Action setter) 112 | { 113 | binder = Binder.BindTwoWay(getter, setter); 114 | return owner; 115 | } 116 | 117 | /// 118 | /// Binds this property using one way binding. 119 | /// 120 | /// The getter. 121 | /// the owner control 122 | public TOwner BindOneWay(Func getter) 123 | { 124 | binder = Binder.BindOneWay(getter); 125 | return owner; 126 | } 127 | 128 | /// 129 | /// Binds this property using one way to source binding. 130 | /// 131 | /// The setter. 132 | /// the owner control 133 | public TOwner BindOneWayToSource(Action setter) 134 | { 135 | binder = Binder.BindOneWayToSource(setter); 136 | return owner; 137 | } 138 | 139 | /// 140 | /// Convenience fluent method for adding a handler to the event. 141 | /// 142 | /// The handler. 143 | /// the owner control 144 | public TOwner OnPropertyChanged(PropertyChangedEventHandler handler) 145 | { 146 | PropertyChanged += handler; 147 | return owner; 148 | } 149 | 150 | /// 151 | /// Updates the binding. Call this when the binding should be updated without getting or setting the property. 152 | /// 153 | public void UpdateBinding() 154 | { 155 | if (binder != null && 156 | (binder.Direction == BindingDirection.TwoWay || binder.Direction == BindingDirection.OneWay)) 157 | { 158 | if (AreDifferent(value, binder.Value)) 159 | { 160 | DispatchPropertyChanged(value, binder.Value); 161 | value = binder.Value; 162 | } 163 | } 164 | } 165 | 166 | /// 167 | /// Dispatches property changed events. 168 | /// 169 | /// The old value. 170 | /// The new value. 171 | void DispatchPropertyChanged(TProperty oldValue, TProperty newValue) 172 | { 173 | if (PropertyChanged != null) 174 | { 175 | PropertyChanged(owner, oldValue, newValue); 176 | } 177 | } 178 | 179 | /// 180 | /// Determines if the arguments are different. 181 | /// 182 | /// First object. 183 | /// Second object. 184 | /// true if the arguments are different; otherwise, false. 185 | bool AreDifferent(object a, object b) 186 | { 187 | if (a == null && b == null) 188 | { 189 | return false; 190 | } 191 | if ((a == null && b != null) || (a != null && b == null)) 192 | { 193 | return true; 194 | } 195 | return !a.Equals(b); 196 | } 197 | } 198 | } -------------------------------------------------------------------------------- /AffinityUI/Binder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AffinityUI 4 | { 5 | /// 6 | /// Data binding direction, indicates how data should be bound between source and destination. 7 | /// 8 | public enum BindingDirection 9 | { 10 | /// 11 | /// Binding is performed from the source to the control and the control to the source. 12 | /// 13 | TwoWay, 14 | /// 15 | /// Binding is performed from the source to the control. 16 | /// 17 | OneWay, 18 | /// 19 | /// Binding is performed from the control to the source. 20 | /// 21 | OneWayToSource 22 | } 23 | 24 | /// 25 | /// A data binding helper for fields and properties. 26 | /// 27 | /// The type of the field or property being bound 28 | public class Binder 29 | { 30 | Action setter; 31 | Func getter; 32 | 33 | /// 34 | /// Gets the . 35 | /// 36 | /// The binding direction. 37 | public BindingDirection Direction { get; private set; } 38 | 39 | /// 40 | /// Initializes a new instance of the class. 41 | /// 42 | /// The binding direction. 43 | Binder(BindingDirection direction) 44 | { 45 | Direction = direction; 46 | } 47 | 48 | /// 49 | /// Creates a binder with two way binding. 50 | /// 51 | /// The type of the value. 52 | /// The setter. 53 | /// The getter. 54 | /// a new Binder for type TValue 55 | public static Binder BindTwoWay(Func getter, Action setter) 56 | { 57 | var binder = new Binder(BindingDirection.TwoWay) { getter = getter, setter = setter }; 58 | return binder; 59 | } 60 | 61 | /// 62 | /// Creates a binder with one way binding. 63 | /// 64 | /// The type of the value. 65 | /// The getter. 66 | /// a new Binder for type TValue 67 | public static Binder BindOneWay(Func getter) 68 | { 69 | var binder = new Binder(BindingDirection.OneWay) { getter = getter }; 70 | return binder; 71 | } 72 | 73 | /// 74 | /// Creates a binder with one way to source binding. 75 | /// 76 | /// The type of the value. 77 | /// The setter. 78 | /// a new Binder for type TValue 79 | public static Binder BindOneWayToSource(Action setter) 80 | { 81 | var binder = new Binder(BindingDirection.OneWayToSource) { setter = setter }; 82 | return binder; 83 | } 84 | 85 | /// 86 | /// Gets or sets the bound value. 87 | /// 88 | /// The bound value. 89 | public T Value 90 | { 91 | get 92 | { 93 | if (getter == null) 94 | { 95 | throw new InvalidOperationException("Cannot get the value because the binding mode is one way to source (write only)."); 96 | } 97 | return getter(); 98 | } 99 | set 100 | { 101 | if (setter == null) 102 | { 103 | throw new InvalidOperationException("Cannot set the value because the binding mode is one way (read only)."); 104 | } 105 | setter(value); 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /AffinityUI/Box.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | 6 | namespace AffinityUI 7 | { 8 | /// 9 | /// A box with GUIContent. 10 | /// 11 | public class Box : ContentControl 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public Box() 17 | : base() 18 | { 19 | Style(() => GUI.skin.box); 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The label text. 26 | public Box(string label) 27 | : this() 28 | { 29 | Label(label); 30 | } 31 | 32 | /// 33 | /// Called when layout is done using GUI. 34 | /// 35 | protected override void Layout_GUI() 36 | { 37 | GUI.Box(Position(), Content(), Style()); 38 | } 39 | 40 | /// 41 | /// Called when layout is done using GUILayout. 42 | /// 43 | protected override void Layout_GUILayout() 44 | { 45 | GUILayout.Box(Content(), Style(), LayoutOptions()); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /AffinityUI/Button.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace AffinityUI 5 | { 6 | /// 7 | /// Handler type for button click events. 8 | /// 9 | public delegate void ButtonClickHandler(TSource src); 10 | 11 | /// 12 | /// A clickable button. 13 | /// 14 | public class Button : ContentControl