5 using System.Collections.Generic;
 
    7 using SiliconStudio.Core;
 
    8 using SiliconStudio.Core.Diagnostics;
 
    9 using SiliconStudio.Core.Mathematics;
 
   10 using SiliconStudio.Paradox.Games;
 
   11 using SiliconStudio.Paradox.Graphics;
 
   12 using SiliconStudio.Paradox.Input;
 
   13 using SiliconStudio.Paradox.UI.Controls;
 
   15 namespace SiliconStudio.
Paradox.UI
 
   22         internal Matrix WorldMatrix;
 
   31             get { 
return rootElement;}
 
   36                 if(rootElement != null)
 
   41         internal Matrix ViewProjectionInternal;
 
   47         public Matrix ViewMatrix { 
get; 
private set; }
 
   53         public Matrix ProjectionMatrix { 
get; 
private set; }
 
   59         public Matrix ViewProjectionMatrix { 
get { 
return ViewProjectionInternal; } }
 
   63         internal UIBatch Batch { 
get; 
private set; }
 
   71         internal Vector2 BackBufferVirtualResolutionRatio { 
get; 
private set; }
 
   73         private Vector3 virtualResolution;
 
   77         private UIElement lastTouchedElement;
 
   78         private Vector3 lastIntersectionPoint;
 
   81         private readonly HashSet<UIElement> newlySelectedElementParents = 
new HashSet<UIElement>();
 
   83         private readonly List<PointerEvent> compactedPointerEvents = 
new List<PointerEvent>();
 
   87         private float uiFrustrumHeight;
 
   89         private Matrix inverseViewMatrix;
 
   94         private float viewPositionZ;
 
   96         private float nearPlane;
 
   98         private float farPlane;
 
  100         private Vector2 lastMousePosition;
 
  102         private UIElement lastOveredElement;
 
  107             Services.AddService(typeof(
UISystem), 
this);
 
  110             gameVirtualResolution.VirtualResolutionChanged += OnGameVirtualResolutionChanged;
 
  113         private void OnGameVirtualResolutionChanged(
object sender, 
EventArgs eventArgs)
 
  115             VirtualResolution = gameVirtualResolution.VirtualResolution;
 
  129             Game.Window.ClientSizeChanged += WindowOnClientSizeChanged;
 
  131             Game.Activated += OnApplicationResumed;
 
  132             Game.Deactivated += OnApplicationPaused;
 
  137             gameVirtualResolution.VirtualResolutionChanged -= OnGameVirtualResolutionChanged;
 
  139             Game.Activated -= OnApplicationResumed;
 
  140             Game.Deactivated -= OnApplicationPaused;
 
  143             OnApplicationPaused(
this, 
EventArgs.Empty);
 
  148         private void WindowOnClientSizeChanged(
object sender, 
EventArgs eventArgs)
 
  150             BackBufferVirtualResolutionRatio = CalculateBackBufferVirtualResolutionRatio();
 
  153         private Vector2 CalculateBackBufferVirtualResolutionRatio()
 
  168                     StencilEnable = 
true,
 
  171                         StencilDepthBufferFail = StencilOperation.Keep,
 
  172                         StencilFail = StencilOperation.Keep,
 
  173                         StencilPass = StencilOperation.Keep,
 
  174                         StencilFunction = CompareFunction.Equal
 
  177             KeepStencilValueState = DepthStencilState.New(
GraphicsDevice, depthStencilDescription);
 
  179             depthStencilDescription.FrontFace.StencilPass = StencilOperation.Increment;
 
  180             IncreaseStencilValueState = DepthStencilState.New(GraphicsDevice, depthStencilDescription);
 
  182             depthStencilDescription.FrontFace.StencilPass = StencilOperation.Decrement;
 
  183             DecreaseStencilValueState = DepthStencilState.New(GraphicsDevice, depthStencilDescription);
 
  186             var designsTexture = TextureExtensions.CreateTextureFromFileData(GraphicsDevice, DefaultDesigns.Designs);
 
  187             Button.PressedImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default button pressed design", designsTexture) { Borders = 8 * Vector4.One, Region = 
