From 8dde01a842348fc7d03cda8e4a76223a5a6d96f6 Mon Sep 17 00:00:00 2001 From: Eddio0141 Date: Fri, 1 Nov 2024 19:47:34 +0000 Subject: [PATCH] ui is cooler now --- .../GUI/Components/DropdownList.cs | 6 +-- .../GUI/Windows/ObjectPickerWindow.cs | 31 +++++++++---- .../Implementations/GUI/Windows/ToolBar.cs | 5 +- UniTAS/Patcher/Interfaces/GUI/Window.cs | 43 +++++++++++++++++- .../Patcher/Models/GUI/WindowDependencies.cs | 5 +- .../Resources/object-icon.png | Bin 0 -> 668 bytes .../Resources/window-close-click.png | Bin 0 -> 702 bytes .../Resources/window-close-hover.png | Bin 0 -> 702 bytes .../Resources/window-close-normal.png | Bin 0 -> 652 bytes .../Resources/window-normal.png | Bin 0 -> 7445 bytes .../Resources/window-on-normal.png | Bin 0 -> 8328 bytes 11 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 UniTAS/Patcher/RuntimeResources/Resources/object-icon.png create mode 100644 UniTAS/Patcher/RuntimeResources/Resources/window-close-click.png create mode 100644 UniTAS/Patcher/RuntimeResources/Resources/window-close-hover.png create mode 100644 UniTAS/Patcher/RuntimeResources/Resources/window-close-normal.png create mode 100644 UniTAS/Patcher/RuntimeResources/Resources/window-normal.png create mode 100644 UniTAS/Patcher/RuntimeResources/Resources/window-on-normal.png diff --git a/UniTAS/Patcher/Implementations/GUI/Components/DropdownList.cs b/UniTAS/Patcher/Implementations/GUI/Components/DropdownList.cs index 7faee0b3..525fc9fc 100644 --- a/UniTAS/Patcher/Implementations/GUI/Components/DropdownList.cs +++ b/UniTAS/Patcher/Implementations/GUI/Components/DropdownList.cs @@ -19,17 +19,17 @@ public bool DropdownButtons(Rect position, (string, Action)[] buttons) alignment = TextAnchor.MiddleLeft, normal = new() { - background = TextureUtils.MakeSolidColourTexture(2, 2, new Color(0.15f, 0.15f, 0.15f)), + background = TextureUtils.MakeSolidColourTexture(2, 2, new Color(0.09f, 0.12f, 0.22f)), textColor = Color.white }, hover = new() { - background = TextureUtils.MakeSolidColourTexture(2, 2, new Color(0.22f, 0.22f, 0.22f)), + background = TextureUtils.MakeSolidColourTexture(2, 2, new Color(0.12f, 0.16f, 0.29f)), textColor = Color.white }, active = new() { - background = TextureUtils.MakeSolidColourTexture(2, 2, new Color(0.32f, 0.32f, 0.32f)), + background = TextureUtils.MakeSolidColourTexture(2, 2, new Color(0.15f, 0.27f, 0.37f)), textColor = Color.white }, fixedHeight = 25, diff --git a/UniTAS/Patcher/Implementations/GUI/Windows/ObjectPickerWindow.cs b/UniTAS/Patcher/Implementations/GUI/Windows/ObjectPickerWindow.cs index 715e39f8..abbcb6c8 100644 --- a/UniTAS/Patcher/Implementations/GUI/Windows/ObjectPickerWindow.cs +++ b/UniTAS/Patcher/Implementations/GUI/Windows/ObjectPickerWindow.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using UniTAS.Patcher.Interfaces.DependencyInjection; @@ -13,11 +14,21 @@ namespace UniTAS.Patcher.Implementations.GUI.Windows; [Register] -public class ObjectPickerWindow(WindowDependencies windowDependencies, IUnityInputWrapper unityInput) - : Window(windowDependencies, - config: new WindowConfig(defaultWindowRect: GUIUtils.WindowRect(500, 500), windowName: "Object picker")) +public class ObjectPickerWindow : Window { - private readonly IUpdateEvents _updateEvents = windowDependencies.UpdateEvents; + public ObjectPickerWindow(WindowDependencies windowDependencies, IUnityInputWrapper unityInput) : base( + windowDependencies, + config: new WindowConfig(defaultWindowRect: GUIUtils.WindowRect(500, 500), windowName: "Object picker")) + { + _unityInput = unityInput; + _updateEvents = windowDependencies.UpdateEvents; + var objectIconTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false); + windowDependencies.TextureWrapper.LoadImage(objectIconTexture, + Path.Combine(UniTASPaths.Resources, "object-icon.png")); + _objNameContent = new(objectIconTexture); + } + + private readonly IUpdateEvents _updateEvents; private Vector2 _scrollPos = Vector2.zero; @@ -113,7 +124,7 @@ private void ApplyFilterToObjects() private void ClickSelectUpdate() { - var mousePos = unityInput.MousePosition; + var mousePos = _unityInput.MousePosition; if (_raycastCamera == null) { _raycastCamera = Camera.main; @@ -141,13 +152,13 @@ private void ClickSelectUpdate() _clickSelectText = builder.ToString(); var close = false; - if (unityInput.GetMouseButtonDown(0)) + if (_unityInput.GetMouseButtonDown(0)) { close = true; _objects = [(0, raycastHit.gameObject)]; } - if (!close && unityInput.AnyKeyDown) + if (!close && _unityInput.AnyKeyDown) { close = true; } @@ -187,6 +198,8 @@ private static Transform RaycastFromCamera(Camera camera, Vector2 mousePos) private string _search; private GUIStyle _objNameStyle; + private readonly GUIContent _objNameContent; + protected override void OnGUI() { GUILayout.BeginVertical(); @@ -251,7 +264,8 @@ protected override void OnGUI() if (depth > 0) GUILayout.Space(depth * 20); _objNameStyle ??= new GUIStyle(UnityEngine.GUI.skin.label) { alignment = TextAnchor.MiddleLeft }; - if (GUILayout.Button(obj.name, _objNameStyle)) + _objNameContent.text = $" {obj.name}"; + if (GUILayout.Button(_objNameContent, _objNameStyle)) { OnObjectSelected?.Invoke(this, obj); _selected = true; @@ -276,4 +290,5 @@ protected override void OnGUI() public event Action OnObjectSelected; private bool _selected; + private readonly IUnityInputWrapper _unityInput; } \ No newline at end of file diff --git a/UniTAS/Patcher/Implementations/GUI/Windows/ToolBar.cs b/UniTAS/Patcher/Implementations/GUI/Windows/ToolBar.cs index c174965c..d19f1946 100644 --- a/UniTAS/Patcher/Implementations/GUI/Windows/ToolBar.cs +++ b/UniTAS/Patcher/Implementations/GUI/Windows/ToolBar.cs @@ -67,14 +67,15 @@ private set private readonly IDropdownList _dropdownList; public ToolBar(IWindowFactory windowFactory, IBinds binds, IGUIComponentFactory guiComponentFactory, - IObjectTrackerManager objectTrackerManager, IUpdateEvents updateEvents, ICursorWrapper cursorWrapper, IGameRestart gameRestart) + IObjectTrackerManager objectTrackerManager, IUpdateEvents updateEvents, ICursorWrapper cursorWrapper, + IGameRestart gameRestart) { _windowFactory = windowFactory; _cursorWrapper = cursorWrapper; gameRestart.OnGameRestart += OnGameRestart; _dropdownList = guiComponentFactory.CreateComponent(); - _buttonNormal.SetPixel(0, 0, new(0.25f, 0.25f, 0.25f)); + _buttonNormal.SetPixel(0, 0, new(0.129f, 0.149f, 0.263f)); _buttonNormal.Apply(); var buttonHold = new Texture2D(1, 1); buttonHold.SetPixel(0, 0, new(0.5f, 0.5f, 0.5f)); diff --git a/UniTAS/Patcher/Interfaces/GUI/Window.cs b/UniTAS/Patcher/Interfaces/GUI/Window.cs index a5cb132e..1d86927f 100644 --- a/UniTAS/Patcher/Interfaces/GUI/Window.cs +++ b/UniTAS/Patcher/Interfaces/GUI/Window.cs @@ -1,10 +1,12 @@ using System; +using System.IO; using BepInEx; using UniTAS.Patcher.Models.GUI; using UniTAS.Patcher.Services; using UniTAS.Patcher.Services.GUI; using UniTAS.Patcher.Services.NoRefresh; using UniTAS.Patcher.Services.UnityEvents; +using UniTAS.Patcher.Services.UnitySafeWrappers.Wrappers; using UniTAS.Patcher.Utils; using UnityEngine; @@ -85,6 +87,7 @@ protected WindowConfig Config private readonly IConfig _configService; private readonly IToolBar _toolBar; private readonly INoRefresh _noRefresh; + private readonly ITextureWrapper _textureWrapper; private string WindowName { get; set; } public string WindowConfigId { get; } @@ -104,6 +107,7 @@ protected Window(WindowDependencies windowDependencies, string windowId = null) _configService = windowDependencies.Config; _toolBar = windowDependencies.ToolBar; _noRefresh = windowDependencies.NoRefresh; + _textureWrapper = windowDependencies.TextureWrapper; } protected Window(WindowDependencies windowDependencies, WindowConfig config, string windowId = null) @@ -116,6 +120,7 @@ protected Window(WindowDependencies windowDependencies, WindowConfig config, str _configService = windowDependencies.Config; _toolBar = windowDependencies.ToolBar; _noRefresh = windowDependencies.NoRefresh; + _textureWrapper = windowDependencies.TextureWrapper; if (config != null) { Config = config; @@ -179,6 +184,10 @@ protected void Init() private bool _pendingNewLayout = true; + private static GUIStyle _windowStyle; + private static readonly Texture2D WindowBgOnNormal = new Texture2D(1, 1, TextureFormat.ARGB32, false); + private static readonly Texture2D WindowBgNormal = new Texture2D(1, 1, TextureFormat.ARGB32, false); + private void OnGUIUnconditional() { var currentEvent = Event.current; @@ -218,9 +227,24 @@ private void OnGUIUnconditional() _pendingNewLayout = false; - _windowRect = GUILayout.Window(_windowId, _windowRect, WindowUpdate, WindowName, Config.LayoutOptions); + if (_windowStyle == null) + { + _windowStyle = new GUIStyle(UnityEngine.GUI.skin.window); + _textureWrapper.LoadImage(WindowBgOnNormal, Path.Combine(UniTASPaths.Resources, "window-on-normal.png")); + _textureWrapper.LoadImage(WindowBgNormal, Path.Combine(UniTASPaths.Resources, "window-normal.png")); + _windowStyle.onNormal.background = WindowBgOnNormal; + _windowStyle.normal.background = WindowBgNormal; + } + + _windowRect = GUILayout.Window(_windowId, _windowRect, WindowUpdate, WindowName, _windowStyle, + Config.LayoutOptions); } + private static GUIStyle _closeButtonStyle; + private static readonly Texture2D CloseButtonNormal = new Texture2D(1, 1, TextureFormat.ARGB32, false); + private static readonly Texture2D CloseButtonHover = new Texture2D(1, 1, TextureFormat.ARGB32, false); + private static readonly Texture2D CloseButtonClick = new Texture2D(1, 1, TextureFormat.ARGB32, false); + private void WindowUpdate(int id) { HandleDragResize(); @@ -231,8 +255,23 @@ private void WindowUpdate(int id) GUILayout.BeginHorizontal(GUIUtils.EmptyOptions); // close button + if (_closeButtonStyle == null) + { + _closeButtonStyle = new GUIStyle(UnityEngine.GUI.skin.button); + + _textureWrapper.LoadImage(CloseButtonNormal, + Path.Combine(UniTASPaths.Resources, "window-close-normal.png")); + _textureWrapper.LoadImage(CloseButtonHover, + Path.Combine(UniTASPaths.Resources, "window-close-hover.png")); + _textureWrapper.LoadImage(CloseButtonClick, + Path.Combine(UniTASPaths.Resources, "window-close-click.png")); + _closeButtonStyle.normal.background = CloseButtonNormal; + _closeButtonStyle.hover.background = CloseButtonHover; + _closeButtonStyle.active.background = CloseButtonClick; + } + if (UnityEngine.GUI.Button(new(_windowRect.width - CloseButtonSize, 0f, CloseButtonSize, CloseButtonSize), - "x")) + GUIContent.none, _closeButtonStyle)) { Show = false; } diff --git a/UniTAS/Patcher/Models/GUI/WindowDependencies.cs b/UniTAS/Patcher/Models/GUI/WindowDependencies.cs index 21a18929..aed28976 100644 --- a/UniTAS/Patcher/Models/GUI/WindowDependencies.cs +++ b/UniTAS/Patcher/Models/GUI/WindowDependencies.cs @@ -2,6 +2,7 @@ using UniTAS.Patcher.Services.GUI; using UniTAS.Patcher.Services.NoRefresh; using UniTAS.Patcher.Services.UnityEvents; +using UniTAS.Patcher.Services.UnitySafeWrappers.Wrappers; namespace UniTAS.Patcher.Models.GUI; @@ -10,11 +11,13 @@ public class WindowDependencies( IPatchReverseInvoker patchReverseInvoker, IConfig config, IToolBar toolBar, - INoRefresh noRefresh) + INoRefresh noRefresh, + ITextureWrapper textureWrapper) { public IUpdateEvents UpdateEvents { get; } = updateEvents; public IPatchReverseInvoker PatchReverseInvoker { get; } = patchReverseInvoker; public IConfig Config { get; } = config; public INoRefresh NoRefresh { get; } = noRefresh; public IToolBar ToolBar { get; } = toolBar; + public ITextureWrapper TextureWrapper { get; } = textureWrapper; } \ No newline at end of file diff --git a/UniTAS/Patcher/RuntimeResources/Resources/object-icon.png b/UniTAS/Patcher/RuntimeResources/Resources/object-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f9960a687615a3a495e80afac3343a634cd1c8a1 GIT binary patch literal 668 zcmV;N0%QG&P)EX>4Tx04R}tkv&MmKpe$iQ>9X>4rUM$%ut=$MMWHI6^c+H)C#RSn2&xzlZGV4 z#ZhoAIQX$xb#QUk)xlK|1V2EW9h?+hq{ROvg%&X$9QWhhy~o`4LmDd;Q9Os6@D6c(`r5dvh?Q9%_p;-ge000JJOGiWi{{a60|De66lK=n!32;bRa{vG? zBLDy{BLR4&KXw2B00(qQO+^Rj3Lh00Cb?=1*8l(j8FWQhbVF}#ZDnqB07G(RVRU6= zAa`kWXdp*PO;A^X4i^9b0Ch=3K~y-)rBlHXz#s?&tRZ}fPa zSYDm?CT8#v-re%+Lmf|P6q>~b+1S1TwA5Bc_v8T#UXgQv6Im+&0000EX>4Tx04R}tkv&MmKpe$iQ>9X>4rUM$%ut=$MMWHI6^c+H)C#RSn2&xzlZGV4 z#ZhoAIQX$xb#QUk)xlK|1V2EW9h?+hq{ROvg%&X$9QWhhy~o`4LmDd;Q9Os6@D6c(`r5dvh?Q9%_p;-ge000SaNLh0L04^f{04^f|c%?sf00007bV*G` z2j~j{6CoOwGL(w|000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0001~ zNkl;#LT( kyb)<2Bp)UTkN~>@9*g{KqRR+v;Q#;t07*qoM6N<$g7dL3kN^Mx literal 0 HcmV?d00001 diff --git a/UniTAS/Patcher/RuntimeResources/Resources/window-close-hover.png b/UniTAS/Patcher/RuntimeResources/Resources/window-close-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..76f6b0446868f110b698c57bce63554fb2431d63 GIT binary patch literal 702 zcmV;v0zv(WP)EX>4Tx04R}tkv&MmKpe$iQ>9X>4rUM$%ut=$MMWHI6^c+H)C#RSn2&xzlZGV4 z#ZhoAIQX$xb#QUk)xlK|1V2EW9h?+hq{ROvg%&X$9QWhhy~o`4LmDd;Q9Os6@D6c(`r5dvh?Q9%_p;-ge000SaNLh0L04^f{04^f|c%?sf00007bV*G` z2j~j{6CWF(@V{UH000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0001~ zNklfWa~!w8NU+xVC@7sOQ~h!K-oMJAOViihr7Pv zxI}1y**e1$XeYOeM2b&K;DOMd;M4;Qgr$5c6Ivjw-chGO1Hl;A6vICVHZ|rx(1Y+q zR@lE`uMAATpgZALjBQplz@G<}1B`0UKp;Zg1A&O0dms=Y?tws*I17PDaRvg>;#LT( kyb)<2Bp)UTkN~>@9umK7_9EX>4Tx04R}tkv&MmKpe$iQ>9X>4rUM$%ut=$MMWHI6^c+H)C#RSn2&xzlZGV4 z#ZhoAIQX$xb#QUk)xlK|1V2EW9h?+hq{ROvg%&X$9QWhhy~o`4LmDd;Q9Os6@D6c(`r5dvh?Q9%_p;-ge000SaNLh0L04^f{04^f|c%?sf00007bV*G` z2j~j{6CMMqhZc7L000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0001Y zNkl^d5pfuKzmuIvaER;3vluOoF-Clu$S`1qx{AQ>MW{N3>mHh_}W#)H5eTxOwIbfZH m)?HxThSq!Ft&1oK0y|Fm6O0jkqb~md0000t076DHcLx8sGk!RyYRBEbOg#YAxn=t2<; z=tAWKx~ztIhMy;;ZrGrF+#vomx)1Xys;xi2fEplp`8a!yd%goPGjr5Aup>%X_~khP zvOq*wSa?`yM0j|3WMl+$6f1gERMe<(W5(XYnlL_T;)L;uiR={a6gFr2q{PIjl4;XX zK89gQQ)CLMAdM@;1QZA@GBR>h)To5$=mbG>VzOY^muEMKji6#;&^Uk|OJl^+JnbL} z#u-ZUUOp=Dp3Vpf4GWKmWJW=U9Wj(r40;G7G&Cdx)-HwhAS5<)Ofo++Y^)X!=PYCi zmOuMi#H1Omd*TWXUrG_`?JFXg@%JW-8$bE}DO0DVVj{6bDwAhrt8#Ml)H4fpMa6SV z9-e0)NMl*KX}-f*S>K>>$gv< zX_j?cuYY^9%mZq*0lS}#94<;f;Q_Nep!a+*BTEV0nc94!`dq_+BG+$HYT8t~Th?EM z9?-cZU{602f3~H;>;apr`>rMVZQ>suYQmH&ZA;$k{76&KRg>CuvHzX^>Za0`mv&t~ z*gNn-eqYU26{~nRORECIO{H&pz>5uQuDwxNaA08GvZQ0%jtTqj=;HaT9(of?TMD!) z)^HQe;s@?}i1)LpuXv?lt^e0%wWVz37bmV5CU%M9rX6QC=;5zHL*IoYzb)PL#@{k@ zx9vi5ulLtI~*l)XbPW|zjxbzMW&?tMm1GY_-c$waOeAl_= zfd_Marub~*9~R{5h_qL}6+12zYE=)p7@n`dcyq&f_%OE8l$DjQ&dOrj>{g?xf&{?5 zap|*)yiYO`J02@+DrgyPjEVg$|CMf)Dse&Fy8Ps$%x&`ZwaYS}TbzSfdT z+rndAdx~O0lo=Z*Y-IiE^>)wXRq_0Zi8oH2{HXKfgEb3^<32yH1{*9d*Xs)QoteAp z&;uVQFluS-DIJ0zviZ^9_Ey${(u+OQ4|u+AXnYJQVaCL)9lH+iZojWx`0~4Z+zspJ zep)wk$?QboxfSiTvtCjxGdyCiH`ISv|M_QQue8tD`s5jI@u!<}(lm)hqE{}zzp*p* z6tZ{TjyJbo-2Z68w6hN!nAI#>$BJ(aiKP=qwV83^p6%yfFWGl!*_WNlo|`KB{?jcP z$({81huH5gdrR4Oa$C{H4Oi

Q`@cEKJ|K{1ErheCZcAT2F1CUGtsL*5vBnaX)%X zy|}SaRa>*i{9Vt^#{G})J~JBaC-OF*o|(Dfk=BS08xBj(EPt(({oxPSj(yX4j`2*> zn_o(H?@30rn|`WnaNVf9as6U_RkgA+&AxBPDkFT79$jkEl{iZ@v*ZS=nTr!vJ;`;O zZQjSvG^N{y8y1jGww^3ASrnX$AME0=O@x9oSENBTwk)#Tl(*PU7A~HxGb~423X4PTR&czya+s%zc^tOa#koMiDS6vE#W9J3 z@L^<=4ujofbDFFcHie1nt(8s%hXd=`f%wcejV1_harjk$dhp!1jmPJrJhPcMxP`;1 zs)8W?fbQDDp<84lc?G1yT4^_ssw&droHQ7MFa+D%D(w|sI)s5oR*+`s>VUoShjdB3 zdInoi5|o+DHg78^_7G2}$#`3=A+b?4UOIyVfz5-sL%ajrz0S}}qmgG@4V6@Q>TCsv z>R(P+4JJbF&FTf1L?$wd5g`V@FauwP;CdsDNF*pB!eoS4LJ9{#sVxpCZZVJ)6a?p* zAdbN(!6jl`fEaPT0KxQPA%c?_ACZa(J#5bx$uQ|4h&gr>oRxUR;HW4l0z%oj)vmKzD-@jI@k6j$1D6wlJMnCIZ~;Ms2NJr# zfy4tSDo1_cQ*at9VKOfIPu|qxVW&ZVIOKUIhtq0b z8Ynm2Wh!7OhT{?uh8Sgf5rUxviO7r?fk;F` zOeWwA>>nnp<+2I z@C(NK{V57@qtGZ7iV%Vz3LJ<`dr^c|6FM6O{eFf8Yh z*)<~9uoM`U^T_P_pUK6%{l-XI;DeqEz7OX7b;&&VHW{XWC^sAAQ=h$SqAtObNL${+ z4gk25s6=x&DXU;%xKpiBg`Z_6#Z5#vE}WaUpP*QMe)$HsyXZ(4^zW@{cJm&xa literal 0 HcmV?d00001 diff --git a/UniTAS/Patcher/RuntimeResources/Resources/window-on-normal.png b/UniTAS/Patcher/RuntimeResources/Resources/window-on-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3c249c29008be2e73f3fe102d74041eac4e73afa GIT binary patch literal 8328 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 literal 0 HcmV?d00001