/// <summary> /// Determine the actual plane matrix from the selected plane of this behavior /// </summary> /// <param name="element"></param> /// <returns></returns> protected Matrix4x4 GetUsedPlane(NotuiElement element) { ActualPlaneSelection = UseSelectedPlane == SelectedPlane.ParentPlane ? (element.Parent != null ? SelectedPlane.ParentPlane : SelectedPlane.ViewAligned) : UseSelectedPlane; Matrix4x4 usedplane; switch (ActualPlaneSelection) { case SelectedPlane.ParentPlane: usedplane = element.Parent.DisplayMatrix; break; case SelectedPlane.OwnPlane: usedplane = element.DisplayMatrix; break; case SelectedPlane.ViewAligned: usedplane = Matrix4x4.CreateFromQuaternion(element.Context.ViewOrientation) * Matrix4x4.CreateTranslation(element.DisplayMatrix.Translation); break; default: usedplane = Matrix4x4.CreateFromQuaternion(element.Context.ViewOrientation) * Matrix4x4.CreateTranslation(element.DisplayMatrix.Translation); break; } return(usedplane); }
public VEnvironmentData(NotuiElement element) { _element = element; TypeCSharpName = element.GetType().GetCSharpName(); element.OnMainLoopEnd += (sender, args) => { Touches.AssignFrom(_element.Touching.Keys); TouchesHitting.AssignFrom(_element.Touching.Values.Select(t => t != null)); TouchingIntersections.AssignFrom(_element.Touching.Values.Where(t => t != null)); HittingTouches.AssignFrom(_element.Hitting.Keys); HittingIntersections.AssignFrom(_element.Hitting.Values); Mice.AssignFrom(_element.Mice.Select(t => t.AttachadMouse)); Children.AssignFrom(_element.Children.Values); Behaviors.AssignFrom(_element.Behaviors); if (_element.Parent == null) { Parent.SliceCount = 0; } else { Parent.SliceCount = 1; Parent[0] = element.Parent; } VDispTr = _element.DisplayMatrix.AsVMatrix4X4(); }; }
/// <inheritdoc cref="ElementPrototype"/> public override void UpdateFrom(NotuiElement other) { base.UpdateFrom(other); if (other is PolygonElement element) { Vertices = element.Vertices.ToList(); } }
/// <inheritdoc cref="NotuiElement"/> public PolygonElement(ElementPrototype prototype, NotuiContext context, NotuiElement parent = null) : base(prototype, context, parent) { if (prototype is PolygonElementPrototype prot) { Vertices = prot.Vertices.ToList(); } }
/// <inheritdoc cref="NotuiElement"/> public BoxElement(ElementPrototype prototype, NotuiContext context, NotuiElement parent = null) : base(prototype, context, parent) { if (prototype is BoxElementPrototype prot) { Size = prot.Size; } }
private void RecursiveInteracted(NotuiElement element) { element.OnTouchBegin += (sender, args) => Interacted = true; foreach (var child in element.Children.Values) { RecursiveInteracted(child); } }
/// <inheritdoc cref="ElementPrototype"/> public override void UpdateFrom(NotuiElement other) { base.UpdateFrom(other); if (other is BoxElement element) { Size = element.Size; } }
/// <summary> /// Recursive function which adds touches interacting with the children to this behavior /// </summary> /// <param name="element"></param> /// <param name="touches"></param> /// <param name="touchsrc"></param> protected void AddChildrenTouches(NotuiElement element, List <Touch> touches, InteractingTouchSource touchsrc = InteractingTouchSource.Touching) { foreach (var child in element.Children.Values) { touches.AddRange(GetTouchesFromSource(child, touchsrc)); AddChildrenTouches(child, touches, touchsrc); } }
/// <inheritdoc cref="NotuiElement"/> public SegmentElement(ElementPrototype prototype, NotuiContext context, NotuiElement parent = null) : base(prototype, context, parent) { if (prototype is SegmentElementPrototype seprot) { HoleRadius = seprot.HoleRadius; Cycles = seprot.Cycles; Phase = seprot.Phase; } }
/// <inheritdoc cref="ElementPrototype"/> public override void UpdateFrom(NotuiElement other) { base.UpdateFrom(other); if (other is SegmentElement element) { HoleRadius = element.HoleRadius; Cycles = element.Cycles; Phase = element.Phase; } }
private void Move(NotuiElement element, BehaviorState state, Matrix4x4 usedplane) { var disptr = element.DisplayTransformation; var worldvel = Vector4.Transform(new Vector4(state.DeltaPos * Coeffitient * 0.5f, 0, 0), usedplane).xyz(); if (element.Parent != null) { Matrix4x4.Invert(element.Parent.DisplayMatrix, out var invparenttr); worldvel = Vector4.Transform(new Vector4(worldvel, 0), invparenttr).xyz(); } disptr.Translate(worldvel); disptr.Position = Intersections.BoxPointLimit(BoundingBoxMin, BoundingBoxMax, disptr.Position); }
private void Move(NotuiElement element, BehaviorState state, Matrix4x4 usedplane) { var disptr = element.DisplayTransformation; if (Draggable) { var worldvel = Vector4.Transform(new Vector4(state.DeltaPos * DraggingCoeffitient * 0.5f, 0, 0), usedplane).xyz(); if (element.Parent != null) { Matrix4x4.Invert(element.Parent.DisplayMatrix, out var invparenttr); worldvel = Vector4.Transform(new Vector4(worldvel, 0), invparenttr).xyz(); } disptr.Translate(worldvel); if (LimitTranslation) { disptr.Position = Intersections.BoxPointLimit(BoundingBoxMin, BoundingBoxMax, disptr.Position); } } if (Scalable) { var sclvel = state.DeltaSize * ScalingCoeffitient * 0.5f; disptr.Scale = Vector3.Max( new Vector3(ScaleMinMax.X), Vector3.Min( new Vector3(ScaleMinMax.Y), disptr.Scale * new Vector3(1 + sclvel) ) ); } if (Pivotable) { // see if rotation is still inside boundaries var targetrot = state.TotalAngle + state.DeltaAngle * RotationCoeffitient * 0.5f * (1 / disptr.Scale.Length()); if (!LimitRotation || RotationMinMax.X <= targetrot && targetrot <= RotationMinMax.Y) { state.TotalAngle = targetrot; var worldaxis = Vector3.TransformNormal(Vector3.UnitZ, usedplane); if (element.Parent != null) { Matrix4x4.Invert(element.Parent.DisplayMatrix, out var invparenttr); worldaxis = Vector3.TransformNormal(worldaxis, invparenttr); } var worldrot = Quaternion.CreateFromAxisAngle(worldaxis, state.DeltaAngle * RotationCoeffitient); disptr.LocalRotate(worldrot); } } state.Mainloop(element.Context.DeltaTime); }
protected override void Filter(int ei, NotuiElement element, ISpread <string> filter) { bool CompareType(NotuiElement el) { var res = false; foreach (var f in filter) { if (string.IsNullOrWhiteSpace(f)) { continue; } if (el.EnvironmentObject is VEnvironmentData venvdat) { res = FContains[ei] ? venvdat.TypeCSharpName.Contains(f) : venvdat.TypeCSharpName == f; } else { res = FContains[ei] ? el.GetType().GetCSharpName().Contains(f) : el.GetType().GetCSharpName() == f; } if (!res) { continue; } break; } return(FExclude[ei] ? !res : res); }; if (FContains.SliceCount == 0 || FExclude.SliceCount == 0) { return; } else { if (FOut.SliceCount == 0) { return; } FOut[ei].AddRange(element.Children.Values.Where(CompareType)); } }
public static void AttachManagementObject(this NotuiElement element, string nodepath, object obj) { if (element.EnvironmentObject == null) { element.EnvironmentObject = new VEnvironmentData(element); } if (element.EnvironmentObject is VEnvironmentData venvdat) { if (venvdat.NodeSpecific.ContainsKey(nodepath)) { venvdat.NodeSpecific[nodepath] = obj; } else { venvdat.NodeSpecific.Add(nodepath, obj); } } }
/// <summary> /// Get touches from the selected source list /// </summary> protected IEnumerable <Touch> GetTouchesFromSource(NotuiElement element, InteractingTouchSource touchsrc = InteractingTouchSource.Touching) { switch (touchsrc) { case InteractingTouchSource.Touching: return(element.Touching.Keys); case InteractingTouchSource.Hitting: return(element.Hitting.Keys); case InteractingTouchSource.Mice: return(element.Mice); default: return(Enumerable.Empty <Touch>()); } }
protected override void Filter(int ei, NotuiElement element, ISpread <string> filter) { if (FUseName.SliceCount == 0 || FSeparator.SliceCount == 0) { return; } foreach (var f in filter) { if (string.IsNullOrWhiteSpace(f)) { continue; } if (FOut.SliceCount == 0) { return; } FOut[ei].AddRange(element.Opaq(f, FSeparator[ei], FUseName[ei])); } }
public void Subscribe(NotuiElement element) { try { element.OnInteractionBegin -= _OnInteractionBeginHandler; element.OnInteractionEnd -= _OnInteractionEndHandler; element.OnTouchBegin -= _OnTouchBeginHandler; element.OnTouchEnd -= _OnTouchEndHandler; element.OnHitBegin -= _OnHitBeginHandler; element.OnHitEnd -= _OnHitEndHandler; element.OnInteracting -= _OnInteractingHandler; element.OnChildrenUpdated -= _OnChildrenUpdatedHandler; element.OnDeletionStarted -= _OnDeletionStartedHandler; element.OnDeleting -= _OnDeletingHandler; element.OnFadedIn -= _OnFadedInHandler; element.OnMouseButtonPressed -= _OnMouseButtonPressed; element.OnMouseButtonReleased -= _OnMouseButtonReleased; element.OnHorizontalMouseWheelChange -= _OnHorizontalMouseWheelChange; element.OnVerticalMouseWheelChange -= _OnVerticalMouseWheelChange; } catch { } element.OnInteractionBegin += _OnInteractionBeginHandler; element.OnInteractionEnd += _OnInteractionEndHandler; element.OnTouchBegin += _OnTouchBeginHandler; element.OnTouchEnd += _OnTouchEndHandler; element.OnHitBegin += _OnHitBeginHandler; element.OnHitEnd += _OnHitEndHandler; element.OnInteracting += _OnInteractingHandler; element.OnChildrenUpdated += _OnChildrenUpdatedHandler; element.OnDeletionStarted += _OnDeletionStartedHandler; element.OnDeleting += _OnDeletingHandler; element.OnFadedIn += _OnFadedInHandler; element.OnMouseButtonPressed += _OnMouseButtonPressed; element.OnMouseButtonReleased += _OnMouseButtonReleased; element.OnHorizontalMouseWheelChange += _OnHorizontalMouseWheelChange; element.OnVerticalMouseWheelChange += _OnVerticalMouseWheelChange; }
/// <inheritdoc cref="InteractionBehavior"/> public override void Behave(NotuiElement element) { var currstate = IsStateAvailable(element) ? GetState <BehaviorState>(element) : new BehaviorState(element); SetState(element, currstate); if (currstate.Interacted) { var restsrc = element.Parent?.Children.Values ?? element.Context.RootElements.Values; if (restsrc.Count == 1) { return; } var rest = element.Parent?.Children.Values.Where(rel => rel.Id != element.Id) ?? element.Context.RootElements.Values.Where(rel => rel.Id != element.Id); var ordered = rest.OrderBy(rel => rel.DisplayTransformation.Position.Z); var depth = Distance + Top; var currp = element.DisplayTransformation.Position; element.DisplayTransformation.Position = new Vector3(currp.xy(), Top); var currtp = element.TargetTransformation.Position; element.TargetTransformation.Position = new Vector3(currtp.xy(), Top); foreach (var el in ordered) { var elp = el.DisplayTransformation.Position; el.DisplayTransformation.Position = new Vector3(elp.xy(), depth); var eltp = el.TargetTransformation.Position; el.TargetTransformation.Position = new Vector3(eltp.xy(), depth); depth += Distance; } currstate.Interacted = false; } }
/// <inheritdoc cref="InteractionBehavior"/> public override void Behave(NotuiElement element) { var usedplane = GetUsedPlane(element); var currstate = IsStateAvailable(element) ? GetState <BehaviorState>(element) : new BehaviorState(); var touches = GetBehavingTouches(element, InteractingTouchSource.Mice); if (touches.Count >= 1) { var allscroll = touches.Aggregate(Vector2.Zero, (v, touch) => v + new Vector2( (float)touch.MouseDelta.AccumulatedHorizontalWheelDelta / 120, (float)touch.MouseDelta.AccumulatedWheelDelta / 120) ); if (allscroll.Length() > 0) { currstate.DeltaPos = allscroll; } } Move(element, currstate, usedplane); FlickProgress(currstate, element.Context); SetState(element, currstate); }
/// <summary> /// Get all the touches which can act on this behavior /// </summary> /// <param name="element"></param> /// <param name="touchsrc"></param> /// <returns></returns> protected List <Touch> GetBehavingTouches(NotuiElement element, InteractingTouchSource touchsrc = InteractingTouchSource.Touching) { List <Touch> touches; if (UseOnlyWithSpecificChildren == null) { touches = GetTouchesFromSource(element, touchsrc).ToList(); if (UseChildrenInteracting) { AddChildrenTouches(element, touches, touchsrc); } } else { touches = new List <Touch>(); var selectedChildren = UseOnlyWithSpecificChildren(element); foreach (var child in selectedChildren) { touches.AddRange(GetTouchesFromSource(child, touchsrc)); } } return(touches); }
protected void AssignElementOutputs(NotuiElement element, int i) { if (element == null) { return; } if (element.EnvironmentObject is VEnvironmentData venvdat) { TouchesOut[i] = venvdat.Touches; TouchesHittingOut[i] = venvdat.TouchesHitting; TouchingIntersectionsOut[i] = venvdat.TouchingIntersections; HittingTouchesOut[i] = venvdat.HittingTouches; HittingIntersectionsOut[i] = venvdat.HittingIntersections; MiceOut[i] = venvdat.Mice; ChildrenOut[i] = venvdat.Children; BehavsOut[i] = venvdat.Behaviors; ParentOut[i] = venvdat.Parent; DisplayTrOut[i] = venvdat.VDispTr; TypeOut[i] = venvdat.TypeCSharpName; } ElementOut[i] = element; NameOut[i] = element.Name; PrototypeOut[i] = element.Prototype; IdOut[i] = element.Id; HitOut[i] = element.Hit; TouchedOut[i] = element.Touched; ActiveOut[i] = element.Active; TransparentOut[i] = element.Transparent; FadeStateOut[i] = element.FadingState; ElementFadeOut[i] = element.ElementFade; AgeOut[i] = element.Age.Elapsed.TotalSeconds; DyingOut[i] = element.Dying; LocDisplayOut[i] = element.DisplayTransformation; ContextOut[i] = element.Context; }
protected abstract void Filter(int ei, NotuiElement element, ISpread <string> filter);
protected override void Filter(int ei, NotuiElement element, ISpread <string> filter) { bool NameCompare(NotuiElement el) { var res = false; foreach (var f in filter) { if (string.IsNullOrWhiteSpace(f)) { continue; } res = FContains[ei] ? el.Name.Contains(f) : el.Name.Equals(f, StringComparison.InvariantCulture); if (!res) { continue; } break; } return(FExclude[ei] ? !res : res); }; bool IdCompare(NotuiElement el) { var res = false; foreach (var f in filter) { if (string.IsNullOrWhiteSpace(f)) { continue; } res = FContains[ei] ? el.Id.Contains(f) : el.Id.Equals(f, StringComparison.InvariantCulture); if (!res) { continue; } break; } return(FExclude[ei] ? !res : res); }; if (FContains.SliceCount == 0 || FUseName.SliceCount == 0 || FExclude.SliceCount == 0) { return; } else { if (FOut.SliceCount == 0) { return; } FOut[ei].AddRange(FUseName[ei] ? element.Children.Values.Where(NameCompare) : element.Children.Values.Where(IdCompare)); } }
/// <summary> /// Construct based on an instance /// </summary> /// <param name="fromInstance">The element instance</param> /// <param name="newId">Generate a new ID?</param> /// <remarks>Static function ElementPrototype.CreateFromInstance(...) is recommended to be used instead of this</remarks> public SphereElementPrototype(NotuiElement fromInstance, bool newId = true) : base(fromInstance, newId) { }
/// <inheritdoc cref="NotuiElement"/> public SphereElement(ElementPrototype prototype, NotuiContext context, NotuiElement parent = null) : base(prototype, context, parent) { }
/// <inheritdoc cref="InteractionBehavior"/> public override void Behave(NotuiElement element) { if (element.Value == null) { element.Value = new AttachedValues(); } var stateAvailable = IsStateAvailable(element); var values = element.Value.Values; if (!stateAvailable) { SetState(element, new BehaviorState()); element.Value.Values = new float[Max(VerticalOffs, HorizontalOffs) + 1]; element.Value.Values.Fill(values); values = element.Value.Values; values[HorizontalOffs] = Default.X; values[VerticalOffs] = Default.Y; } if (AxisCoeff.Length() < 0.00001) { return; } if (Constrain && Vector2.Distance(LimitMin, LimitMax) < 0.00001) { return; } if (element.Touching.IsEmpty) { return; } KeyValuePair <Touch, IntersectionPoint> fastesttouch; try { if (MouseMask.Length == 0) { fastesttouch = element.Touching.OrderByDescending(t => t.Key.Velocity.LengthSquared()).First(); } else if (MouseMask.Length == 1 && MouseMask[0] == MouseButtons.Left) { fastesttouch = (from touch in element.Touching where touch.Key.AttachadMouse == null || touch.Key.MouseDelta.MouseClicks.Values.Where(mc => mc.Button != MouseButtons.Left).All(mc => !mc.Pressed) select touch) .OrderByDescending(t => t.Key.Velocity.LengthSquared()).First(); } else { fastesttouch = (from touch in element.Touching where touch.Key.AttachadMouse != null where touch.Key.MouseDelta.MouseClicks.Values.Where(mc => mc.Pressed).All(mc => MouseMask.Contains(mc.Button)) select touch) .OrderByDescending(t => t.Key.Velocity.LengthSquared()).First(); } } catch { return; } if (values.Length <= Max(VerticalOffs, HorizontalOffs)) { element.Value.Values = new float[Max(VerticalOffs, HorizontalOffs) + 1]; element.Value.Values.Fill(values); values = element.Value.Values; } Vector3 vel; if (UseSurfaceSpace) { var origis = fastesttouch.Value; if (origis == null) { return; } element.PureHitTest(fastesttouch.Key, true, out var previs); if (previs == null) { return; } vel = (origis.SurfaceSpace - previs.SurfaceSpace) * 0.5f; } else { vel = fastesttouch.Key.GetPlanarVelocity(element.DisplayMatrix, element.Context, out var cpos, out var ppos); } if (Constrain) { values[HorizontalOffs] = Max(LimitMin.X, Min(LimitMax.X, values[HorizontalOffs] + vel.X * AxisCoeff.X * 0.5f)); values[VerticalOffs] = Max(LimitMin.Y, Min(LimitMax.Y, values[VerticalOffs] + vel.Y * AxisCoeff.Y * 0.5f)); } else { values[HorizontalOffs] += vel.X * AxisCoeff.X * 0.5f; values[VerticalOffs] += vel.Y * AxisCoeff.Y * 0.5f; } }
/// <inheritdoc cref="NotuiElement"/> public InfinitePlaneElement(ElementPrototype prototype, NotuiContext context, NotuiElement parent = null) : base(prototype, context, parent) { }
/// <summary> /// Construct based on an instance /// </summary> /// <param name="fromInstance">The element instance</param> /// <param name="newId">Generate a new ID?</param> /// <remarks>Static function ElementPrototype.CreateFromInstance(...) is recommended to be used instead of this</remarks> public PolygonElementPrototype(NotuiElement fromInstance, bool newId = true) : base(fromInstance, newId) { }
public static void AttachSliceId(this NotuiElement element, string nodepath, int id) { element.AttachManagementObject(nodepath, id); }
/// <summary></summary> /// <param name="prototype"></param> /// <param name="context"></param> /// <param name="parent"></param> protected PlanarElement(ElementPrototype prototype, NotuiContext context, NotuiElement parent = null) : base(prototype, context, parent) { }