new RectangleF(71, 3, 32, 32)});
 
  188             Button.NotPressedImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default button not pressed design", designsTexture) { Borders = 8 * Vector4.One, Region = 
new RectangleF(3, 3, 32, 32) });
 
  189             Button.MouseOverImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default button overred design", designsTexture) { Borders = 8 * Vector4.One, Region = 
new RectangleF(37, 3, 32, 32) });
 
  190             EditText.ActiveImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default edit active design", designsTexture) { Borders = 12 * Vector4.One, Region = 
new RectangleF(105, 3, 32, 32) });
 
  191             EditText.InactiveImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default edit inactive design", designsTexture) { Borders = 12 * Vector4.One, Region = 
new RectangleF(139, 3, 32, 32) });
 
  192             EditText.MouseOverImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default edit overred design", designsTexture) { Borders = 12 * Vector4.One, Region = 
new RectangleF(173, 3, 32, 32) });
 
  193             ToggleButton.CheckedImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default toggle button checked design", designsTexture) { Borders = 8 * Vector4.One, Region = 
new RectangleF(71, 3, 32, 32) });
 
  194             ToggleButton.UncheckedImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default toggle button unchecked design", designsTexture) { Borders = 8 * Vector4.One, Region = 
new RectangleF(3, 3, 32, 32) });
 
  195             ToggleButton.IndeterminateImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default toggle button indeterminate design", designsTexture) { Borders = 8 * Vector4.One, Region = 
new RectangleF(37, 3, 32, 32) });
 
  196             Slider.TrackBackgroundImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default slider track background design", designsTexture) { Borders = 14 * Vector4.One, Region = 
new RectangleF(207, 3, 32, 32) });
 
  197             Slider.TrackForegroundImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default slider track foreground design", designsTexture) { Borders = 0 * Vector4.One, Region = 
new RectangleF(3, 37, 32, 32) });
 
  198             Slider.ThumbImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default slider thumb design", designsTexture) { Borders = 4 * Vector4.One, Region = 
new RectangleF(37, 37, 16, 32) });
 
  199             Slider.MouseOverThumbImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default slider thumb overred design", designsTexture) { Borders = 4 * Vector4.One, Region = 
new RectangleF(71, 37, 16, 32) });
 
  200             Slider.TickImagePropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new UIImage(
"Default slider track foreground design", designsTexture) { Region = 
new RectangleF(245, 3, 3, 6) });
 
  201             Slider.TickOffsetPropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(13f);
 
  202             Slider.TrackStartingOffsetsrPropertyKey.DefaultValueMetadata = DefaultValueMetadata.Static(
new Vector2(3));
 
  208         void OnApplicationPaused(
object sender, 
EventArgs e)
 
  211             var focusedEdit = UIElement.FocusedElement as 
EditText;
 
  212             if (focusedEdit != null)
 
  213                 focusedEdit.IsSelectionActive = 
