This commit is contained in:
2026-07-09 21:33:33 +02:00
commit 84a2a365f3
2364 changed files with 950134 additions and 0 deletions
@@ -0,0 +1,9 @@
using VOID.UserInterface.Game.Util;
namespace VOID.UserInterface.Game.Interfaces
{
public interface IHasWindow
{
public WindowUI windowUI { get; }
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 54723d0142c14d8a9dd1b6ccebbba3dd
timeCreated: 1720718867
@@ -0,0 +1,10 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Style src="project://database/Assets/92%20-%20UserInterface/Generic/Game/Utility/SlotInner.uss?fileID=7433441132597879392&amp;guid=28796e98eb4058846bf25d5786d0b036&amp;type=3#SlotInner" />
<ui:Button name="root-slot" enable-rich-text="false" picking-mode="Ignore">
<ui:VisualElement name="background" picking-mode="Ignore" />
<ui:VisualElement name="icon" picking-mode="Ignore" />
<ui:VisualElement name="border" picking-mode="Ignore" />
</ui:Button>
</ui:UXML>
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5a74e2b56bbc27c4ab7a5d0c1de93f00
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
@@ -0,0 +1,37 @@
#root-slot {
width: 100%;
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
background-color: rgba(0, 0, 0, 0);
height: 100%;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
border-left-width: 0;
border-right-width: 0;
border-top-width: 0;
border-bottom-width: 0;
}
#root-slot > #background {
position: absolute;
width: 100%;
height: 100%;
background-image: url('project://database/Assets/_ADDONS/MedievalKingdomUI/Artworks/White_gold_Skin/UI_elements_W/icon_frame_bg.png?fileID=2800000&guid=27f3ca780c69fcf49b884913b9ac5e3b&type=3#icon_frame_bg');
}
#root-slot > #icon {
position: absolute;
width: 100%;
height: 100%;
}
#root-slot > #border {
position: absolute;
width: 100%;
height: 100%;
background-image: url('project://database/Assets/_ADDONS/MedievalKingdomUI/Artworks/White_gold_Skin/UI_elements_W/icon_frame.png?fileID=2800000&guid=f272753cabc45b9419037998d01412e7&type=3#icon_frame');
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28796e98eb4058846bf25d5786d0b036
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,17 @@
.slot {
}
.slot-small {
height: 40px;
width: 40px;
}
.slot-medium {
height: 55px;
width: 55px;
}
.slot-big {
height: 70px;
width: 70px;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 760aa0b2431a11e46a81be0018d225b1
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,128 @@
using UnityEngine;
using UnityEngine.UIElements;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Item;
using VOID.ScriptableObjects.Abilities;
namespace VOID.UserInterface.Game.Util
{
/// <summary>
/// Manages all visuals inside slot: <see cref="ItemObject"/> or <see cref="BasicAbility"/>,
/// including: image, border and background
/// </summary>
public class SlotUI
{
// Where slot belongs with its index
public SlotType slotType { get; private set; }
public int slotIndex { get; private set; }
// Content of slot
public bool isEmpty { get; private set; } = true;
public ItemObject item { get; private set; }
public BasicAbility ability { get; private set; }
// Elements
private VisualElement _templateElement;
private VisualElement _backgroundElement;
private VisualElement _borderElement;
private VisualElement _iconElement;
/// <summary>
/// Initializes <see cref="SlotUI"/> on existing slot visual element.
/// </summary>
/// <param name="templateElement">Existing template to use for this slot</param>
/// <param name="slotType">Defines to which UI it belongs.</param>
/// <param name="slotIndex">Defines specific slot index in UI.</param>
public void Init(VisualElement templateElement, SlotType slotType, int slotIndex)
{
_templateElement = templateElement;
this.slotType = slotType;
this.slotIndex = slotIndex;
// Find all Slot's elements
_backgroundElement = _templateElement.Q("background");
_borderElement = _templateElement.Q("border");
_iconElement = _templateElement.Q("icon");
// Binding component to element
_templateElement.dataSource = this;
_templateElement.pickingMode = PickingMode.Position;
}
/// <summary>
/// Initializes completly new <see cref="SlotUI"/> inside given parent.
/// </summary>
/// <param name="parentElement">Create new slot as child in given parent.</param>
/// <param name="slotType">Defines to which UI it belongs.</param>
/// <param name="slotIndex">Defines specific slot index in UI.</param>
/// <param name="name">Name for new Visual Element</param>
public void InitNew(VisualElement parentElement, SlotType slotType, int slotIndex, string name = null)
{
// Create Slot (from template) in GUI
var templateElement = GameUI.current.slotTemplate.CloneTree().contentContainer;
templateElement.name = name ?? "slot";
templateElement.AddToClassList("slot");
templateElement.AddToClassList("slot-medium");
parentElement.Add(templateElement);
Init(templateElement, slotType, slotIndex);
}
/// <summary>
/// Change slot index. Useful when slot don't move anywhere, but whole counting change.
/// </summary>
public void ChangeIndex(int newIndex)
{
slotIndex = newIndex;
}
/// <summary>
/// Put <see cref="ItemObject"/> into this slot and update all visuals.
/// </summary>
public void Set(ItemObject item)
{
Clear();
if (!item) return;
this.item = item;
UpdateIconElement(item.basicData.image, item.itemData.quality.background, item.itemData.quality.border);
}
/// <summary>
/// Put <see cref="BasicAbility"/> into this slot and update all visuals.
/// </summary>
public void Set(BasicAbility ability)
{
Clear();
if (!ability) return;
this.ability = ability;
UpdateIconElement(ability.displayIcon, ability.quality.background, ability.quality.border);
}
private void UpdateIconElement(Texture2D icon, Texture2D background, Texture2D border)
{
isEmpty = false;
_backgroundElement.style.backgroundImage = new StyleBackground(background);
_iconElement.style.backgroundImage = new StyleBackground(icon);
_borderElement.style.backgroundImage = new StyleBackground(border);
}
/// <summary>
/// Remove <see cref="ItemObject"/> or <see cref="BasicAbility"/> from this slot and make it empty.
/// </summary>
public void Clear()
{
_iconElement.style.backgroundImage = new StyleBackground(StyleKeyword.Null);
ability = null;
item = null;
isEmpty = true;
}
/// <summary>
/// Destroy whole <see cref="SlotUI"/> with its <see cref="VisualElement"/>.
/// </summary>
public void Destroy()
{
_templateElement.parent.Remove(_templateElement);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f1c96fb02c124931b4416e0465f9a5bb
timeCreated: 1673204998
@@ -0,0 +1,10 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Style src="project://database/Assets/92%20-%20UserInterface/Generic/Game/Utility/StatusInner.uss?fileID=7433441132597879392&amp;guid=f7652f06b5fcc1e4c92df4749fc71467&amp;type=3#StatusInner" />
<ui:VisualElement name="root-status" picking-mode="Ignore" style="flex-grow: 1;">
<ui:VisualElement name="background" picking-mode="Ignore" style="flex-grow: 1;" />
<ui:VisualElement name="icon" picking-mode="Ignore" style="background-image: url(&apos;project://database/Assets/5%20-%20Textures/Generic/Icons/status_placeholder_icon.png?fileID=2800000&amp;guid=f386e7ee1fbaf804396fd2b5d6176a56&amp;type=3#status_placeholder_icon&apos;);" />
<ui:Label text="{TIME}" name="time-remaining" picking-mode="Ignore" />
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9c95cff4b708f194db8bb1259ba03d85
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
@@ -0,0 +1,29 @@
#root-status {
width: 100%;
height: 100%;
}
#root-status > #background {
background-color: rgba(0, 0, 0, 0.48);
}
#root-status > #icon {
width: 100%;
height: 100%;
position: absolute;
}
#root-status > #time-remaining {
position: absolute;
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
width: 100%;
-unity-text-align: upper-center;
-unity-font-style: bold;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7652f06b5fcc1e4c92df4749fc71467
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,29 @@
.status {
}
.status-small {
height: 30px;
width: 30px;
}
.status-small #time-remaining {
font-size: 10px;
}
.status-medium {
height: 45px;
width: 45px;
}
.status-medium #time-remaining {
font-size: 15px;
}
.status-big {
height: 60px;
width: 60px;
}
.status-big #time-remaining {
font-size: 20px;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6eb1ae18d8fd2c541be09b7ecad6e722
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,61 @@
using System;
using UnityEngine.UIElements;
using VOID.ScriptableObjects;
namespace VOID.UserInterface.Game.Util
{
[Serializable]
public class StatusUI
{
// Content of slot
public BasicStatus status { get; private set; }
// Elements
private VisualElement _templateElement;
private VisualElement _iconElement;
private Label _timerLabel;
/// <summary>
/// Initializes completly new <see cref="StatusUI"/> inside given parent.
/// </summary>
/// <param name="parentWrapperElement">Create new status as child in given parent.</param>
/// <param name="status"><see cref="BasicStatus"/> to use for this StatusUI</param>
/// <param name="name">Optional name for UI element</param>
public void InitNew(VisualElement parentWrapperElement, BasicStatus status, string name = null)
{
this.status = status;
// Create Status (from template) in GUI
_templateElement = GameUI.current.statusTemplate.CloneTree().contentContainer;
_templateElement.name = name ?? "status";
_templateElement.AddToClassList("status");
_templateElement.AddToClassList("status-medium");
parentWrapperElement.Add(_templateElement);
// Find all Status's elements
_iconElement = _templateElement.Q("icon");
_iconElement.style.backgroundImage = new StyleBackground(status.displayIcon);
_timerLabel = _templateElement.Q<Label>("time-remaining");
// Monitor what happening to displayed status
status.OnTimeDecrease += OnTimeDecrease;
// Also force
OnTimeDecrease();
_templateElement.dataSource = this;
_templateElement.pickingMode = PickingMode.Position;
}
public void Destroy()
{
status.OnTimeDecrease -= OnTimeDecrease;
_templateElement.parent.Remove(_templateElement);
}
private void OnTimeDecrease()
{
_timerLabel.text = status.durationLeft.ToString("0");
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c7631d6650df4a3fbf44905ca6c5c0d7
timeCreated: 1696165886
@@ -0,0 +1,12 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Style src="project://database/Assets/92%20-%20UserInterface/Generic/Game/Utility/UnitPortraitInner.uss?fileID=7433441132597879392&amp;guid=6aa5b13cdb7a3d84994729c506f6ba51&amp;type=3#UnitPortraitInner" />
<ui:VisualElement name="root-unit-portrait" picking-mode="Ignore">
<ui:Button name="portrait" picking-mode="Ignore">
<ui:ProgressBar value="69" title=" " name="health-bar" picking-mode="Ignore" />
</ui:Button>
<ui:Label text="69/100" name="health-label" />
<ui:VisualElement name="border" picking-mode="Ignore" />
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2b588e131b790bd408086718bd2f82cd
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
@@ -0,0 +1,124 @@
#root-unit-portrait {
width: 100%;
height: 100%;
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
}
#portrait {
width: 100%;
height: 100%;
background-image: url('project://database/Assets/5%20-%20Textures/Generic/Portraits/Units/PortraitPlaceholder.png?fileID=2800000&guid=257f48a9190bac44e9fc555146d7690d&type=3#PortraitPlaceholder');
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
border-top-left-radius: 7%;
border-top-right-radius: 7%;
border-bottom-right-radius: 7%;
border-bottom-left-radius: 7%;
overflow: hidden;
}
#health-bar {
width: 100%;
background-color: rgba(88, 88, 88, 0.59);
position: absolute;
height: 5%;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
padding-top: 0;
padding-right: 5%;
padding-left: 5%;
bottom: 3%;
}
#health-bar .unity-progress-bar__container {
max-height: 100%;
max-width: 100%;
min-height: auto;
min-width: auto;
width: 100%;
height: 100%;
}
#health-bar .unity-progress-bar__background {
background-color: rgba(0, 0, 0, 0.39);
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
max-width: 100%;
max-height: 100%;
width: 100%;
height: 100%;
border-left-width: 0;
border-right-width: 0;
border-top-width: 0;
border-bottom-width: 0;
}
#health-bar .unity-progress-bar__progress {
background-color: rgb(255, 0, 0);
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
max-width: 100%;
max-height: 100%;
width: auto;
height: 100%;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
}
#health-bar .unity-progress-bar__title-container {
display: none;
}
#health-label {
position: absolute;
bottom: 5%;
align-self: center;
margin-top: 0;
margin-right: 0;
margin-bottom: 0;
margin-left: 0;
padding-top: 0;
padding-right: 0;
padding-bottom: 0;
padding-left: 0;
-unity-font-style: bold;
color: rgb(255, 255, 255);
text-shadow: 1px 1px 1px rgb(0, 0, 0);
}
#border {
width: 100%;
height: 100%;
position: absolute;
background-image: url('project://database/Assets/_ADDONS/MedievalKingdomUI/Artworks/Classic_Skin/UI_elements_C/icon_frame_lg.png?fileID=2800000&guid=f8efd3dc9609b4e45add8aebb16b34f2&type=3#icon_frame_lg');
}
.active #border {
background-image: url('project://database/Assets/_ADDONS/MedievalKingdomUI/Artworks/White_gold_Skin/UI_elements_W/icon_frame_lg.png?fileID=2800000&guid=0964db7d06777d1429e0648e8be94ba7&type=3#icon_frame_lg');
-unity-background-image-tint-color: rgb(255, 255, 0);
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6aa5b13cdb7a3d84994729c506f6ba51
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,41 @@
.unit-portrait-small {
height: 120px;
width: 80px;
}
.unit-portrait-small #health-bar {
height: 5px;
}
.unit-portrait-small #health-label {
font-size: 12px;
}
.unit-portrait-medium {
height: 165px;
width: 110px;
}
.unit-portrait-medium #health-bar {
height: 7px;
}
.unit-portrait-medium #health-label {
font-size: 15px;
}
.unit-portrait-big {
height: 210px;
width: 140px;
}
.unit-portrait-big #health-bar {
height: 9px;
}
.unit-portrait-big #health-label {
font-size: 18px;
}
.unit-portrait {
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9fd7af89854ed243b3383ce693bc254
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,119 @@
using System;
using Sirenix.OdinInspector;
using UnityEngine.UIElements;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Abstract.Events;
using VOID.Generic.Objects.Unit;
namespace VOID.UserInterface.Game.Party
{
/// <summary>
/// Manages all visuals inside <see cref="UnitObject"/> portrait, including: image, border and healthbar
/// </summary>
public class UnitPortraitUI
{
[ShowInInspector, ReadOnly] public UnitObject unit { get; private set; }
public event Action<UnitObject> OnClick;
// Visual Elements
public VisualElement templateElement { get; private set; }
private Button _portrait;
private ProgressBar _healthBar;
private Label _healthLabel;
/// <summary>
/// Initializes <see cref="UnitPortraitUI"/> on existing potrait visual element.
/// </summary>
/// <param name="unitPortraitTemplate">Existing template to use for this portrait</param>
public void Init(VisualElement unitPortraitTemplate)
{
// Find all important elements
templateElement = unitPortraitTemplate;
_portrait = templateElement.Q<Button>("portrait");
_healthBar = templateElement.Q<ProgressBar>("health-bar");
_healthLabel = templateElement.Q<Label>("health-label");
templateElement.RegisterCallback(new EventCallback<MouseDownEvent>(_ => OnClick?.Invoke(unit)), TrickleDown.TrickleDown);
// Binding component to element
templateElement.dataSource = this;
templateElement.pickingMode = PickingMode.Position;
}
/// <summary>
/// Initializes completly new <see cref="UnitPortraitUI"/> inside given parent.
/// </summary>
/// <param name="parentElement">Create new potratit as child in given parent.</param>
public void InitNew(VisualElement parentElement)
{
// Find all important elements
var newTemplateElement = GameUI.current.unitPortraitTemplate.CloneTree().contentContainer;
newTemplateElement.AddToClassList("unit-portrait");
newTemplateElement.AddToClassList("unit-portrait-small");
parentElement.Add(newTemplateElement);
Init(newTemplateElement);
}
/// <summary>
/// Display given <see cref="UnitObject"/> in this portrait.
/// </summary>
public void SetUnit(UnitObject unitToSet)
{
// Remove everything about previous Unit
UnsetUnit();
// New Unit assigned - start listeners and wait
unit = unitToSet;
unit.basicEvents.onCurrentResourceChange.AddListener(OnBasicResourceChange);
// Set Unit's portrait
_portrait.style.backgroundImage = new StyleBackground(unit.basicData.image);
UnitPortraitHealthChange();
}
/// <summary>
/// Clear currently displaying <see cref="UnitObject"/> in this portrait.
/// </summary>
public void UnsetUnit()
{
// There is no unit currently
if (!unit) return;
// Remove all listeners, then remove assigned Unit
unit.basicEvents.onCurrentResourceChange.RemoveListener(OnBasicResourceChange);
unit = null;
// Make UI invisible and unset portrait
_portrait.style.backgroundImage = null;
}
/// <summary>
/// Completly destroy this potratit.
/// </summary>
public void Destroy()
{
unit.basicEvents.onCurrentResourceChange.RemoveListener(OnBasicResourceChange);
templateElement.parent.Remove(templateElement);
}
private void OnBasicResourceChange(BasicResourceChangeEvent basicResourceChangeEvent)
{
// Update HealthBar length
if (basicResourceChangeEvent.type is BasicResourceType.Health)
{
UnitPortraitHealthChange();
}
}
private void UnitPortraitHealthChange()
{
// Update HealthBar length
_healthBar.value = unit.basicData.currentResources.Get(BasicResourceType.Health) / unit.basicData.maxResources.Get(BasicResourceType.Health) * 100;
// Update HealthBar label
_healthLabel.text = $"{unit.basicData.currentResources.Get(BasicResourceType.Health)}/{unit.basicData.maxResources.Get(BasicResourceType.Health)}";
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1f4b363d4ac84b1dacd35f6a1ed17802
timeCreated: 1697404285
@@ -0,0 +1,15 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Style src="project://database/Assets/92%20-%20UserInterface/Generic/Game/Utility/WindowInner.uss?fileID=7433441132597879392&amp;guid=29ea7ef4a8f41f04a97d41ef15550aca&amp;type=3#WindowInner" />
<ui:VisualElement name="root-window" picking-mode="Ignore" style="flex-grow: 1;">
<ui:VisualElement name="image" picking-mode="Ignore" />
<ui:VisualElement name="header-center" picking-mode="Ignore">
<ui:VisualElement name="header">
<ui:Label text="EXAMPLE_TITLE" display-tooltip-when-elided="true" name="title" picking-mode="Ignore" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="border" picking-mode="Ignore" />
<ui:Button text="x" name="close" />
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 04235ec1d1b764e448e2524000a1b87a
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
@@ -0,0 +1,66 @@
#root-window > #image {
width: 100%;
height: 100%;
position: absolute;
background-color: rgb(33, 33, 33);
min-width: auto;
min-height: auto;
}
#root-window > #header-center {
align-items: center;
}
#root-window > #header-center > #header {
position: absolute;
padding-top: 15px;
padding-left: 5px;
padding-right: 5px;
padding-bottom: 5px;
background-color: rgba(0, 0, 0, 0.39);
}
#root-window > #header-center > #header > #title {
-unity-text-align: upper-center;
width: 100%;
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
padding-bottom: 0;
color: rgb(187, 187, 187);
}
#root-window > #border {
position: absolute;
width: 100%;
height: 100%;
background-image: url('project://database/Assets/_ADDONS/MedievalKingdomUI/Artworks/White_gold_Skin/UI_elements_W/Main_bar_frame.png?fileID=2800000&guid=f3e73c26aa3a97547bc7b96427ec4084&type=3#Main_bar_frame');
min-width: 150px;
min-height: 150px;
-unity-background-scale-mode: stretch-to-fill;
-unity-slice-left: 32;
-unity-slice-top: 32;
-unity-slice-right: 32;
-unity-slice-bottom: 32;
-unity-slice-scale: 0.5px;
}
#root-window > #close {
position: absolute;
width: 25px;
height: 25px;
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 0;
padding-left: 5px;
padding-right: 5px;
padding-top: 5px;
padding-bottom: 5px;
right: 5px;
top: 5px;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 29ea7ef4a8f41f04a97d41ef15550aca
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,5 @@
#window {
position: absolute;
width: 100%;
height: 100%;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80611877e61dcf346bf43cfc4ebd3394
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
using PlayerInputManager = VOID.Generic.Player.Input.PlayerInputManager;
using ShortcutsInputManager = VOID.Generic.Player.Input.ShortcutsInputManager;
namespace VOID.UserInterface.Game.Util
{
[Serializable]
public class WindowUI : MonoBehaviour
{
public static List<WindowUI> openWindows = new();
// UI Visual Elements
private VisualElement _parentElement;
private VisualElement _rootElement;
private Button _windowCloseButton;
private VisualElement _headerElement;
private Label _titleLabel;
// Events
public event Action OnClose;
public event Action OnOpen;
// References
private PlayerInputManager _playerInputManager;
private GameUI _gameUI;
// Toggle
private bool _isOpen;
private bool _isOverHeader;
private bool _isDragging;
// Offset - relative position from window position to cursor
private Vector2 _draggingOffset;
private void Awake()
{
var uiDocument = gameObject.GetComponent<UIDocument>();
var templateElement = uiDocument.rootVisualElement;
// Find all visual elements
_rootElement = templateElement.Q("root-window");
_parentElement = _rootElement.parent.parent;
_headerElement = _rootElement.Q("header");
_titleLabel = _headerElement.Q<Label>("title");
_windowCloseButton = _rootElement.Q<Button>("close");
// Close backpack when "x" pressed
_windowCloseButton.clicked += Close;
// Make window active if pressed
_parentElement.RegisterCallback(new EventCallback<MouseDownEvent>(_ => SetActiveWindow()), TrickleDown.TrickleDown);
}
private void Start()
{
_gameUI = GameUI.current;
_playerInputManager = PlayerInputManager.current;
_playerInputManager.OnDraggingPrepare += PrepareDragging;
_playerInputManager.OnDraggingStart += StartDragging;
_playerInputManager.OnDraggingEnd += EndDragging;
}
public void SetTitle(string title)
{
_titleLabel.text = title;
}
public void Toggle()
{
if (_isOpen)
{
Close();
}
else
{
Open();
}
}
public void Close()
{
// Hide element
_parentElement.style.display = DisplayStyle.None;
// Reset element position styles
_parentElement.style.right = StyleKeyword.Null;
_parentElement.style.top = StyleKeyword.Null;
_parentElement.style.bottom = StyleKeyword.Null;
_parentElement.style.left = StyleKeyword.Null;
_isOpen = false;
OnClose?.Invoke();
openWindows.Remove(this);
}
public void Open()
{
// Show Element
_parentElement.style.display = DisplayStyle.Flex;
_isOpen = true;
OnOpen?.Invoke();
openWindows.Add(this);
SetActiveWindow();
}
private void Update()
{
if (!_isDragging) return;
var mousePos = _gameUI.cursorPositionOnUI;
_parentElement.style.top = new StyleLength(mousePos.y - Mathf.Abs(_draggingOffset.y));
_parentElement.style.left = new StyleLength(mousePos.x - Mathf.Abs(_draggingOffset.x));
}
private void PrepareDragging()
{
// Check if dragging started at window's title header...
_isOverHeader = GameUI.current.elementsUnderCursor.Contains(_headerElement);
// ...Only dragging by TITLE element allows to drag whole window
if (!_isOverHeader) return;
// Calculate offset from mouse position to window position
var windowPos = new Vector2(_parentElement.worldBound.x,_parentElement.worldBound.y);
var mousePos = _gameUI.cursorPositionOnUI;
_draggingOffset = windowPos - mousePos;
}
private void StartDragging()
{
if (!_isOverHeader) return;
_isDragging = true;
_parentElement.style.right = new StyleLength(StyleKeyword.Auto);
_parentElement.style.bottom = new StyleLength(StyleKeyword.Auto);
}
public void EndDragging()
{
_isDragging = false;
_isOverHeader = false;
}
public void SetActiveWindow()
{
openWindows.Remove(this);
openWindows = openWindows.Prepend(this).ToList();
UpdateDocumentUIOrder();
}
/// <summary>
/// Calculating sorting order for all windows (in which order they will be rendered)
/// </summary>
public static void UpdateDocumentUIOrder()
{
openWindows.ForEach(window =>
{
var sortingOrder = openWindows.Count - openWindows.IndexOf(window);
window.GetComponent<UIDocument>().sortingOrder = sortingOrder;
});
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7739f7d2ddb54e68ba72bbd6d7d955df
timeCreated: 1693497508