Пример #1
0
        /// <summary>Updates mouse overs, touches and the mouse position.</summary>
        public static void Update()
        {
            InputPointer pointer;

            // Look out for any 'new' touch events:
            int touchCount = UnityEngine.Input.touchCount;

            if (touchCount > 0)
            {
                Debug.Log("HiInput TouchCount: " + touchCount.ToString());

                // For each one..
                for (int i = 0; i < touchCount; i++)
                {
                    // Get the info:
                    Touch touch = UnityEngine.Input.GetTouch(i);

                    pointer = null;

                    // Already seen this one?
                    // There won't be many touches so a straight linear scan is by far the fastest option here.
                    // (It's much better than a dictionary).
                    for (int p = InputPointer.PointerCount - 1; p >= 0; p--)
                    {
                        // Get the pointer:
                        pointer = InputPointer.AllRaw[p];

                        if (pointer.ID == touch.fingerId)
                        {
                            // Got it!
                            break;
                        }
                    }

                    TouchPointer tp = null;

                    if (pointer == null)
                    {
                        // Touch start! A new finger has been seen for the first time.
                                                #if UNITY_5_3_OR_NEWER
                        // Could be a stylus:
                        if (touch.type == TouchType.Stylus)
                        {
                            tp = new StylusPointer();
                        }
                        else
                        {
                            tp = new FingerPointer();
                        }
                                                #else
                        // Can only assume it's a finger here:
                        tp = new FingerPointer();
                                                #endif

                        // Add it to the available set:
                        tp.Add();
                    }
                    else
                    {
                        // Apply latest info:
                        tp = (pointer as TouchPointer);
                    }

                    // Mark it as still alive so it doesn't get removed shortly.
                    tp.StillAlive     = true;
                    tp.LatestPosition = touch.position;

                                        #if UNITY_5_3_OR_NEWER
                    tp.LatestPressure = touch.pressure;
                    tp.Radius         = touch.radius;
                    tp.RadiusVariance = touch.radiusVariance;

                    // Is it a stylus?
                    if (tp is StylusPointer)
                    {
                        tp.UpdateStylus(touch.azimuthAngle, touch.altitudeAngle);
                    }

                    // Always a pressure of 1 otherwise (which is set by default).
                                        #endif
                }
            }

            // Update each pointer, invalidating itself only if it has moved:
            bool pointerRemoved = false;

            for (int i = InputPointer.PointerCount - 1; i >= 0; i--)
            {
                // Get the pointer:
                pointer = InputPointer.AllRaw[i];

                // Update its position and state now:
                Vector2 delta;
                bool    moved = pointer.Relocate(out delta);

                if (pointer.Removed)
                {
                    // It got removed! (E.g. a finger left the screen).
                    pointerRemoved = true;
                    continue;
                }

                // If the pointer is invalid or they all are:
                if (moved || PointersInvalid)
                {
                    // Figure out what's under it. This takes its pos on the screen
                    // and figures out what's there, as well as converting the position
                    // to one which is relative to the document (used by e.g. a WorldUI).
                    float   documentX     = pointer.ScreenX;
                    float   documentY     = pointer.ScreenY;
                    Element newActiveOver = ElementFromPoint(ref documentX, ref documentY, pointer);

                    // Update docX/Y:
                    pointer.DocumentX = documentX;
                    pointer.DocumentY = documentY;

                    // Get the old one:
                    Element oldActiveOver = pointer.ActiveOver;

                    // Shared event:
                    MouseEvent mouseEvent = new MouseEvent(documentX, documentY, pointer.ButtonID, pointer.IsDown);
                    mouseEvent.trigger = pointer;
                    mouseEvent.clientX = pointer.DocumentX;
                    mouseEvent.clientY = pointer.DocumentY;
                    mouseEvent.SetModifiers();
                    mouseEvent.SetTrusted();

                    // If overElement has changed from the previous one..
                    if (newActiveOver != oldActiveOver)
                    {
                        if (oldActiveOver != null)
                        {
                            // Trigger a mouseout (bubbles):
                            mouseEvent.EventType = "mouseout";
                            mouseEvent.SetTrusted();
                            mouseEvent.relatedTarget = newActiveOver;
                            oldActiveOver.dispatchEvent(mouseEvent);

                            // And a mouseleave (doesn't bubble).
                            // Only triggered if newActiveOver is *not* the parent of oldActiveOver.
                            if (oldActiveOver.parentNode_ != newActiveOver)
                            {
                                mouseEvent.Reset();
                                mouseEvent.bubbles       = false;
                                mouseEvent.EventType     = "mouseleave";
                                mouseEvent.relatedTarget = newActiveOver;
                                oldActiveOver.dispatchEvent(mouseEvent);
                            }
                        }

                        // Update it:
                        pointer.ActiveOver = newActiveOver;

                        if (oldActiveOver != null)
                        {
                            // Update the CSS (hover; typically out):
                            (oldActiveOver as IRenderableNode).ComputedStyle.RefreshLocal(true);
                        }

                        if (newActiveOver != null)
                        {
                            // Update the CSS (hover; typically in)
                            (newActiveOver as IRenderableNode).ComputedStyle.RefreshLocal(true);
                        }

                        // Trigger a mouseover (bubbles):
                        mouseEvent.Reset();
                        mouseEvent.bubbles       = true;
                        mouseEvent.relatedTarget = oldActiveOver;
                        mouseEvent.EventType     = "mouseover";

                        if (newActiveOver == null)
                        {
                            // Clear the main UI tooltip:
                            UI.document.tooltip = null;

                            // Dispatch to unhandled:
                            Unhandled.dispatchEvent(mouseEvent);
                        }
                        else
                        {
                            newActiveOver.dispatchEvent(mouseEvent);

                            // Set the tooltip if we've got one:
                            UI.document.tooltip = newActiveOver["title"];

                            // And a mouseenter (doesn't bubble).
                            // Only triggered if newActiveOver is *not* a child of oldActiveOver.
                            if (newActiveOver.parentNode_ != oldActiveOver)
                            {
                                mouseEvent.Reset();
                                mouseEvent.bubbles       = false;
                                mouseEvent.EventType     = "mouseenter";
                                mouseEvent.relatedTarget = oldActiveOver;
                                newActiveOver.dispatchEvent(mouseEvent);
                            }
                        }
                    }

                    if (moved)
                    {
                        // Trigger a mousemove event:
                        mouseEvent.Reset();
                        mouseEvent.bubbles   = true;
                        mouseEvent.EventType = "mousemove";

                        if (newActiveOver == null)
                        {
                            Unhandled.dispatchEvent(mouseEvent);
                        }
                        else
                        {
                            newActiveOver.dispatchEvent(mouseEvent);
                        }
                    }
                }

                // If the pointer requires pressure changes..
                if (pointer.FireTouchEvents)
                {
                    // Set the pressure (which triggers mousedown/up for us too):
                    TouchPointer tp = (pointer as TouchPointer);

                    if (tp.LatestPressure != tp.Pressure)
                    {
                        tp.SetPressure(tp.LatestPressure);
                    }

                    // We test touch move down here because it must happen after we've
                    // transferred 'ActiveOver' to 'ActiveDown' which happens inside SetPressure.

                    // Touch events are triggered on the element that was pressed down on
                    // (even if we've moved beyond it's bounds).
                    if (moved)
                    {
                        // Trigger a touchmove event too:
                        TouchEvent te = new TouchEvent("touchmove");
                        te.trigger = pointer;
                        te.SetTrusted();
                        te.clientX = pointer.DocumentX;
                        te.clientY = pointer.DocumentY;
                        te.SetModifiers();


                        if (pointer.ActivePressed == null)
                        {
                            // Trigger on unhandled:
                            Unhandled.dispatchEvent(te);
                        }
                        else
                        {
                            pointer.ActivePressed.dispatchEvent(te);
                        }
                    }
                }

                // Test for dragstart
                if (pointer.IsDown && moved)
                {
                    // How far has it moved since it went down?
                    if (pointer.DragStatus == InputPointer.DRAG_UNKNOWN)
                    {
                        // Is the element we pressed (or any of its parents) draggable?
                        if (pointer.MinDragDistance == 0f)
                        {
                            // Find if we've got a draggable element:
                            pointer.ActiveUpdating = GetDraggable(pointer.ActivePressed);

                            // Find the min drag distance:
                            pointer.MinDragDistance = pointer.GetMinDragDistance();
                        }

                        if (pointer.MovedBeyondDragDistance)
                        {
                            // Possibly dragging.

                            // Actually marked as 'draggable'?
                            if (pointer.ActiveUpdating != null)
                            {
                                // Try start drag:
                                DragEvent de = new DragEvent("dragstart");
                                de.trigger = pointer;
                                de.SetModifiers();
                                de.SetTrusted();
                                de.deltaX  = delta.x;
                                de.deltaY  = delta.y;
                                de.clientX = pointer.DocumentX;
                                de.clientY = pointer.DocumentY;

                                if (pointer.ActivePressed.dispatchEvent(de))
                                {
                                    // We're now dragging!
                                    pointer.DragStatus = InputPointer.DRAGGING;
                                }
                                else
                                {
                                    // It didn't allow it. This status prevents it from spamming dragstart.
                                    pointer.DragStatus = InputPointer.DRAG_NOT_AVAILABLE;
                                }
                            }
                            else
                            {
                                // Selectable?
                                ComputedStyle cs         = (pointer.ActivePressed as IRenderableNode).ComputedStyle;
                                Css.Value     userSelect = cs[Css.Properties.UserSelect.GlobalProperty];

                                if (userSelect != null && !(userSelect.IsType(typeof(Css.Keywords.None))) && !userSelect.IsAuto)
                                {
                                    // Selectable!
                                    Css.Properties.UserSelect.BeginSelect(pointer, userSelect);

                                    // Set status:
                                    pointer.DragStatus = InputPointer.SELECTING;

                                    // Focus it if needed:
                                    HtmlElement html = (pointer.ActivePressed as HtmlElement);

                                    if (html != null)
                                    {
                                        html.focus();
                                    }
                                }
                                else
                                {
                                    // This status prevents it from spamming, at least until we release.
                                    pointer.DragStatus = InputPointer.DRAG_NOT_AVAILABLE;
                                }
                            }
                        }
                    }
                    else if (pointer.DragStatus == InputPointer.DRAGGING)
                    {
                        // Move the dragged element (the event goes to everybody):
                        if (pointer.ActivePressed != null)
                        {
                            DragEvent de = new DragEvent("drag");
                            de.trigger = pointer;
                            de.SetModifiers();
                            de.SetTrusted();
                            de.deltaX  = delta.x;
                            de.deltaY  = delta.y;
                            de.clientX = pointer.DocumentX;
                            de.clientY = pointer.DocumentY;

                            if (pointer.ActivePressed.dispatchEvent(de))
                            {
                                // Note that onDrag runs on the *dragging* element only.
                                Element dragging = (pointer.ActiveUpdating == null)? pointer.ActivePressed : pointer.ActiveUpdating;

                                if (dragging.OnDrag(de))
                                {
                                    // Run the PowerUI default - move the element:
                                    RenderableData renderData = (dragging as IRenderableNode).RenderData;

                                    // Get the "actual" left/top values:
                                    if (renderData.FirstBox != null)
                                    {
                                        // Get computed style:
                                        ComputedStyle cs = renderData.computedStyle;

                                        // Fix if it isn't already:
                                        if (renderData.FirstBox.PositionMode != PositionMode.Fixed)
                                        {
                                            cs.ChangeTagProperty("position", "fixed");
                                        }

                                        // Get top/left pos:
                                        float left = renderData.FirstBox.X + delta.x;
                                        float top  = renderData.FirstBox.Y + delta.y;

                                        // Write it back out:
                                        cs.ChangeTagProperty("left", new Css.Units.DecimalUnit(left));
                                        cs.ChangeTagProperty("top", new Css.Units.DecimalUnit(top));
                                    }
                                }
                            }
                        }
                    }
                    else if (pointer.DragStatus == InputPointer.SELECTING)
                    {
                        // Update the selection.

                        if (pointer.ActivePressed != null)
                        {
                            DragEvent de = new DragEvent("drag");
                            de.trigger = pointer;
                            de.SetModifiers();
                            de.SetTrusted();
                            de.clientX = pointer.DocumentX;
                            de.clientY = pointer.DocumentY;

                            if (pointer.ActivePressed.dispatchEvent(de))
                            {
                                // Get the current selection:
                                Selection s = (pointer.ActivePressed.document as HtmlDocument).getSelection();

                                // Safety check:
                                if (s.ranges.Count > 0)
                                {
                                    // Get the range:
                                    Range range = s.ranges[0];

                                    // Get text node:
                                    RenderableTextNode htn = (range.startContainer as RenderableTextNode);

                                    if (htn != null)
                                    {
                                        // Get the new end index:
                                        int endIndex = htn.LetterIndex(pointer.DocumentX, pointer.DocumentY);

                                        // Update:
                                        range.endOffset = endIndex;

                                        // Flush:
                                        s.UpdateSelection(true, range);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (pointerRemoved)
            {
                // Tidy the removed ones:
                InputPointer.Tidy();
            }

            // Clear invalidated state:
            PointersInvalid = false;

                        #if MOBILE
            // Handle mobile keyboard:
            if (MobileKeyboard != null)
            {
                HandleMobileKeyboardInput();
            }
                        #endif
        }
Пример #2
0
        /// <summary>Scrolls this scrollbar by the given number of pixels, optionally relative to a fixed point on the bar.
        /// Note that this may fail if the scrollbar cannot scroll any further.</summary>
        /// <param name="pixels">The number of pixels to scroll this bar by.</param>
        /// <param name="fromCurrent">True if pixels is relative to where the thumb currently is. False if pixels is relative
        /// to where the bar was when the mouse was clicked. See e.g. <see cref="PowerUI.VScrollTabTag.StartY"/>.</param>
        /// <param name="scrollTarget">True if the target should also be scrolled.</param>
        public void ScrollBy(float pixels, bool fromCurrent, bool scrollTarget)
        {
            // Scroll it by pixels from Start.
            float newLocation     = pixels;
            float currentPosition = Position;

            LayoutBox box = RenderData.FirstBox;

            if (fromCurrent)
            {
                newLocation += currentPosition;
            }
            else
            {
                newLocation += Start;
            }

            // Get the size of the button before the tab:
            float sizeBefore = StartArrowSize;

            float barSize = BarSize;

            float max = barSize + sizeBefore;

            if (IsVertical)
            {
                max -= box.Height;
            }
            else
            {
                max -= box.Width;
            }

            if (newLocation < sizeBefore)
            {
                newLocation = sizeBefore;
            }
            else if (newLocation > max)
            {
                newLocation = max;
            }

            if (newLocation == currentPosition)
            {
                return;
            }

            if (IsVertical)
            {
                Style.top = newLocation + "fpx";
            }
            else
            {
                Style.left = newLocation + "fpx";
            }

            // Fire a change event on the scrollbar:
            Dom.Event e = new Dom.Event("change");
            e.SetTrusted();
            ScrollBar.dispatchEvent(e);

            if (scrollTarget)
            {
                // Get info for the target:
                HtmlElement   target   = ScrollBar.scrollTarget;
                ComputedStyle targetCs = target.style.Computed;
                box = targetCs.FirstBox;

                if (target != null && box != null)
                {
                    // Get the progress:
                    float progress = (newLocation - sizeBefore) / barSize;

                    // Update CSS:
                    if (IsVertical)
                    {
                        targetCs.ChangeTagProperty("scroll-top", new Css.Units.DecimalUnit(progress * box.ContentHeight));
                    }
                    else
                    {
                        targetCs.ChangeTagProperty("scroll-left", new Css.Units.DecimalUnit(progress * box.ContentWidth));
                    }

                    // And request a redraw:
                    target.htmlDocument.RequestLayout();
                }
            }
        }
Пример #3
0
        /// <summary>Submits this form using the given button. It may override the action etc.</summary>
        public void submit(HtmlElement clickedButton)
        {
            // Generate a nice dictionary of the form contents.

            // Step 1: find the unique names of the elements:
            Dictionary <string, string> uniqueValues = new Dictionary <string, string>();

            // Get submittable elements:
            HTMLFormControlsCollection allInputs = GetAllInputs(InputSearchMode.Submittable);

            foreach (Element element in allInputs)
            {
                if (element is HtmlButtonElement)
                {
                    // No buttons.
                    continue;
                }

                string type = element["type"];
                if (type == "submit")
                {
                    // No submit either.
                    continue;
                }

                string name = element["name"];
                if (name == null)
                {
                    name = "";
                }

                // Step 2: For each one, get their value.
                // We might have a name repeated, in which case we check if they are radio boxes.

                if (uniqueValues.ContainsKey(name))
                {
                    // Ok the element is already added - we have two with the same name.
                    // If they are radio, then only overwrite value if the new addition is checked.
                    // Otherwise, overwrite - furthest down takes priority.
                    if (element.Tag == "input")
                    {
                        HtmlInputElement tag = (HtmlInputElement)element;

                        if (tag.Type == InputType.Radio && !tag.Checked)
                        {
                            // Don't overwrite.
                            continue;
                        }
                    }
                }
                string value = (element as HtmlElement).value;
                if (value == null)
                {
                    value = "";
                }
                uniqueValues[name] = value;
            }

            // Get the action:
            string action = GetOverriden("action", clickedButton);

            FormEvent formData = new FormEvent(uniqueValues);

            formData.SetTrusted(true);
            formData.EventType = "submit";
            // Hook up the form element:
            formData.form = this;

            if (dispatchEvent(formData))
            {
                // Get ready to post now!
                DataPackage package = new DataPackage(action, document.basepath);
                package.AttachForm(formData.ToUnityForm());

                // Apply request to the data:
                formData.request = package;

                // Apply load event:
                package.onload = package.onerror = delegate(UIEvent e){
                    // Attempt to run ondone (doesn't bubble):
                    formData.Reset();
                    formData.EventType = "done";

                    if (dispatchEvent(formData))
                    {
                        // Otherwise the ondone function quit the event.

                        // Load the result into target now.
                        string target = GetOverriden("target", clickedButton);

                        HtmlDocument targetDocument = ResolveTarget(target);

                        if (targetDocument == null)
                        {
                            // Posting a form to an external target.

                            Log.Add("Warning: Unity cannot post forms to external targets. It will be loaded a second time.");

                            // Open the URL outside of Unity:
                            UnityEngine.Application.OpenURL(package.location.absoluteNoHash);
                        }
                        else
                        {
                            // Change the location:
                            targetDocument.SetRawLocation(package.location);

                            // History entry required:
                            targetDocument.window.history.DocumentNavigated();

                            // Apply document content:
                            targetDocument.GotDocumentContent(package.responseText, package.statusCode, true);
                        }
                    }
                };

                // Send now!
                package.send();
            }
        }
        /// <summary>Resolves the given target to a document.</summary>
        /// <returns>The targeted document. Null if there is no document at all and the target is essentially outside of Unity.</returns>
        public HtmlDocument ResolveTarget(string target)
        {
            // Grab the document the element is in:
            HtmlDocument document = htmlDocument;

            if (target == null)
            {
                // No target - does the document define a default one?
                // Note that this is set with the "base" html tag.

                if (document.location != null)
                {
                    target = document.baseTarget;
                }
            }

            // Null target is the same as _self.
            if (string.IsNullOrEmpty(target))
            {
                target = "_self";
            }

            // Grab the window:
            Window window = document.window;

            switch (target)
            {
            case "_blank":

                // Open the given url outside Unity.
                return(null);

            case "_top":
                // Open the given URL at the top window.

                return(window.top.document);

            case "_parent":

                // Open it there:
                return(window.parent.document);

            case "_self":

                // Open it in this document:
                return(document);

            case "_main":

                // Open into the main UI:
                return(UI.document);

            default:
                // Anything else and it's the name of an iframe (preferred) or a WorldUI.

                // Get the element by name:
                HtmlElement iframeElement = document.getElementByAttribute("name", target) as HtmlElement;

                if (iframeElement == null)
                {
                    // WorldUI with this name?
                    WorldUI ui = WorldUI.Find(target);

                    if (ui == null)
                    {
                        // Not found - same as self:
                        return(document);
                    }

                    // Load into the WorldUI:
                    return(ui.document);
                }

                // Great, we have an iframe - grab the content document:
                return(iframeElement.contentDocument);
            }
        }
Пример #5
0
 /// <summary>Adds a dropdown menu option.</summary>
 public void add(HtmlElement element)
 {
     // Just add as a child:
     appendChild(element);
 }