false;
 
  219         void OnApplicationResumed(
object sender, 
EventArgs e)
 
  235         internal Vector3 VirtualResolution
 
  239                 return virtualResolution;
 
  244                     throw new InvalidOperationException(
"The resolution along the X axis is not valid. [Value=" + value.X + 
"]");
 
  246                     throw new InvalidOperationException(
"The resolution along the Y axis is not valid. [Value=" + value.Y + 
"]");
 
  248                     throw new InvalidOperationException(
"The resolution along the Z axis is not valid. [Value=" + value.Z + 
"]");
 
  250                 if(virtualResolution == value)
 
  253                 virtualResolution = value;
 
  255                 var uiFieldOfView = (float)Math.Atan2(virtualResolution.Y / 2, virtualResolution.Z + 1f) * 2;
 
  256                 uiFrustrumHeight = 2 * (float)Math.Tan(uiFieldOfView / 2);
 
  259                 farPlane = 1f + 2 * virtualResolution.Z;
 
  260                 var projection = Matrix.PerspectiveFovRH(uiFieldOfView, virtualResolution.X / virtualResolution.Y, nearPlane, farPlane);
 
  261                 projection.M22 = -projection.M22;
 
  263                 ProjectionMatrix = projection;
 
  264                 viewPositionZ = virtualResolution.Z + 1f;
 
  265                 ViewMatrix = Matrix.LookAtRH(
new Vector3(0, 0, viewPositionZ), Vector3.Zero, Vector3.UnitY);
 
  266                 inverseViewMatrix = Matrix.Invert(ViewMatrix);
 
  267                 ViewProjectionInternal = ViewMatrix * ProjectionMatrix;
 
  268                 WorldMatrix = Matrix.Translation(-VirtualResolution.X / 2, -VirtualResolution.Y / 2, 0);
 
  269                 BackBufferVirtualResolutionRatio = CalculateBackBufferVirtualResolutionRatio();
 
  271                 var handler = ResolutionChanged;
 
  279             base.Update(gameTime);
 
  281             if (RootElement == null) 
 
  286             using (var profiler = Profiler.Begin(UIProfilerKeys.TouchEventsUpdate))
 
  289                 UpdateTouchEvents(gameTime);
 
  294         private void UpdateKeyEvents()
 
  296             foreach (var keyEvent 
in input.KeyEvents)
 
  299                 var key = keyEvent.Key;
 
  302                     UIElement.FocusedElement.RaiseKeyPressedEvent(
new KeyEventArgs { Key = key, Input = input });
 
  306                     UIElement.FocusedElement.RaiseKeyReleasedEvent(
new KeyEventArgs { Key = key, Input = input });
 
  310             foreach (var key 
in input.KeyDown)
 
  312                 if (UIElement.FocusedElement == null || !UIElement.FocusedElement.IsHierarchyEnabled) 
return;
 
  313                 UIElement.FocusedElement.RaiseKeyDownEvent(
new KeyEventArgs { Key = key, Input = input });
 
  317         private void UpdateMouseOver()
 
  322             var intersectionPoint = Vector3.Zero;
 
  323             var mousePosition = input.MousePosition;
 
  324             var overredElement = lastOveredElement;
 
  327             if(mousePosition != lastMousePosition)
 
  328                 overredElement = GetElementFromPointerScreenPosition(mousePosition, ref intersectionPoint);
 
  331             var commonElement = FindCommonParent(overredElement, lastOveredElement);
 
  334             var parent = lastOveredElement;
 
  335             while (parent != commonElement && parent != null)
 
  337                 parent.MouseOverState = MouseOverState.MouseOverNone;
 
  338                 parent = parent.VisualParent;
 
  342             if(overredElement != null)
 
  345                 overredElement.MouseOverState = MouseOverState.MouseOverElement;
 
  348                 parent = overredElement.VisualParent;
 
  349                 while (parent != null)
 
  351                     if (parent.IsHierarchyEnabled)
 
  352                         parent.MouseOverState = MouseOverState.MouseOverChild;
 
  354                     parent = parent.VisualParent;
 
  359             lastOveredElement = overredElement;
 
  360             lastMousePosition = mousePosition;
 
  363         private void UpdateTouchEvents(
GameTime gameTime)
 
  366             var aggregatedTranslation = Vector2.Zero;
 
  367             for (var index = 0; index < input.PointerEvents.Count; ++index)
 
  369                 var pointerEvent = input.PointerEvents[index];
 
  373                     aggregatedTranslation = Vector2.Zero;
 
  374                     compactedPointerEvents.Add(pointerEvent.Clone());
 
  378                 aggregatedTranslation += pointerEvent.DeltaPosition;
 
  380                 if (index + 1 >= input.PointerEvents.Count || input.PointerEvents[index + 1].State != 
PointerState.Move)
 
  382                     var compactedMoveEvent = pointerEvent.Clone();
 
  383                     compactedMoveEvent.DeltaPosition = aggregatedTranslation;
 
  384                     compactedPointerEvents.Add(compactedMoveEvent);
 
  388             var intersectionPoint = Vector3.Zero;
 
  389             var lastTouchPosition = 
