Skip to content

Commit

Permalink
[Windows] Support for dynamic action buttons
Browse files Browse the repository at this point in the history
- Windows: action buttons can now be added or removed at runtime. When
there are more buttons than available space, an extra button is added to
display action buttons which can't be hold by action bar.
- User can choose some behaviors related with user interactions and
more actions button.
- Added a new button + icon prefab.
- Unification of button definitons for both windows and hand menu.
- Button factory: extended to support explicit base prefabs on button
creation.
- Reduced number of involved colliders for look and feel animations for
buttons.
- Redesigned Windows sample scene to show built-in window capabilities.
  • Loading branch information
sescalada committed Mar 13, 2024
1 parent 4936b5d commit 6c32706
Show file tree
Hide file tree
Showing 50 changed files with 3,987 additions and 2,222 deletions.
1,549 changes: 1,547 additions & 2 deletions samples/Content/Scenes/Windows.wescene

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions samples/XrvSamples/Scenes/HandMenuScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using Evergine.Xrv.Core;
using Evergine.Xrv.Core.Menu;
using Evergine.Xrv.Core.UI.Buttons;

namespace XrvSamples.Scenes
{
Expand Down Expand Up @@ -94,7 +95,7 @@ private void IncreaseNumberOfButtons_ButtonReleased(object sender, EventArgs e)

private void DecreaseNumberOfButtons_ButtonReleased(object sender, EventArgs e)
{
if (this.handMenu.ButtonDescriptions.LastOrDefault() is MenuButtonDescription definition)
if (this.handMenu.ButtonDescriptions.LastOrDefault() is ButtonDescription definition)
{
this.handMenu.ButtonDescriptions.Remove(definition);
this.UpdateCounts();
Expand All @@ -104,7 +105,7 @@ private void DecreaseNumberOfButtons_ButtonReleased(object sender, EventArgs e)
private void AddButton()
{
bool isToggle = DateTime.Now.Millisecond % 2 == 0;
this.handMenu.ButtonDescriptions.Add(new MenuButtonDescription
this.handMenu.ButtonDescriptions.Add(new ButtonDescription
{
IsToggle = isToggle,
TextOn = () => $"{(isToggle ? "T_" : string.Empty)}{DateTime.Now.Millisecond}",
Expand Down
163 changes: 163 additions & 0 deletions samples/XrvSamples/Scenes/WindowScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
using Evergine.Xrv.Core.UI.Windows;
using System.Threading.Tasks;
using Evergine.Framework.Prefabs;
using System.Collections.Generic;
using Evergine.Xrv.Core.UI.Buttons;
using Evergine.Framework.Threading;
using Evergine.MRTK.SDK.Features.UX.Components.ToggleButtons;

namespace XrvSamples.Scenes
{
Expand Down Expand Up @@ -38,6 +42,21 @@ public class WindowScene : BaseScene
private PressableButton customTitleButton;
private PressableButton customTitleDialogButton;

private Window actionButtonsWindow;
private PressableButton actionButtonsShowWindowButton;
private List<ButtonDescription> actionButtonsDescriptors;
private PressableButton actionButtonsLessActionsButton;
private PressableButton actionButtonsMoreActionsButton;
private PressableButton actionButtonsLessSlotsButton;
private PressableButton actionButtonsMoreSlotsButton;
private Text3DMesh actionButtonActionsCountText;
private Text3DMesh actionButtonSlotsCountText;
private Text3DMesh actionButtonsCallbackText;
private ToggleButton actionButtonsCloseToggle;
private PressableButton actionButtonsToggleChange;
private ToggleButton actionButtonsTogglePlacement;
private ToggleButton actionButtonsToggleBehavior;

protected override void OnPostCreateXRScene()
{
this.xrv = Application.Current.Container.Resolve<XrvService>();
Expand Down Expand Up @@ -119,6 +138,50 @@ protected override void OnPostCreateXRScene()
this.customTitleButton.ButtonPressed += this.CustomTitleButton_ButtonPressed;
this.customTitleDialogButton = entityManager.FindAllByTag("customTitleDialogButton").First().FindComponentInChildren<PressableButton>();
this.customTitleDialogButton.ButtonPressed += this.CustomTitleDialogButton_ButtonPressed;

// Action buttons
this.actionButtonsWindow = this.windowsSystem.CreateWindow(configurator =>
{
configurator.Content = this.CreateText3D(
"Here the window contents",
new Vector2(0.3f, 0.2f),
new Vector3(0.01f, -0.01f, 0f));
});
this.actionButtonsShowWindowButton = entityManager.FindAllByTag("actionButtonsShowButton").First().FindComponentInChildren<PressableButton>();
this.actionButtonsShowWindowButton.ButtonPressed += this.ActionButtonsShowWindowButton_ButtonPressed;
this.actionButtonsDescriptors = new List<ButtonDescription>();
this.actionButtonsLessActionsButton = entityManager.FindAllByTag("actionButtonsLessActionsButton").First().FindComponentInChildren<PressableButton>();
this.actionButtonsLessActionsButton.ButtonPressed += this.ActionButtonsLessActionsButton_ButtonPressed;
this.actionButtonsMoreActionsButton = entityManager.FindAllByTag("actionButtonsMoreActionsButton").First().FindComponentInChildren<PressableButton>();
this.actionButtonsMoreActionsButton.ButtonPressed += this.ActionButtonsMoreActionsButton_ButtonPressed;
this.actionButtonsLessSlotsButton = entityManager.FindAllByTag("actionButtonsLessSlotsButton").First().FindComponentInChildren<PressableButton>();
this.actionButtonsLessSlotsButton.ButtonPressed += this.ActionButtonsLessSlotsButton_ButtonPressed;
this.actionButtonsMoreSlotsButton = entityManager.FindAllByTag("actionButtonsMoreSlotsButton").First().FindComponentInChildren<PressableButton>();
this.actionButtonsMoreSlotsButton.ButtonPressed += this.ActionButtonsMoreSlotsButton_ButtonPressed;

this.actionButtonActionsCountText = entityManager.FindAllByTag("actionButtonActionsCountText").First().FindComponentInChildren<Text3DMesh>();
this.actionButtonSlotsCountText = entityManager.FindAllByTag("actionButtonsSlotsCountText").First().FindComponentInChildren<Text3DMesh>();
this.actionButtonsCallbackText = entityManager.FindAllByTag("actionButtonsCallbackText").First().FindComponentInChildren<Text3DMesh>();
this.actionButtonsCloseToggle = entityManager.FindAllByTag("actionButtonsToggleClose").First().FindComponentInChildren<ToggleButton>();
this.actionButtonsCloseToggle.Toggled += this.ActionButtonsCloseToggle_Toggled;

this.actionButtonsToggleChange = entityManager.FindAllByTag("actionButtonsToggleChange").First().FindComponentInChildren<PressableButton>();
this.actionButtonsToggleChange.ButtonPressed += this.ActionButtonsToggleChange_ButtonPressed;

this.actionButtonsTogglePlacement = entityManager.FindAllByTag("actionButtonsTogglePlacement").First().FindComponentInChildren<ToggleButton>();
this.actionButtonsTogglePlacement.Toggled += this.ActionButtonsTogglePlacement_Toggled;

this.actionButtonsToggleBehavior = entityManager.FindAllByTag("actionButtonsToggleMoreBehavior").First().FindComponentInChildren<ToggleButton>();
this.actionButtonsToggleBehavior.Toggled += this.ActionButtonsToggleBehavior_Toggled;

this.actionButtonsWindow.ActionButtonPressed += this.ActionButtonsWindow_ActionButtonPressed;

EvergineForegroundTask.Run(() =>
{
this.AddSampleActionButton();
this.AddSampleActionButton();
this.UpdateActionButtonCounters();
});
}

private void CreateAlert_ButtonReleased(object sender, EventArgs e)
Expand Down Expand Up @@ -270,5 +333,105 @@ private void CustomTitleDialogButton_Closed(object sender, EventArgs e)
alertDialog.Closed -= this.CustomTitleDialogButton_Closed;
}
}

private void AddSampleActionButton(bool isToggleSample = false)
{
var number = this.actionButtonsDescriptors.Count + 1;
var descriptor = new ButtonDescription
{
TextOn = () => $"Option {number}",
IconOn = EvergineContent.Materials.Icons.Pi,
Name = $"Option {number}",
};

if (isToggleSample)
{
descriptor.IsToggle = true;
descriptor.TextOff = () => $"#Off {number}";
descriptor.IconOff = EvergineContent.Materials.Icons.cross;
}

this.actionButtonsDescriptors.Add(descriptor);
this.actionButtonsWindow.ExtraActionButtons.Add(descriptor);
this.UpdateActionButtonCounters();

if (isToggleSample)
{
Entity buttonEntity = this.actionButtonsWindow.GetActionButtonEntity(descriptor);
buttonEntity.AddComponent(new AutomaticToggleChange());
}
}

private void ActionButtonsWindow_ActionButtonPressed(object sender, ActionButtonPressedEventArgs args)
{
this.actionButtonsCallbackText.Text = $"{(args.IsOn ? args.Description.TextOn() : args.Description.TextOff())} callback executed";
}

private void UpdateActionButtonCounters()
{
this.actionButtonActionsCountText.Text = this.actionButtonsWindow.ExtraActionButtons.Count.ToString();
this.actionButtonSlotsCountText.Text = this.actionButtonsWindow.AvailableActionSlots.ToString();
}

private void ActionButtonsShowWindowButton_ButtonPressed(object sender, EventArgs e) => this.actionButtonsWindow.Open();

private void ActionButtonsLessActionsButton_ButtonPressed(object sender, EventArgs e)
{
if (this.actionButtonsDescriptors.Any())
{
var descriptor = this.actionButtonsDescriptors.Last();
this.actionButtonsDescriptors.Remove(descriptor);
this.actionButtonsWindow.ExtraActionButtons.Remove(descriptor);
}

this.UpdateActionButtonCounters();
}

private void ActionButtonsMoreActionsButton_ButtonPressed(object sender, EventArgs e) => this.AddSampleActionButton();


private void ActionButtonsToggleChange_ButtonPressed(object sender, EventArgs e) => this.AddSampleActionButton(true);

private void ActionButtonsMoreSlotsButton_ButtonPressed(object sender, EventArgs e)
{
this.actionButtonsWindow.AvailableActionSlots++;
this.UpdateActionButtonCounters();
}

private void ActionButtonsLessSlotsButton_ButtonPressed(object sender, EventArgs e)
{
this.actionButtonsWindow.AvailableActionSlots = Math.Max(2, this.actionButtonsWindow.AvailableActionSlots - 1);
this.UpdateActionButtonCounters();
}

private void ActionButtonsCloseToggle_Toggled(object sender, EventArgs e) =>
this.actionButtonsWindow.ShowCloseButton = !this.actionButtonsWindow.ShowCloseButton;

private void ActionButtonsTogglePlacement_Toggled(object sender, EventArgs e) =>
this.actionButtonsWindow.MoreActionsPlacement = this.actionButtonsTogglePlacement.IsOn
? MoreActionsButtonPlacement.BeforeFollowAndClose : MoreActionsButtonPlacement.BeforeActionButtons;

private void ActionButtonsToggleBehavior_Toggled(object sender, EventArgs e) =>
this.actionButtonsWindow.MoreActionsBehavior = this.actionButtonsToggleBehavior.IsOn
? MoreActionsPanelBehavior.HideAutomatically : MoreActionsPanelBehavior.StayOpen;

private class AutomaticToggleChange : Behavior
{
private readonly TimeSpan toggleTime = TimeSpan.FromSeconds(2);
private TimeSpan currentTime;

[BindComponent(source: BindComponentSource.Children)]
private ToggleStateManager stateManager = null;

protected override void Update(TimeSpan gameTime)
{
if ((this.currentTime += gameTime) >= this.toggleTime)
{
this.stateManager.ChangeState(this.stateManager.CurrentState.Value == ToggleState.On
? this.stateManager.States.ElementAt(0) : this.stateManager.States.ElementAt(1));
this.currentTime = TimeSpan.Zero;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
!Evergine.Assets.Exporters.MaterialMetaFile,Evergine.Assets
Id: dd562e05-03e6-45f5-b79e-d32b8bd8f9e7
DefaultProfile:
ExcludeAsset: false
Name: null
Platform: Undefined
ExportAsRaw: false
MaterialInfo:
Id: c4c0b49f-dce4-4680-a6f7-12af593c608b
ActiveDirectives:
- ALBEDO_MAP
- ALPHABLEND
AllowInstancing: false
EffectID: 4f7e4c24-e83c-4350-9cd4-511fb2199cf4
Layer: e35c59a9-26ab-4b4c-8210-4b1f21c31530
OrderBias: 0
Parameters:
- Name: WorldViewProj
Type: Evergine.Mathematics.Matrix4x4,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
- Name: World
Type: Evergine.Mathematics.Matrix4x4,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
- Name: EyePosition
Type: Evergine.Mathematics.Vector3,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAA
- Name: EyeCount
Type: System.Int32
ValueByteArray: AAAAAA==
- Name: MultiviewViewProj
Type: Evergine.Mathematics.Matrix4x4,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
- Name: SunDirection
Type: Evergine.Mathematics.Vector3,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAA
- Name: SunColor
Type: Evergine.Mathematics.Vector3,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAA
- Name: HoverLightData
Type: Evergine.Mathematics.Vector4,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAAAAAAAA==
- Name: ProximityLightData
Type: Evergine.Mathematics.Vector4,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAAAAAAAAAAAAA==
- Name: Color
Type: Evergine.Mathematics.Vector3,Evergine.Mathematics
ValueByteArray: AACAPwAAgD8AAIA/
- Name: Alpha
Type: System.Single
ValueByteArray: AACAPw==
- Name: InnerGlowColor
Type: Evergine.Mathematics.Vector3,Evergine.Mathematics
ValueByteArray: AACAPwAAgD8AAIA/
- Name: InnerGlowAlpha
Type: System.Single
ValueByteArray: AABAPw==
- Name: InnerGlowPower
Type: System.Single
ValueByteArray: AACAQA==
- Name: BorderWidth
Type: System.Single
ValueByteArray: zczMPQ==
- Name: BorderMinValue
Type: System.Single
ValueByteArray: zczMPQ==
- Name: FluentLightIntensity
Type: System.Single
ValueByteArray: AACAPw==
- Name: RoundCornerRadious
Type: System.Single
ValueByteArray: AACAPg==
- Name: RoundCornerMargin
Type: System.Single
ValueByteArray: CtcjPA==
- Name: Cutoff
Type: System.Single
ValueByteArray: AAAAPw==
- Name: EdgeSmoothingValue
Type: System.Single
ValueByteArray: bxIDOw==
- Name: RoundCornersRadious
Type: Evergine.Mathematics.Vector4,Evergine.Mathematics
ValueByteArray: AAAAPwAAAD8AAAA/AAAAPw==
- Name: FadeBeginDistance
Type: System.Single
ValueByteArray: CtcjPA==
- Name: FadeCompleteDistance
Type: System.Single
ValueByteArray: zczMPQ==
- Name: FadeMinValue
Type: System.Single
ValueByteArray: AAAAAA==
- Name: HoverColorOverride
Type: Evergine.Mathematics.Vector3,Evergine.Mathematics
ValueByteArray: 61gxPetYMT3rWDE9
- Name: ProximityLightCenterColorOverride
Type: Evergine.Mathematics.Vector4,Evergine.Mathematics
ValueByteArray: DjQEPflsiT753nQ/AAAAAA==
- Name: ProximityLightMiddleColorOverride
Type: Evergine.Mathematics.Vector4,Evergine.Mathematics
ValueByteArray: P1y8PN/IaD4AAIA/zcxMPg==
- Name: ProximityLightOuterColorOverride
Type: Evergine.Mathematics.Vector4,Evergine.Mathematics
ValueByteArray: b/qmPctjGjwe/gM/AACAPw==
- Name: Metallic
Type: System.Single
ValueByteArray: AAAAAA==
- Name: Smoothness
Type: System.Single
ValueByteArray: AAAAPw==
- Name: Tiling
Type: Evergine.Mathematics.Vector2,Evergine.Mathematics
ValueByteArray: AACAPwAAgD8=
- Name: Offset
Type: Evergine.Mathematics.Vector2,Evergine.Mathematics
ValueByteArray: AAAAAAAAAAA=
- Name: IridescenceIntensity
Type: System.Single
ValueByteArray: AAAAPw==
- Name: IridescenceThreshold
Type: System.Single
ValueByteArray: zcxMPQ==
- Name: IridescenceAngle
Type: System.Single
ValueByteArray: FK5Hvw==
Samplers:
- ID: a6f09f12-0f97-4b8e-a872-3f8dbe5bd249
Name: Sampler
- ID: 00000000-0000-0000-0000-000000000000
Name: null
Textures:
- ID: 5f17586c-7492-48c2-8f6f-7a3068c9773e
Name: Texture
- ID: 00000000-0000-0000-0000-000000000000
Name: null
Profiles: {}
Loading

0 comments on commit 6c32706

Please sign in to comment.