diff --git a/Editor/Helper/GUIStyles.cs b/Editor/Helper/GUIStyles.cs index c5f8f16..3a57f71 100644 --- a/Editor/Helper/GUIStyles.cs +++ b/Editor/Helper/GUIStyles.cs @@ -1,3 +1,4 @@ +using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; diff --git a/Editor/Helper/Helper.cs b/Editor/Helper/Helper.cs index 0b83ee7..f1890fa 100644 --- a/Editor/Helper/Helper.cs +++ b/Editor/Helper/Helper.cs @@ -316,6 +316,45 @@ public static void DrawHelpbox(PropertyStaticData propertyStaticData, PropertyDy } } + public static readonly float helpURLButtonWidth = 18f; + + private static GUIContent _helpURLIconCache; + private static GUIContent _helpURLIcon => _helpURLIconCache ??= new GUIContent(EditorGUIUtility.IconContent("_Help")) { tooltip = string.Empty }; + + public static Rect GetHelpURLRect(Rect parentRect) + { + return new Rect(parentRect.xMax - helpURLButtonWidth - 4f, + parentRect.yMax - (EditorGUIUtility.singleLineHeight + helpURLButtonWidth) * 0.5f - 4.5f, + helpURLButtonWidth, + helpURLButtonWidth); + } + + public static void HandleHelpURLClick(Rect parentRect, string helpURL) + { + if (string.IsNullOrEmpty(helpURL)) return; + + var rect = GetHelpURLRect(parentRect); + if (Event.current.type == EventType.MouseDown + && Event.current.button == 0 + && rect.Contains(Event.current.mousePosition)) + { + Application.OpenURL(helpURL); + Event.current.Use(); + } + } + + public static void DrawHelpURLIcon(Rect parentRect, string helpURL) + { + if (string.IsNullOrEmpty(helpURL)) return; + + var rect = GetHelpURLRect(parentRect); + var content = new GUIContent(_helpURLIcon) { tooltip = helpURL }; + var enabled = GUI.enabled; + GUI.enabled = true; + GUI.Label(rect, content, GUIStyles.iconButton); + GUI.enabled = enabled; + } + private static Texture _logoCache; private static GUIContent _logoGuiContentCache; private static Texture _logo => _logoCache = _logoCache ?? AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath("26b9d845eb7b1a747bf04dc84e5bcc2c")); diff --git a/Editor/LWGUI.cs b/Editor/LWGUI.cs index f495817..b62c23a 100644 --- a/Editor/LWGUI.cs +++ b/Editor/LWGUI.cs @@ -174,6 +174,10 @@ private void DrawProperty(MaterialProperty prop) var revertButtonRect = RevertableHelper.SplitRevertButtonRect(ref rect); + var hasHelpURL = propStaticData.isMain && !string.IsNullOrEmpty(propStaticData.helpURL); + if (hasHelpURL) + Helper.HandleHelpURLClick(rect, propStaticData.helpURL); + var enabled = GUI.enabled; if (propStaticData.isReadOnly || !propDynamicData.isActive) GUI.enabled = false; @@ -186,6 +190,9 @@ private void DrawProperty(MaterialProperty prop) RevertableHelper.DrawRevertableProperty(revertButtonRect, prop, metaDatas, propStaticData.isMain || propStaticData.isAdvancedHeaderProperty); materialEditor.ShaderProperty(rect, prop, label); + + if (hasHelpURL) + Helper.DrawHelpURLIcon(rect, propStaticData.helpURL); Helper.EndProperty(metaDatas, prop); GUI.enabled = enabled; diff --git a/Editor/ShaderDrawers/ExtraDecorators/Appearance/HelpURLDecorator.cs b/Editor/ShaderDrawers/ExtraDecorators/Appearance/HelpURLDecorator.cs new file mode 100644 index 0000000..a2a85a8 --- /dev/null +++ b/Editor/ShaderDrawers/ExtraDecorators/Appearance/HelpURLDecorator.cs @@ -0,0 +1,54 @@ +// Copyright (c) Jason Ma + +using UnityEditor; +using UnityEngine; + +namespace LWGUI +{ + /// + /// Display a Help URL button on the right side of the Group. + /// Clicking the button opens the URL in the default browser. + /// "https://" is automatically prepended. + /// Each comma-separated parameter is joined with '/' to form the full URL path. + /// + /// url: the document URL without "https://", each ',' = '/'. (Default: none) + /// e.g. [HelpURL(github.com, JasonMa0012, LWGUI)] => https://github.com/JasonMa0012/LWGUI + /// + public class HelpURLDecorator : SubDrawer + { + private string _url; + + private static string Join(params string[] segments) => string.Join("/", segments); + + #region + + public HelpURLDecorator(string url) { this._url = url; } + public HelpURLDecorator(string s1, string s2) : this(Join(s1, s2)) { } + public HelpURLDecorator(string s1, string s2, string s3) : this(Join(s1, s2, s3)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4) : this(Join(s1, s2, s3, s4)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5) : this(Join(s1, s2, s3, s4, s5)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6) : this(Join(s1, s2, s3, s4, s5, s6)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7) : this(Join(s1, s2, s3, s4, s5, s6, s7)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10, string s11) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10, string s11, string s12) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10, string s11, string s12, string s13) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10, string s11, string s12, string s13, string s14) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10, string s11, string s12, string s13, string s14, string s15) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15)) { } + public HelpURLDecorator(string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8, string s9, string s10, string s11, string s12, string s13, string s14, string s15, string s16) : this(Join(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16)) { } + + #endregion + + + protected override float GetVisibleHeight(MaterialProperty prop) { return 0; } + + public override void BuildStaticMetaData(Shader inShader, MaterialProperty inProp, MaterialProperty[] inProps, PropertyStaticData inoutPropertyStaticData) + { + inoutPropertyStaticData.helpURL = "https://" + _url.Replace(" ", ""); + } + + public override void DrawProp(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor) { } + } +} diff --git a/Editor/ShaderDrawers/ExtraDecorators/Appearance/HelpURLDecorator.cs.meta b/Editor/ShaderDrawers/ExtraDecorators/Appearance/HelpURLDecorator.cs.meta new file mode 100644 index 0000000..bc92d27 --- /dev/null +++ b/Editor/ShaderDrawers/ExtraDecorators/Appearance/HelpURLDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fe03ed76bbf6b14f8c9ed73abdd3c9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ShaderDrawers/ShaderDrawerBase.cs b/Editor/ShaderDrawers/ShaderDrawerBase.cs index 0a46ba3..7c5aa66 100644 --- a/Editor/ShaderDrawers/ShaderDrawerBase.cs +++ b/Editor/ShaderDrawers/ShaderDrawerBase.cs @@ -33,6 +33,9 @@ public partial class PropertyStaticData public List buttonCommands = new(); public List buttonDisplayNameWidths = new(); + // HelpURL + public string helpURL = string.Empty; + // You can add more data that is determined during the initialization of the Drawer as a cache here, // thereby avoiding the need to calculate it every frame in OnGUI(). // >>>>>>>>>>>>>>>>>>>>>>>> Add new data here <<<<<<<<<<<<<<<<<<<<<<< diff --git a/README.md b/README.md index 4dfe422..4399868 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ It significantly shortens iteration cycles while improving collaboration between * [Title & SubTitle](#title--subtitle) * [Tooltip & Helpbox](#tooltip--helpbox) * [ReadOnly](#readonly) + * [HelpURL](#helpurl) * [Logic](#logic) * [PassSwitch](#passswitch) * [Structure](#structure) @@ -867,6 +868,32 @@ Tips: public ReadOnlyDecorator() ``` +#### HelpURL + +```c# +/// Display a Help URL button on the right side of the Group. +/// Clicking the button opens the URL in the default browser. +/// "https://" is automatically prepended. +/// Each comma-separated parameter is joined with '/' to form the full URL path. +/// +/// url: the document URL without "https://", each ',' = '/'. (Default: none) +/// e.g. [HelpURL(github.com, JasonMa0012, LWGUI)] => https://github.com/JasonMa0012/LWGUI +public HelpURLDecorator(string url) +public HelpURLDecorator(string s1, string s2) +... +public HelpURLDecorator(string s1, string s2, ..., string s16) +``` + +Example: + +```c# +[HelpURL(github.com, JasonMa0012, LWGUI)] +[Main(GroupName)] _group ("Group", float) = 0 + +[HelpURL(github.com, JasonMa0012, LWGUI, blob, 1.x, README.md)] +[Main(GroupName2, _, on, off)] _group2 ("Group2", float) = 0 +``` + ### Logic #### PassSwitch diff --git a/README_CN.md b/README_CN.md index 1c3f86f..336c690 100644 --- a/README_CN.md +++ b/README_CN.md @@ -60,6 +60,7 @@ LWGUI 已在诸多大型商业项目中长期验证: * [Title & SubTitle](#title--subtitle) * [Tooltip & Helpbox](#tooltip--helpbox) * [ReadOnly](#readonly) + * [HelpURL](#helpurl) * [Logic](#logic) * [PassSwitch](#passswitch) * [Structure](#structure) @@ -864,6 +865,32 @@ Tips: public ReadOnlyDecorator() ``` +#### HelpURL + +```c# +/// 在Group右侧显示一个帮助文档链接按钮. +/// 点击后会在默认浏览器中打开指定URL. +/// 自动添加"https://"前缀. +/// 每个逗号分隔的参数以'/'连接, 组成完整URL路径. +/// +/// url: 不含"https://"的文档URL, 每个','='/' (默认: 无) +/// 例: [HelpURL(github.com, JasonMa0012, LWGUI)] => https://github.com/JasonMa0012/LWGUI +public HelpURLDecorator(string url) +public HelpURLDecorator(string s1, string s2) +... +public HelpURLDecorator(string s1, string s2, ..., string s16) +``` + +示例: + +```c# +[HelpURL(github.com, JasonMa0012, LWGUI)] +[Main(GroupName)] _group ("Group", float) = 0 + +[HelpURL(github.com, JasonMa0012, LWGUI, blob, 1.x, README.md)] +[Main(GroupName2, _, on, off)] _group2 ("Group2", float) = 0 +``` + ### Logic #### PassSwitch diff --git a/Test/SampleDrawerA.shader b/Test/SampleDrawerA.shader index dbc15de..426db9d 100644 --- a/Test/SampleDrawerA.shader +++ b/Test/SampleDrawerA.shader @@ -15,6 +15,7 @@ [Title(Title on Group)] // Create a folding group with name "g1" + [HelpURL(github.com, JasonMa0012, LWGUI)] [Main(g1)] _group ("Group", float) = 0 [Sub(g1)] _float ("float", float) = 2 @@ -37,6 +38,7 @@ // Create a drop-down menu that opens by default, without toggle + [HelpURL(github.com, JasonMa0012, LWGUI, blob, 1.x, README.md)] [Main(g2, _KEYWORD, on, off)] _group2 ("group2 without toggle", float) = 1 [Tooltip(Test Tooltip)] [Helpbox(Test Helpbox)] @@ -52,6 +54,7 @@ [RampAtlasIndexer(g2, _RampAtlas, Green, Linear, GA, 24)] _RampAtlasIndex2 ("Indexer Linear/Green/24", float) = 3 + [HelpURL(github.com, JasonMa0012, LWGUI, blob, 1.x, package.json)] [Main(Preset, _, on, off)] _PresetGroup ("Preset Samples", float) = 0 [Preset(Preset, LWGUI_Preset_BlendMode)] _BlendMode ("Blend Mode Preset", float) = 0 [SubEnum(Preset, UnityEngine.Rendering.CullMode)] _Cull ("Cull", Float) = 2