new Vector2(
float.NegativeInfinity);
 
  392             foreach (var pointerEvent 
in compactedPointerEvents)
 
  395                 if(lastTouchedElement == null && pointerEvent.State != 
PointerState.Down)
 
  398                 var time = gameTime.Total;
 
  399                 var currentTouchPosition = pointerEvent.Position;
 
  400                 var currentTouchedElement = lastTouchedElement;
 
  403                 if (lastTouchPosition != currentTouchPosition)
 
  404                     currentTouchedElement = GetElementFromPointerScreenPosition(currentTouchPosition, ref intersectionPoint);
 
  407                     lastIntersectionPoint = intersectionPoint;
 
  409                 var touchEvent = 
new TouchEventArgs
 
  411                     Action = TouchAction.Down, 
 
  413                     ScreenPosition = currentTouchPosition, 
 
  414                     ScreenTranslation = pointerEvent.DeltaPosition,
 
  415                     WorldPosition = intersectionPoint,
 
  416                     WorldTranslation = intersectionPoint - lastIntersectionPoint
 
  419                 switch (pointerEvent.State)
 
  421                     case PointerState.Down:
 
  422                         touchEvent.Action = TouchAction.Down;
 
  423                         if (currentTouchedElement != null)
 
  424                             currentTouchedElement.RaiseTouchDownEvent(touchEvent);
 
  427                     case PointerState.Up:
 
  428                         touchEvent.Action = TouchAction.Up;
 
  431                         if (currentTouchedElement != lastTouchedElement)
 
  432                             ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent);
 
  435                         if (currentTouchedElement != null)
 
  436                             currentTouchedElement.RaiseTouchUpEvent(touchEvent);
 
  439                     case PointerState.Move:
 
  440                         touchEvent.Action = TouchAction.Move;
 
  443                         if (currentTouchedElement != null)
 
  444                             currentTouchedElement.RaiseTouchMoveEvent(touchEvent);
 
  447                         if (currentTouchedElement != lastTouchedElement)
 
  448                             ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent);
 
  451                     case PointerState.Out:
 
  452                     case PointerState.Cancel:
 
  453                         touchEvent.Action = TouchAction.Move;
 
  456                         if (currentTouchedElement != lastTouchedElement)
 
  457                             ThrowEnterAndLeaveTouchEvents(currentTouchedElement, lastTouchedElement, touchEvent);
 
  460                         var element = currentTouchedElement;
 
  461                         while (element != null)
 
  463                             if(element.IsTouched)
 
  464                                 element.RaiseTouchLeaveEvent(touchEvent);
 
  465                             element = element.VisualParent;
 
  469                         throw new ArgumentOutOfRangeException();
 
  472                 lastTouchedElement = currentTouchedElement;
 
  473                 lastTouchPosition = currentTouchPosition;
 
  474                 lastIntersectionPoint = intersectionPoint;
 
  480                 foreach (var pointerEvent 
in compactedPointerEvents)
 
  481                     PointerEvent.Pool.Enqueue(pointerEvent);
 
  483             compactedPointerEvents.Clear();
 
  486         private UIElement FindCommonParent(UIElement element1, UIElement element2)
 
  489             newlySelectedElementParents.Clear();
 
  490             var newElementParent = element1;
 
  491             while (newElementParent != null)
 
  493                 newlySelectedElementParents.Add(newElementParent);
 
  494                 newElementParent = newElementParent.VisualParent;
 
  498             var commonElement = element2;
 
  499             while (commonElement != null && !newlySelectedElementParents.Contains(commonElement))
 
  500                 commonElement = commonElement.VisualParent;
 
  502             return commonElement;
 
  505         private void ThrowEnterAndLeaveTouchEvents(UIElement currentElement, UIElement previousElement, TouchEventArgs touchEvent)
 
  507             var commonElement = FindCommonParent(currentElement, previousElement);
 
  510             var previousElementParent = previousElement;
 
  511             while (previousElementParent != commonElement && previousElementParent != null)
 
  513                 if (previousElementParent.IsHierarchyEnabled && previousElementParent.IsTouched)
 
  515                     touchEvent.Handled = 
false; 
 
  516                     previousElementParent.RaiseTouchLeaveEvent(touchEvent);
 
  518                 previousElementParent = previousElementParent.VisualParent;
 
  522             var newElementParent = currentElement;
 
  523             while (newElementParent != commonElement && newElementParent != null)
 
  525                 if (newElementParent.IsHierarchyEnabled && !newElementParent.IsTouched)
 
  527                     touchEvent.Handled = 
