// ╔════════════════════════════════════════════════════════════════╗ // ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║ // ║ Licensed under Unity Asset Store Terms of Service: ║ // ║ https://unity.com/legal/as-terms ║ // ║ Use permitted only in compliance with the License. ║ // ║ Distributed "AS IS", without warranty of any kind. ║ // ╚════════════════════════════════════════════════════════════════╝ #if UNITY_EDITOR #region using NWH.NUI; using UnityEditor; using UnityEngine; #endregion namespace NWH.Common.AssetInfo { /// /// EditorWindow displaying welcome message with package information and useful links. /// Shown on first import or version update via CommonInitializationMethods. /// public class WelcomeMessageWindow : EditorWindow { /// /// AssetInfo containing package metadata and URLs to display. /// public AssetInfo assetInfo; /// /// Callback invoked when window is closed. Used to trigger next window in queue. /// internal System.Action onCloseCallback; /// /// Currently selected sidebar category index. /// private int selectedSidebarIndex = 0; /// /// Cached logo texture for package branding. /// private Texture2D logoTexture; /// /// Scroll position for content area. /// private Vector2 scrollPosition; /// /// Unity callback when window is enabled. /// Logo loading moved to OnGUI due to Unity lifecycle (assetInfo not set until after OnEnable). /// private void OnEnable() { // Logo will be loaded lazily in OnGUI when assetInfo is available } /// /// Loads package-specific logo texture with fallback to generic NWH logo. /// private void LoadLogoTexture() { if (assetInfo == null) { return; } // Try to load package-specific logo based on asset name string assetName = assetInfo.assetName; string logoPath = null; if (assetName.Contains("Vehicle Physics")) { logoPath = "NWH Vehicle Physics 2/Editor/logo_light"; } else if (assetName.Contains("Dynamic Water Physics")) { logoPath = "Dynamic Water Physics 2/Logos/dwp_logo"; } else if (assetName.Contains("Aerodynamics")) { logoPath = "NWH Aerodynamics/Editor/NAE Logo"; } else if (assetName.Contains("Wheel Controller")) { logoPath = "Wheel Controller 3D/Editor/logo_wc3d_light"; } if (!string.IsNullOrEmpty(logoPath)) { logoTexture = Resources.Load(logoPath); } // Fallback to generic NWH logo if (logoTexture == null) { logoPath = "Editor/NWHLogoSquare"; logoTexture = Resources.Load(logoPath); } } /// /// Draws welcome message GUI with package info, documentation links, and support resources. /// /// AssetInfo containing package metadata /// Window width in pixels public static void DrawWelcomeMessage(AssetInfo assetInfo, float width = 300f) { if (assetInfo == null) { Debug.LogWarning("AssetInfo is null"); return; } GUIStyle style = new(EditorStyles.helpBox); style.margin = new RectOffset(10, 10, 10, 12); style.padding = new RectOffset(10, 10, 10, 12); GUILayout.BeginVertical(style, GUILayout.Width(width - 35f)); GUILayout.Space(8); GUILayout.Label($"Welcome to {assetInfo.assetName}", EditorStyles.boldLabel); GUILayout.Space(15); GUILayout.Label($"Thank you for purchasing {assetInfo.assetName}.\n" + "Check out the following links:"); GUILayout.Space(10); GUILayout.Label("Existing customer?", EditorStyles.centeredGreyMiniLabel); if (GUILayout.Button("Upgrade Notes")) { Application.OpenURL(assetInfo.upgradeNotesURL); } if (GUILayout.Button("Changelog")) { Application.OpenURL(assetInfo.changelogURL); } GUILayout.Space(5); GUILayout.Label("New to the asset?", EditorStyles.centeredGreyMiniLabel); if (GUILayout.Button("Quick Start")) { Application.OpenURL(assetInfo.quickStartURL); } if (GUILayout.Button("Documentation")) { Application.OpenURL(assetInfo.documentationURL); } GUILayout.Space(15); GUILayout.Label("Also, don't forget to join us at Discord:", EditorStyles.centeredGreyMiniLabel); if (GUILayout.Button("Discord Server")) { Application.OpenURL(assetInfo.discordURL); } GUILayout.Space(15); GUILayout.Label("Don't have Discord? You can also contact us through:", EditorStyles.centeredGreyMiniLabel); if (GUILayout.Button("Email")) { Application.OpenURL(assetInfo.emailURL); } if (GUILayout.Button("Forum")) { Application.OpenURL(assetInfo.forumURL); } GUILayout.Space(15); GUILayout.Label("Enjoying the asset? Please consider leaving a review, \n" + "it means a lot to us developers. Thank you.", EditorStyles.centeredGreyMiniLabel); if (GUILayout.Button("Leave a Review")) { Application.OpenURL(assetInfo.assetURL); } GUILayout.EndVertical(); } /// /// Unity callback to draw window GUI. /// private void OnGUI() { if (assetInfo == null) { return; } // Lazy load logo on first draw if needed if (logoTexture == null) { LoadLogoTexture(); } // Set minimum window size minSize = new Vector2(650f, 450f); // Draw logo at top DrawLogoSection(); // Draw main content area (sidebar + content) EditorGUILayout.BeginHorizontal(); // Draw sidebar DrawSidebar(); // Draw content based on selection DrawContent(); EditorGUILayout.EndHorizontal(); } /// /// Draws logo section at top of window with background and padding. /// private void DrawLogoSection() { // Background box for logo section with NWH brand color Color originalColor = GUI.backgroundColor; GUI.backgroundColor = NUISettings.editorHeaderColor; GUIStyle logoBackgroundStyle = new GUIStyle(EditorStyles.helpBox) { padding = new RectOffset(20, 20, 15, 15) }; EditorGUILayout.BeginVertical(logoBackgroundStyle, GUILayout.Height(120)); GUILayout.FlexibleSpace(); if (logoTexture != null) { Rect logoRect = GUILayoutUtility.GetRect(100, 90, GUILayout.ExpandWidth(true)); GUI.DrawTexture(logoRect, logoTexture, ScaleMode.ScaleToFit); } else { // Fallback: show asset name if logo fails to load GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 18, alignment = TextAnchor.MiddleCenter }; GUILayout.Label(assetInfo.assetName, titleStyle); } GUILayout.FlexibleSpace(); EditorGUILayout.EndVertical(); GUI.backgroundColor = originalColor; GUILayout.Space(5); } /// /// Draws sidebar with category selection buttons. /// private void DrawSidebar() { EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Width(200)); GUILayout.Space(10); GUILayout.Label("Categories", EditorStyles.boldLabel); GUILayout.Space(15); string[] categories = { "Getting Started", "What's New", "Documentation", "Support & Community", "Other Assets" }; for (int i = 0; i < categories.Length; i++) { GUIStyle buttonStyle = new GUIStyle(GUI.skin.button) { alignment = TextAnchor.MiddleLeft, padding = new RectOffset(10, 10, 8, 8), fontStyle = selectedSidebarIndex == i ? FontStyle.Bold : FontStyle.Normal }; // NWH brand color for selected item if (selectedSidebarIndex == i) { Color originalColor = GUI.backgroundColor; GUI.backgroundColor = NUISettings.lightBlueColor; if (GUILayout.Button(categories[i], buttonStyle, GUILayout.Height(32))) { selectedSidebarIndex = i; } GUI.backgroundColor = originalColor; } else { if (GUILayout.Button(categories[i], buttonStyle, GUILayout.Height(32))) { selectedSidebarIndex = i; } } GUILayout.Space(5); } GUILayout.FlexibleSpace(); EditorGUILayout.EndVertical(); } /// /// Draws content area based on selected sidebar category. /// private void DrawContent() { scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true)); GUILayout.Space(10); switch (selectedSidebarIndex) { case 0: // Getting Started DrawGettingStartedContent(); break; case 1: // What's New DrawWhatsNewContent(); break; case 2: // Documentation DrawDocumentationContent(); break; case 3: // Support & Community DrawSupportContent(); break; case 4: // Other Assets DrawOtherAssetsContent(); break; } EditorGUILayout.EndVertical(); EditorGUILayout.EndScrollView(); } /// /// Draws Getting Started category content. /// private void DrawGettingStartedContent() { // Welcome section GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14 }; GUILayout.Label($"Welcome to {assetInfo.assetName}!", headerStyle); GUILayout.Space(8); GUILayout.Label($"Thank you for purchasing {assetInfo.assetName}. " + "We're excited to have you on board!", EditorStyles.wordWrappedLabel); GUILayout.Space(20); // Quick Start section DrawSectionHeader("Quick Start"); GUILayout.Label("Get up and running quickly with our comprehensive Quick Start guide.", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("Open Quick Start Guide", GUILayout.Height(35))) { Application.OpenURL(assetInfo.quickStartURL); } GUILayout.Space(25); // Existing Customer section DrawSectionHeader("Existing Customer?"); GUILayout.Label("Already familiar with the asset? Check what's new in this version.", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("View Upgrade Notes", GUILayout.Height(35))) { Application.OpenURL(assetInfo.upgradeNotesURL); } } /// /// Draws Documentation category content. /// private void DrawDocumentationContent() { GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14 }; GUILayout.Label("Documentation & Resources", headerStyle); GUILayout.Space(15); // Full Documentation section DrawSectionHeader("Full Documentation"); GUILayout.Label("Complete reference for all features, components, and API documentation.", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("Open Documentation", GUILayout.Height(35))) { Application.OpenURL(assetInfo.documentationURL); } GUILayout.Space(25); // Changelog section DrawSectionHeader("Changelog"); GUILayout.Label("View complete history of changes, fixes, and improvements across all versions.", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("View Changelog", GUILayout.Height(35))) { Application.OpenURL(assetInfo.changelogURL); } } /// /// Draws Support & Community category content. /// private void DrawSupportContent() { GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14 }; GUILayout.Label("Support & Community", headerStyle); GUILayout.Space(15); // Discord Community section DrawSectionHeader("Discord Community"); GUILayout.Label("Join our Discord server for quick help, discussions, and community support.", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("Join Discord Server", GUILayout.Height(35))) { Application.OpenURL(assetInfo.discordURL); } GUILayout.Space(25); // Direct Support section DrawSectionHeader("Direct Support"); GUILayout.Label("Contact us directly for technical support and assistance.", EditorStyles.wordWrappedLabel); GUILayout.Space(8); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Email Support", GUILayout.Height(35))) { Application.OpenURL(assetInfo.emailURL); } GUILayout.Space(10); if (GUILayout.Button("Forum", GUILayout.Height(35))) { Application.OpenURL(assetInfo.forumURL); } EditorGUILayout.EndHorizontal(); GUILayout.Space(25); // Review section DrawSectionHeader("Enjoying the Asset?"); GUILayout.Label("Please consider leaving a review. It means a lot to us developers and helps others discover our work!", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("Leave a Review on Asset Store", GUILayout.Height(35))) { Application.OpenURL(assetInfo.assetURL); } } /// /// Draws What's New category content showing recent updates. /// private void DrawWhatsNewContent() { GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14 }; GUILayout.Label($"What's New in {assetInfo.assetName}", headerStyle); GUILayout.Space(8); // Version info GUIStyle versionStyle = new GUIStyle(EditorStyles.label) { fontSize = 12, fontStyle = FontStyle.Italic }; GUILayout.Label($"Version {assetInfo.version}", versionStyle); GUILayout.Space(15); // Recent updates if (assetInfo.recentUpdates != null && assetInfo.recentUpdates.Length > 0) { DrawSectionHeader("Recent Updates"); GUILayout.Space(5); foreach (string update in assetInfo.recentUpdates) { if (!string.IsNullOrEmpty(update)) { EditorGUILayout.BeginHorizontal(); GUILayout.Label("•", GUILayout.Width(15)); GUILayout.Label(update, EditorStyles.wordWrappedLabel); EditorGUILayout.EndHorizontal(); GUILayout.Space(5); } } GUILayout.Space(20); // Link to full changelog GUILayout.Label("For complete version history and detailed changes:", EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("View Full Changelog", GUILayout.Height(35))) { Application.OpenURL(assetInfo.changelogURL); } } else { GUILayout.Label("No recent updates information available.", EditorStyles.centeredGreyMiniLabel); GUILayout.Space(15); if (GUILayout.Button("View Full Changelog", GUILayout.Height(35))) { Application.OpenURL(assetInfo.changelogURL); } } } /// /// Draws Other Assets category content showing other NWH products. /// private void DrawOtherAssetsContent() { GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14 }; GUILayout.Label("Other NWH Assets", headerStyle); GUILayout.Space(15); GUILayout.Label("Explore our other high-quality Unity assets:", EditorStyles.wordWrappedLabel); GUILayout.Space(20); // Define other NWH assets (excluding current one) string currentAsset = assetInfo.assetName; if (!currentAsset.Contains("Vehicle Physics")) { DrawAssetCard("NWH Vehicle Physics 2", "Complete vehicle physics solution with realistic wheel physics, sound, damage, and more.", "https://assetstore.unity.com/packages/tools/physics/nwh-vehicle-physics-2-166252?aid=1011ljhgE"); } if (!currentAsset.Contains("Dynamic Water Physics")) { DrawAssetCard("Dynamic Water Physics 2", "Advanced water simulation with buoyancy, ship controllers, and realistic water interactions.", "https://assetstore.unity.com/packages/tools/physics/dynamic-water-physics-2-147990?aid=1011ljhgE"); } if (!currentAsset.Contains("Wheel Controller")) { DrawAssetCard("Wheel Controller 3D", "Standalone wheel physics controller with advanced tire friction and suspension simulation.", "https://assetstore.unity.com/packages/tools/physics/wheel-controller-3d-49574?aid=1011ljhgE"); } if (!currentAsset.Contains("Aerodynamics")) { DrawAssetCard("NWH Aerodynamics", "Realistic aerodynamics simulation for aircraft and vehicles with customizable airfoils.", "https://assetstore.unity.com/packages/tools/physics/nwh-aerodynamics-288831?aid=1011ljhgE"); } GUILayout.Space(15); // Link to publisher page DrawSectionHeader("View All Assets"); if (GUILayout.Button("Visit NWH Publisher Page", GUILayout.Height(35))) { Application.OpenURL(assetInfo.publisherURL); } } /// /// Helper method to draw a section header with consistent styling. /// private void DrawSectionHeader(string title) { GUIStyle sectionStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 12 }; Color originalColor = GUI.contentColor; GUI.contentColor = NUISettings.propertyHeaderColor; GUILayout.Label(title, sectionStyle); GUI.contentColor = originalColor; } /// /// Helper method to draw an asset card with name, description, and link. /// private void DrawAssetCard(string assetName, string description, string url) { GUIStyle cardStyle = new GUIStyle(EditorStyles.helpBox) { padding = new RectOffset(12, 12, 10, 10) }; EditorGUILayout.BeginVertical(cardStyle); GUILayout.Label(assetName, EditorStyles.boldLabel); GUILayout.Space(5); GUILayout.Label(description, EditorStyles.wordWrappedLabel); GUILayout.Space(8); if (GUILayout.Button("View on Asset Store", GUILayout.Height(30))) { Application.OpenURL(url); } EditorGUILayout.EndVertical(); GUILayout.Space(12); } /// /// Unity callback when window is destroyed. Triggers next window in queue. /// private void OnDestroy() { onCloseCallback?.Invoke(); } } } #endif