/// <summary> /// Handles the <strong>ContactDown</strong> event. /// </summary> /// <param name="contactEvent">The container for the contact that the event is about.</param> protected override void OnContactDown(ContactTargetEvent contactEvent) { base.OnContactDown(contactEvent); // Did the contact hit the thumb or the track. ScrollBarPart partHit = GetScrollBarPartHit(contactEvent.HitTestDetails as ScrollBarHitTestDetails); // The contact went down on the ScrollBar so capture it. Controller.Capture(contactEvent.Contact, this); ScrollBarHitTestDetails details = contactEvent.HitTestDetails as ScrollBarHitTestDetails; // Check to make sure the details are of the correct type. // We assert because this should already be caught by HitTestResult.SetHitTestInformation. if (details == null) { Debug.Fail("contactEvent.HitTestDetails should be of type ScrollBarHitTestDetails."); return; } // Stop any flicking behavior. StopFlick(); switch (partHit) { // The Thumb was hit. case ScrollBarPart.Thumb: // Pause the animation if we are playing. if (scrollAnimation != null && scrollAnimation.IsPlaying) { scrollAnimation.Pause(); } // Set the part hit to the thumb. selectedPart = ScrollBarPart.Thumb; // Add this contact to the thumb list so that it can be used for averaging. thumbCapturedContactsList.Add(contactEvent.Contact.Id); // Tie this contact id to the Thumb. capturedCollectionLookup.Add(contactEvent.Contact.Id, ScrollBarPart.Thumb); // We need to be able to look up the hit test details later so save that off. captureContactsHitTestDetails.Add(contactEvent.Contact.Id, details); // We want to move the thumb from the point at which it was hit not the top, so store the offset in scrollbar space. distanceOffset.Add(contactEvent.Contact.Id, details.Position - (Value * (1 - ViewportSize))); break; // The Track was hit. case ScrollBarPart.Track: // Place the contact at the end of the track queue. trackQueue.Enqueue(contactEvent.Contact.Id); // Tie this contact to the Track. capturedCollectionLookup.Add(contactEvent.Contact.Id, ScrollBarPart.Track); // We need to be able to look up the hit test details later so save that off. captureContactsHitTestDetails.Add(contactEvent.Contact.Id, details); // The thumb has contacts captured so don't proceed. if (thumbCapturedContactsList.Count != 0) return; int id = GetFrontOfTrackQueue(); // If the id isn't the same as contact id which went down don't proceed. if (id != contactEvent.Contact.Id) return; selectedPart = ScrollBarPart.Track; // The contact hit before the thumb. if (details.Position < ThumbStartPosition) { if (isReversed) { PageForward(); } else { PageBack(); } } else // The contact hit after the thumb { if (isReversed) { PageBack(); } else { PageForward(); } } break; default: break; } }
/// <summary> /// Handles the <strong>ContactUp</strong> event. /// </summary> /// <param name="contactEvent">The container for the contact that the event is about.</param> protected override void OnContactUp(ContactTargetEvent contactEvent) { base.OnContactUp(contactEvent); int id = contactEvent.Contact.Id; // Depending on state, the contact will be in some of these dictionaries. // we don't need to track their state after this point for the given id // so just call remove since remove doesn't throw exceptions for items not the collection. thumbCapturedContactsList.Remove(id); capturedCollectionLookup.Remove(id); // If there aren't any contacts on the thumb stop manipulating. if (thumbCapturedContactsList.Count == 0 && captureContactsHitTestDetails.Count != 0) { if (manipulationProcessor != null) { ScrollBarHitTestDetails hitTestDetails = captureContactsHitTestDetails[id] as ScrollBarHitTestDetails; float offset = 0; if (distanceOffset.ContainsKey(id)) { offset = distanceOffset[id]; } // The Manipulations should all run in screen space. manipulationProcessor.ProcessManipulators(stopwatch.ElapsedTicks, new List<Manipulator>(), new List<Manipulator> { new Manipulator(id, ToScreenSpace(hitTestDetails.Position - offset), 0) }); } // The thumb is no longer captured so check to see what the selected part should be. if (GetFrontOfTrackQueue() == -1) selectedPart = ScrollBarPart.None; else selectedPart = ScrollBarPart.Track; } distanceOffset.Remove(id); captureContactsHitTestDetails.Remove(id); }
/// <summary> /// Handles <strong>ContactDown</strong> events. /// </summary> /// <param name="contactEvent">The list Box item contact that was added.</param> protected override void OnContactDown(ContactTargetEvent contactEvent) { base.OnContactDown(contactEvent); ListBoxMode = ListBoxMode.Selection; // Capture the contact to the ListBox Controller.Capture(contactEvent.Contact, this); // Get the item based on the contact details. ListBoxStateMachineItem item = GetItemHit(contactEvent.HitTestDetails as ListBoxHitTestDetails); // The item could be null if there are fewer items whose sizes sum to less than the size of the ListBox. if (item == null) return; // Put the contact on the listbox item. Internal hit test to figure out which item it's over. capturedItemContactIds.Add(contactEvent.Contact.Id, item); // Have the item process ContactDown. item.ProcessContactDown(contactEvent.Contact.Id); // The item should change based on having a contact over it? // Store the position. contactTargetEventContactIds.Add(contactEvent.Contact.Id, contactEvent); }
/// <summary> /// Handles the ContactChanged event. /// </summary> /// <param name="contactEvent"></param> public void ProcessContactChanged(ContactTargetEvent contactEvent) { // For each contact which changed update the item in the manipulation processor list. if (!currentContactInformation.ContainsKey(contactEvent.Contact.Id)) { return; } ScrollViewerHitTestDetails hitTestDetails = contactEvent.HitTestDetails as ScrollViewerHitTestDetails; if (hitTestDetails == null) { return; } // Change the value for this contact. currentContactInformation[contactEvent.Contact.Id] = contactEvent; float averageX, averageY; float actualValueX = 0, constrainedValueX = 0; float actualValueY = 0, constrainedValueY = 0; AverageContactPosition(contactEvent, hitTestDetails, out averageX, out averageY); // Put the new position in the down so that we can use it to calculate change next time. contactDownContactInformation[contactEvent.Contact.Id] = contactEvent; // Transform the value in to start position space and add the change for X actualValueX = averageX + ConvertFromHorizontalValueToControlSpace(horizontalScrollBarStateMachine.Value); // Constrain X constrainedValueX = FlickUtilities.Clamp(actualValueX, 0, 1 - HorizontalViewportSize); // Transform the value into start position space and add the change for Y actualValueY = averageY + ConvertFromVerticalValueToControlSpace(verticalScrollBarStateMachine.Value); // Constrain Y constrainedValueY = FlickUtilities.Clamp(actualValueY, 0, 1 - VerticalViewportSize); // Determine if the viewport start position is outside of the 0 to 1 range. float constrainedRunningY = FlickUtilities.Clamp(runningActualValueY, 0, 1 - VerticalViewportSize); float constrainedRunningX = FlickUtilities.Clamp(runningActualValueX, 0, 1 - HorizontalViewportSize); if ((Orientation & Orientation.Horizontal) != 0) { // Deal with Elasticity behavior for horizontal if (runningActualValueX == constrainedRunningX && actualValueX == constrainedValueX) { ClampScrollBarValueX(actualValueX, constrainedValueX); } else { SetElasticScrollBarValueX(averageX); } } if ((Orientation & Orientation.Vertical) != 0) { // Deal with Elasticity behavor for vertical if (runningActualValueY == constrainedRunningY && actualValueY == constrainedValueY) { ClampScrollBarValueY(actualValueY, constrainedValueY); } else { SetElasticScrollBarValueY(averageY); } } // Use this contact event to update the current manipulators. UpdateCurrentManipulators(contactEvent, hitTestDetails); }
/// <summary> /// Calls <strong><see cref="M:CoreInteractionFramework.ButtonStateMachine.OnClick" /></strong> /// if the contact is captured over the button and there are no more captured contacts. /// </summary> /// <param name="contactEvent">The contact that was removed.</param> protected override void OnContactUp(ContactTargetEvent contactEvent) { if (ClickMode == ClickMode.Release && ContactsCaptured.Contains(contactEvent.Contact.Id) && ContactsCaptured.Count == 1) { if (Controller.DoesHitTestMatchCapture(contactEvent.Contact)) { releaseModeContactUp = true; } } base.OnContactUp(contactEvent); switch (ClickMode) { case ClickMode.Release: case ClickMode.Press: foreach (Contact capturedContact in ContactsCaptured) { if (Controller.DoesHitTestMatchCapture(capturedContact)) { isPressed = true; return; } } isPressed = false; break; case ClickMode.Hover: if (this.ContactsOver.Count == 0) isPressed = false; break; default: break; } }
/// <summary> /// Updates the position of the contact information in contactTargetEventContactIds /// </summary> /// <param name="contactEvent"></param> private void UpdateContactPosition(ContactTargetEvent contactEvent) { // Based on the down position in contactTargetEventContactIds track how much this item has changed // and place it in contactChangeDeltaContactIds int contactId = contactEvent.Contact.Id; if (!contactTargetEventContactIds.ContainsKey(contactId)) { return; } if (contactChangeDeltaContactIds.ContainsKey(contactId)) { ListBoxHitTestDetails originalDetails = (ListBoxHitTestDetails)contactTargetEventContactIds[contactId].HitTestDetails; ListBoxHitTestDetails currentDetails = contactEvent.HitTestDetails as ListBoxHitTestDetails; if (currentDetails == null) { return; } float original = 0f, current = 0f; if (Orientation == Orientation.Horizontal) { current = currentDetails.HorizontalPosition; original = originalDetails.HorizontalPosition; } else { current = currentDetails.VerticalPosition; original = originalDetails.VerticalPosition; } // Get the total distance this contact has moved since it went down. contactChangeDeltaContactIds[contactId] = current - original; } else { contactChangeDeltaContactIds.Add(contactId, 0f); } }
/// <summary> /// Handles ContactRemoved events from the ContactTarget /// </summary> private void OnContactRemoved(object sender, ContactEventArgs e) { ContactTargetEvent cte = new ContactTargetEvent(ContactEventType.Removed, e.Contact); lock (swapLock) { this.orderedContactEventsBackbuffer.Enqueue(cte); if (this.orderedContactEventsBackbuffer.Count > MaximumQueueSize) { throw SurfaceCoreFrameworkExceptions.MaximumQueueSizeReached(MaximumQueueSize); } } }
/// <summary> /// Calls <strong><see cref="M:CoreInteractionFramework.ButtonStateMachine.OnClick" /></strong> /// if there are no contacts over and /// <strong><see cref="P:CoreInteractionFramework.ButtonStateMachine.ClickMode" /></strong> is <strong>Hover</strong>. /// </summary> /// <param name="contactEvent">The contact that entered.</param> protected override void OnContactEnter(ContactTargetEvent contactEvent) { switch (ClickMode) { case ClickMode.Hover: if (this.ContactsOver.Count == 0) { isPressed = true; OnClick(); } break; case ClickMode.Press: case ClickMode.Release: default: break; } base.OnContactEnter(contactEvent); }
private void HitTestFail(HitTestResult hitTestResult) { IInputElementStateMachine stateMachine; // Check to see if this contact is captured to an IInputElementStateMachine. if (capturedContacts.TryGetValue(hitTestResult.Contact.Id, out stateMachine)) { if (hitTestResult.ContactTargetEvent.EventType == ContactEventType.Removed) { // Send the up notification to the old statemachine. packagedContacts.Add(hitTestResult.ContactTargetEvent, stateMachine); // Send leave notification to the old statemachine. ContactTargetEvent leaveEvent = new ContactTargetEvent(ContactEventType.Leave, hitTestResult.Contact); packagedContacts.Add(leaveEvent, stateMachine); } else { // Send the leave notification to the old statemachine. packagedContacts.Add(hitTestResult.ContactTargetEvent, stateMachine); } // If this contact was over it shouldn't be any longer. if (contactsOver.ContainsKey(hitTestResult.Contact.Id)) { contactsOver.Remove(hitTestResult.Contact.Id); } } else { // Is this contact over an IInputElementStateMachine currently? if (contactsOver.TryGetValue(hitTestResult.Contact.Id, out stateMachine)) { // The contact just moved off the edge of the IInputElementStateMachine. if (hitTestResult.ContactTargetEvent.EventType == ContactEventType.Changed) { hitTestResult.ContactTargetEvent.EventType = ContactEventType.Leave; } // Send the notification to the old statemachine. packagedContacts.Add(hitTestResult.ContactTargetEvent, stateMachine); contactsOver.Remove(hitTestResult.Contact.Id); } } // The contact isn't captured, isn't in the contacts over // and it didn't hit anything so there is no where to route it. }
private void HitTestSuccess(HitTestResult hitTestResult) { if (hitTestResult.StateMachine.Controller != this) { throw SurfaceCoreFrameworkExceptions.ControllerSetToADifferentControllerException(hitTestResult.StateMachine); } // Check if the ContactId is in the contactsOver collection. IInputElementStateMachine overStateMachine; if (contactsOver.TryGetValue(hitTestResult.Contact.Id, out overStateMachine)) { // Then check if the hitTestResult is over the sane statemachine if (hitTestResult.StateMachine == overStateMachine) { // Just because the contactOver collection hasn't change doesn't mean this event is being // sent to the correct statemachine. Check if this should be sent to the captured statemachine. IInputElementStateMachine capturedStateMachine; if (capturedContacts.TryGetValue(hitTestResult.Contact.Id, out capturedStateMachine)) { if (hitTestResult.ContactTargetEvent.EventType == ContactEventType.Removed) { // Send the up notification to the old statemachine. packagedContacts.Add(hitTestResult.ContactTargetEvent, capturedStateMachine); // Send leave notification to the old statemachine. ContactTargetEvent leaveEvent = new ContactTargetEvent(ContactEventType.Leave, hitTestResult.Contact); packagedContacts.Add(leaveEvent, capturedStateMachine); } else { packagedContacts.Add(hitTestResult.ContactTargetEvent, capturedStateMachine); } } else { // Contact is not currently captured. if (hitTestResult.ContactTargetEvent.EventType == ContactEventType.Removed) { // Send the up notification to the old statemachine. packagedContacts.Add(hitTestResult.ContactTargetEvent, hitTestResult.StateMachine); // Send leave notification to the old statemachine. ContactTargetEvent leaveEvent = new ContactTargetEvent(ContactEventType.Leave, hitTestResult.Contact); packagedContacts.Add(leaveEvent, hitTestResult.StateMachine); } else { packagedContacts.Add(hitTestResult.ContactTargetEvent, hitTestResult.StateMachine); } } // No calls to RoutePackagedContacts() and packagedContacts.Clear() // When hitTestResult.StateMachine and overStateMachine are the same. } else { // It's over a different statemachine. // Remove the old IInputElementStateMachine from the contactsOver collection. contactsOver.Remove(hitTestResult.Contact.Id); // Add the new IInputElementStateMachine to the contactsOver collection contactsOver.Add(hitTestResult.Contact.Id, hitTestResult.StateMachine); IInputElementStateMachine capturedStateMachine; if (capturedContacts.TryGetValue(hitTestResult.Contact.Id, out capturedStateMachine)) { // Contact is captured, but over a different statemachine. // If the contact is captured then don't send enter leave events. // Route this event to the capturedStateMachine. packagedContacts.Add(hitTestResult.ContactTargetEvent, capturedStateMachine); } else { // Contact is not captured over a new statemachine. // It's not over the same statemachine, so we need to add a leave ContactTargetEvent to tell // the statemachine its leaving. ContactTargetEvent leaveEvent = new ContactTargetEvent(ContactEventType.Leave, hitTestResult.Contact); // We need to add the leave event or it will not get routed. packagedContacts.Add(leaveEvent, overStateMachine); // Then change the EventType to Enter so that the new statemachine // will know a Contact just entered. hitTestResult.ContactTargetEvent.EventType = ContactEventType.Enter; packagedContacts.Add(hitTestResult.ContactTargetEvent, hitTestResult.StateMachine); } // Route contacts and remove the added ones anytime a contact Enter, Add, Remove or Leaves. RoutePackagedContacts(); packagedContacts.Clear(); } } else { // Not in contactsOver. // This contact is just coming over a statemachine either change or add. // Check to see if this contact is captured to an IInputElementStateMachine. IInputElementStateMachine capturedStateMachine = null; if (capturedContacts.TryGetValue(hitTestResult.Contact.Id, out capturedStateMachine)) { // ContactsOver should reflect which element this contact is over, not which it's captured too. contactsOver.Add(hitTestResult.Contact.Id, hitTestResult.StateMachine); // We should send this event to the element that captured it. packagedContacts.Add(hitTestResult.ContactTargetEvent, capturedStateMachine); } else { // Not captured. // We want to send an Enter event instead of a changed. if (hitTestResult.ContactTargetEvent.EventType == ContactEventType.Changed) { hitTestResult.ContactTargetEvent.EventType = ContactEventType.Enter; } if (hitTestResult.ContactTargetEvent.EventType == ContactEventType.Added) { ContactTargetEvent enterEvent = new ContactTargetEvent(ContactEventType.Enter, hitTestResult.Contact); packagedContacts.Add(enterEvent, hitTestResult.StateMachine); } // This contact is now over this IInputElementStateMachine. switch (hitTestResult.ContactTargetEvent.EventType) { case ContactEventType.Enter: case ContactEventType.Added: contactsOver.Add(hitTestResult.Contact.Id, hitTestResult.StateMachine); break; case ContactEventType.Removed: case ContactEventType.Leave: Debug.Fail("If we get an removed or leave we missed adding it to an IInputElementStateMachine somewhere."); break; } packagedContacts.Add(hitTestResult.ContactTargetEvent, hitTestResult.StateMachine); } // Route contacts and remove the added ones anytime a contact Enter, Add, Remove or Leaves. RoutePackagedContacts(); packagedContacts.Clear(); } }
/// <summary> /// Averages the position of the contactEvent.HitTestDetails position based on the number of contacts. /// </summary> /// <param name="contactEvent">The new ContactTargetEvent</param> /// <param name="hitTestDetails">The contacEvent.HitTestDetails as ScrollViewerHitTestDetails</param> /// <param name="averageX"></param> /// <param name="averageY"></param> private void AverageContactPosition(ContactTargetEvent contactEvent, ScrollViewerHitTestDetails hitTestDetails, out float averageX, out float averageY) { // Get the down hitTestDetails for this contact. ScrollViewerHitTestDetails downDetails = contactDownContactInformation[contactEvent.Contact.Id].HitTestDetails as ScrollViewerHitTestDetails; // Calculate how much has changed since last move. averageX = (downDetails.HorizontalPosition - hitTestDetails.HorizontalPosition) * HorizontalViewportSize; averageY = (downDetails.VerticalPosition - hitTestDetails.VerticalPosition) * VerticalViewportSize; // Average the change by the number of contacts on the Surface. averageX /= contactDownContactInformation.Count; averageY /= contactDownContactInformation.Count; }
/// <summary> /// Handles the ContactUp event. /// </summary> /// <param name="contactEvent"></param> public void ProcessContactUp(ContactTargetEvent contactEvent) { if (!currentContactInformation.ContainsKey(contactEvent.Contact.Id)) { return; } Manipulator? removed = null; currentContactInformation.Remove(contactEvent.Contact.Id); contactDownContactInformation.Remove(contactEvent.Contact.Id); // Find the manipulator that is being removed. for (int i = 0; i < manipulations.Count; i++) { Manipulator manipulator = manipulations[i]; if (manipulator.ManipulatorId == contactEvent.Contact.Id) { manipulations.Remove(manipulator); removed = manipulator; break; } } if (removed != null) { removedManipulations.Add(removed.Value); } if (contactDownContactInformation.Count == 0) { runningActualValueY = ConvertFromVerticalValueToControlSpace(verticalScrollBarStateMachine.Value); runningActualValueX = ConvertFromHorizontalValueToControlSpace(horizontalScrollBarStateMachine.Value); verticalViewportStartPosition = runningActualValueY; horizontalViewportStartPosition = runningActualValueX; OnViewportChanged(); } }
/// <summary> /// Handles the ContactDown event. /// </summary> /// <param name="contactEvent"></param> public void ProcessContactDown(ContactTargetEvent contactEvent) { // Stop inertia if it is occuring. if (processInertia) { StopFlick(); } // Reset the running actual to the current value. if (contactDownContactInformation.Count == 0) { runningActualValueY = ConvertFromVerticalValueToControlSpace(verticalScrollBarStateMachine.Value); runningActualValueX = ConvertFromHorizontalValueToControlSpace(horizontalScrollBarStateMachine.Value); } // There was a contact hit tested to this so added it to the manipulation processor list. contactDownContactInformation.Add(contactEvent.Contact.Id, contactEvent); // There was a contact hit tested to this so added it to the manipulation processor list. currentContactInformation.Add(contactEvent.Contact.Id, contactEvent); }
/// <summary> /// Handles the <strong><see cref="E:CoreInteractionFramework.UIElementStateMachine.ContactChanged" /></strong> event. /// </summary> /// <param name="contactEvent">The contact that changed.</param> protected override void OnContactChanged(ContactTargetEvent contactEvent) { base.OnContactChanged(contactEvent); // If the contact is captured to this control then check to see if it or // any other contact hit tested to the control. if (Controller.GetCapturingElement(contactEvent.Contact) == this) { foreach (Contact capturedContact in ContactsCaptured) { if (Controller.DoesHitTestMatchCapture(capturedContact)) { isPressed = true; return; } } isPressed = false; } }
/// <summary> /// Called when a contact that is routed to this state machine goes down. /// </summary> /// <param name="contactEvent">The container object for the contact that is down.</param> protected virtual void OnContactDown(ContactTargetEvent contactEvent) { if (contactEvent.Contact == null) throw SurfaceCoreFrameworkExceptions.ArgumentNullException("contact"); EventHandler<StateMachineContactEventArgs> temp = ContactDown; if (temp != null) { temp(this, new StateMachineContactEventArgs(contactEvent.Contact, this)); } }
/// <summary> /// Changes the state of the button based on the <strong><see cref="P:CoreInteractionFramework.ButtonStateMachine.ClickMode" /></strong> /// property. /// </summary> /// <param name="contactEvent">The contact that hit the button.</param> protected override void OnContactDown(ContactTargetEvent contactEvent) { this.IsPressed = true; switch (ClickMode) { case ClickMode.Press: if (this.ContactsCaptured.Count == 0) OnClick(); this.Controller.Capture(contactEvent.Contact, this); break; case ClickMode.Release: this.Controller.Capture(contactEvent.Contact, this); break; case ClickMode.Hover: if (this.ContactsOver.Count == 0) { OnClick(); } break; default: break; } base.OnContactDown(contactEvent); }
/// <summary> /// Called when a contact that is routed to this state machine enters the state machine. /// </summary> /// <param name="contactEvent">The container for the contact that entered this state /// machine.</param> protected virtual void OnContactEnter(ContactTargetEvent contactEvent) { if (contactEvent.Contact == null) throw SurfaceCoreFrameworkExceptions.ArgumentNullException("contact"); if (contactsOver.CachedContactCollection.Contains(contactEvent.Contact.Id)) throw SurfaceCoreFrameworkExceptions.ContactIsAlreadyInCollection(contactEvent.Contact, contactsOver.CachedContactCollection); Debug.Assert(!contactsOver.EditableContactCollection.Contains(contactEvent.Contact.Id), "Contact was not in the CachedContactCollection, but is in the EditableContactCollection."); this.contactsOver.EditableContactCollection.Add(contactEvent.Contact); EventHandler<StateMachineContactEventArgs> temp = ContactEnter; if (temp != null) { temp(this, new StateMachineContactEventArgs(contactEvent.Contact, this)); } }
/// <summary> /// Called when the Contact has left the button. /// </summary> /// <param name="contactEvent">The contact that departed.</param> protected override void OnContactLeave(ContactTargetEvent contactEvent) { base.OnContactLeave(contactEvent); switch (ClickMode) { case ClickMode.Hover: if (this.ContactsOver.Count == 0) isPressed = false; break; case ClickMode.Press: case ClickMode.Release: default: break; } }
/// <summary> /// Called when a contact that is routed to this state machine leaves the state machine. /// </summary> /// <param name="contactEvent">The container object for the departed contact.</param> protected virtual void OnContactLeave(ContactTargetEvent contactEvent) { if (contactEvent.Contact == null) throw SurfaceCoreFrameworkExceptions.ArgumentNullException("contact"); if (contactsOver.EditableContactCollection.Contains(contactEvent.Contact.Id)) this.contactsOver.EditableContactCollection.Remove(contactEvent.Contact.Id); EventHandler<StateMachineContactEventArgs> temp = ContactLeave; if (temp != null) { temp(this, new StateMachineContactEventArgs(contactEvent.Contact, this)); } }
/// <summary> /// Parameterized internal class constructor. /// </summary> /// <param name="contact"> /// An event that has occured for a Surface Contact.</param> /// <param name="model"> /// Interface for upating a state machine.</param> internal HitTestResult(ContactTargetEvent contact, IInputElementStateMachine model) { this.contact = contact; this.stateMachine = model; }
/// <summary> /// Called when a contact that is routed to this state machine is removed. /// </summary> /// <param name="contactEvent">The container for the removed contact.</param> protected virtual void OnContactUp(ContactTargetEvent contactEvent) { if (contactEvent.Contact == null) throw SurfaceCoreFrameworkExceptions.ArgumentNullException("contact"); if (!contactsOver.CachedContactCollection.Contains(contactEvent.Contact.Id) && !contactsCaptured.CachedContactCollection.Contains(contactEvent.Contact.Id)) throw SurfaceCoreFrameworkExceptions.ContactIsNotInCollection(contactEvent.Contact, contactsOver.CachedContactCollection); Debug.Assert(contactsOver.EditableContactCollection.Contains(contactEvent.Contact.Id) || contactsCaptured.EditableContactCollection.Contains(contactEvent.Contact.Id), "Contact was not in the CachedContactCollection, but is in the EditableContactCollection."); if (contactsOver.EditableContactCollection.Contains(contactEvent.Contact.Id)) this.contactsOver.EditableContactCollection.Remove(contactEvent.Contact.Id); EventHandler<StateMachineContactEventArgs> temp = ContactUp; if (temp != null) { temp(this, new StateMachineContactEventArgs(contactEvent.Contact, this)); } if (contactsCaptured.CachedContactCollection.Contains(contactEvent.Contact.Id)) { Controller.Release(contactEvent.Contact); } }
/// <summary> /// Handles <strong>ContactChanged</strong> events. /// </summary> /// <param name="contactEvent">The list box item contact that changed.</param> protected override void OnContactChanged(ContactTargetEvent contactEvent) { base.OnContactChanged(contactEvent); if (ListBoxMode == ListBoxMode.Selection) { // Update the contact position and track total change. UpdateContactPosition(contactEvent); // If the ListBox is in scroll mode then route this contact to the scrollAdapter. // If in selection mode check to see if the contact has moved 1/8" // and change to scrolling mode if it has. if (DidContactMovePastThreshold(contactEvent.Contact.Id)) { ListBoxMode = ListBoxMode.Scrolling; // Uncapture contacts from items and send capture // information to the ScrollViewer for every captured contacts. foreach (KeyValuePair<int, ContactTargetEvent> downContact in contactTargetEventContactIds) { // Get the ListBoxItem this contact is "captured" to. ListBoxStateMachineItem item = capturedItemContactIds[downContact.Value.Contact.Id]; // Set the pressed state to false for this item. item.IsPressed = false; item.ChangeToScrolling(); item.capturedContacts.Clear(); if (!scrollAdapterContacts.Contains(downContact.Key)) { // Track which contact ids have been added to the scroll adapter. scrollAdapterContacts.Add(downContact.Key); // Process each contact as a contact down. scrollAdapter.ProcessContactDown(downContact.Value); } } } } else { // If the ListBox is scrollling then pass information to the scrollAdapter. scrollAdapter.ProcessContactChanged(contactEvent); } }
/// <summary> /// Handles the <strong>ContactChanged</strong> event. /// </summary> /// <param name="contactEvent">The container for the contact that the event is about.</param> protected override void OnContactChanged(ContactTargetEvent contactEvent) { base.OnContactChanged(contactEvent); // Figure out if this contact is in the list or queue. if (capturedCollectionLookup.ContainsKey(contactEvent.Contact.Id)) { ScrollBarPart part = capturedCollectionLookup[contactEvent.Contact.Id]; // Update the hitTestDetails for this contact id. ScrollBarHitTestDetails details = contactEvent.HitTestDetails as ScrollBarHitTestDetails; if (details != null) { captureContactsHitTestDetails[contactEvent.Contact.Id] = details; } // We only care about changes in the thumb. if (part == ScrollBarPart.Thumb) { if (!captureContactsHitTestDetails.ContainsKey(contactEvent.Contact.Id)) { Debug.Fail("A contact changed occured on the thumb, but the contact wasn't captured"); } // Get the average position over the thumb. float averagePoint = AverageCapturedContactsInThumbList(); // Update the value and thumb properties. Convert into Value space. UpdatedValueInValueSpace(averagePoint / (1 - viewportSize)); } } isScrolling = true; }
/// <summary> /// Handles <strong>ContactUp</strong> events. /// </summary> /// <param name="contactEvent">The contact that is removed from the list box item.</param> protected override void OnContactUp(ContactTargetEvent contactEvent) { if (ContactsCaptured.Contains(contactEvent.Contact.Id)) { // Remove the items from tracking. if (capturedItemContactIds.ContainsKey(contactEvent.Contact.Id)) { // Get the ListBoxItem this contact is "captured" to. ListBoxStateMachineItem item = capturedItemContactIds[contactEvent.Contact.Id]; if (ListBoxMode == ListBoxMode.Scrolling) { scrollAdapter.ProcessContactUp(contactEvent); // Set the pressed state to false for this item. item.IsPressed = false; } else { // If in single selection mode set all the other SelectItems to unselected. if (selectionMode == SelectionMode.Single) { for (int i = 0; i < SelectedItems.Count; i++) { if (SelectedItems[i] == item) continue; SelectedItems[i].IsSelected = false; } } // Only call process contact up when the contact is captured // as it will cause the item to be select/deselected. // Also item's IsPressed state will be cleared if scrolling begins. item.ProcessCapturedContactUp(contactEvent.Contact.Id); } // The contact is up so we don't need to track this item. capturedItemContactIds.Remove(contactEvent.Contact.Id); contactTargetEventContactIds.Remove(contactEvent.Contact.Id); scrollAdapterContacts.Remove(contactEvent.Contact.Id); contactChangeDeltaContactIds.Remove(contactEvent.Contact.Id); } // Release the contact. Controller.Release(contactEvent.Contact); if (ContactsCaptured.Count == 0) { ListBoxMode = ListBoxMode.Selection; } } // Select the item if in selection mode // Release capture on the contact. base.OnContactUp(contactEvent); }
/// <summary> /// Updates manipulators to reflect the contact change. /// </summary> /// <param name="contactEvent">The new ContactTargetEvent</param> /// <param name="details">The contacEvent.HitTestDetails as ScrollViewerHitTestDetails</param> private void UpdateCurrentManipulators(ContactTargetEvent contactEvent, ScrollViewerHitTestDetails details) { // Try to find the changed contact in the manipulators list. bool foundManipulator = false; for (int i = 0; i < manipulations.Count; i++) { Manipulator manipulator = manipulations[i]; if (manipulator.ManipulatorId == contactEvent.Contact.Id) { manipulations.Remove(manipulator); Manipulator manipulatorToAdd = new Manipulator(contactEvent.Contact.Id, ConvertFromHorizontalValueToScreenSpace(details.HorizontalPosition), ConvertFromVerticalValueToScreenSpace(details.VerticalPosition)); // Performance: It doesn't matter where we insert, but if all the contacts are being updated, // then putting the most recent change at the end will mean that there is one less contact // to go through the next time this loop is executed. if (manipulations.Count == 0) { manipulations.Add(manipulatorToAdd); } else { manipulations.Insert(manipulations.Count - 1, manipulatorToAdd); } foundManipulator = true; break; } } // The manipulator isn't in the list so add it. if (!foundManipulator) { manipulations.Add(new Manipulator(contactEvent.Contact.Id, ConvertFromHorizontalValueToScreenSpace(details.HorizontalPosition), ConvertFromVerticalValueToScreenSpace(details.VerticalPosition))); } }