false; 
 
  528                     newElementParent.RaiseTouchEnterEvent(touchEvent);
 
  530                 newElementParent = newElementParent.VisualParent;
 
  533         private UIElement GetElementFromPointerScreenPosition(
Vector2 position, ref 
Vector3 intersectionPoint)
 
  536             var touchPosition = position - 
new Vector2(0.5f);
 
  537             var rayDirectionView = Vector3.Normalize(
new Vector3(touchPosition.X * uiFrustrumHeight * virtualResolution.X / virtualResolution.Y, touchPosition.Y * uiFrustrumHeight, -1));
 
  538             var clickRay = 
new Ray(inverseViewMatrix.TranslationVector, 
Vector3.
TransformNormal(rayDirectionView, inverseViewMatrix));
 
  541             UIElement clickedElement = null;
 
  542             var smallestDepth = float.PositiveInfinity;
 
  543             PerformRecursiveHitTest(rootElement, ref clickRay, ref clickedElement, ref intersectionPoint, ref smallestDepth);
 
  545             return clickedElement;
 
  548         private void PerformRecursiveHitTest(UIElement element, ref 
Ray ray, ref UIElement clickedElement, ref 
Vector3 intersectionPoint, ref 
float smallestDepth)
 
  551             if (!element.IsVisible)
 
  554             if (element.ClipToBounds || element.CanBeHitByUser)
 
  557                 var intersect = element.Intersects(ref ray, out intersection);
 
  560                 if (element.ClipToBounds && !intersect)
 
  564                 var depthInView = (intersection.Z - viewPositionZ);
 
  565                 var depthWithBias = (nearPlane * farPlane) / depthInView / (farPlane - nearPlane) - element.DepthBias * BatchBase<int>.DepthBiasShiftOneUnit;
 
  568                 if (element.CanBeHitByUser && intersect && depthWithBias < smallestDepth)
 
  570                     smallestDepth = depthWithBias;
 
  571                     intersectionPoint = intersection;
 
  572                     clickedElement = element;
 
  577             foreach (var child 
in element.HitableChildren)
 
  578                 PerformRecursiveHitTest(child, ref ray, ref clickedElement, ref intersectionPoint, ref smallestDepth);
 
Provides a base class for all the User Interface elements in Paradox applications. 
 
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
 
bool IsHierarchyEnabled
Gets the value indicating whether this element and all its upper hierarchy are enabled or not...
 
Represents a two dimensional mathematical vector. 
 
EventHandler< EventArgs > ResolutionChanged
 
Contains depth-stencil state for the device. 
 
Interface providing services to deal with the virtual resolution of the game. The virtual resolution ...
 
Interface for the update of the UIElements. 
 
RenderTarget BackBuffer
Gets the back buffer sets by the current Presenter setup on this device. 
 
A utility class to batch and draw UI images. 
 
Represents a three dimensional mathematical vector. 
 
A service registry is a IServiceProvider that provides methods to register and unregister services...
 
override void Destroy()
Disposes of object resources. 
 
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class. 
 
Base class for a GameSystemBase component. 
 
static void TransformNormal(ref Vector3 normal, ref Matrix transform, out Vector3 result)
Performs a normal transformation using the given SiliconStudio.Core.Mathematics.Matrix. 
 
override void LoadContent()
Loads the assets. 
 
int Width
Gets the width in texel. 
 
Current timing used for variable-step (real time) or fixed-step (game time) games. 
 
Represents a three dimensional line based on a point in space and a direction. 
 
Interface of the UI system. 
 
int Height
Gets the height in texel. 
 
override void Update(GameTime gameTime)
This method is called when this game component is updated. 
 
Describes a depth stencil state. 
 
SiliconStudio.Core.Mathematics.Vector3 Vector3
 
Class holding all the data required to define an UI image. 
 
override void Initialize()
This method is called when the component is added to the game. 
 
SiliconStudio.Core.Mathematics.RectangleF RectangleF
 
UISystem(IServiceRegistry registry)
 
Represent an edit text where the user can enter text. 
 
Represents a 4x4 mathematical matrix.