예제 #1
0
        /// <summary>Called when a selection starts using the given input pointer (typically a mouse).</summary>
        public static void BeginSelect(PowerUI.InputPointer pointer, Css.Value mode)
        {
            // Selection starting at the position the pointer started dragging

            // Firstly, resolve our doc coords to a selection range start.

            // Get as first containing child node (should be text or null):
            NodeList kids = pointer.ActivePressed.childNodes_;

            if (kids != null)
            {
                for (int i = 0; i < kids.length; i++)
                {
                    IRenderableNode irn = (kids[i] as IRenderableNode);

                    if (irn != null)
                    {
                        // Contains it?
                        LayoutBox box = irn.RenderData.BoxAt(pointer.DownDocumentX, pointer.DownDocumentY);

                        if (box == null)
                        {
                            // Use the last one:
                            box = irn.RenderData.LastBox;
                        }

                        if (box != null)
                        {
                            // Great! Try it as a text node (should always be one):
                            PowerUI.RenderableTextNode htn = (kids[i] as PowerUI.RenderableTextNode);

                            if (htn != null)
                            {
                                // Awesome - get the letter indices:
                                int startIndex = htn.LetterIndex(pointer.DownDocumentX, box);
                                int endIndex   = htn.LetterIndex(pointer.DocumentX, pointer.DocumentY);

                                // Create a range:
                                Range range = new Range();
                                range.startOffset    = startIndex;
                                range.endOffset      = endIndex;
                                range.startContainer = htn;
                                range.endContainer   = htn;

                                // Get the current selection:
                                Selection s = (kids[i].document as HtmlDocument).getSelection();

                                // Clear all:
                                s.removeAllRanges();

                                // Add range:
                                s.addRange(range);
                            }

                            break;
                        }
                    }
                }
            }
        }
예제 #2
0
        public override void OnClickEvent(MouseEvent clickEvent)
        {
            // Focus it:
            focus();

            if (Type == InputType.Submit)
            {
                // Find the form and then attempt to submit it.
                HtmlFormElement f = form;
                if (f != null)
                {
                    f.submit(this);
                }
            }
            else if (Type == InputType.Radio)
            {
                Select();
            }
            else if (Type == InputType.Checkbox)
            {
                if (Checked_)
                {
                    Unselect();
                }
                else
                {
                    Select();
                }
            }
            else if (IsTextInput())
            {
                // Move the caret to the clicked point.

                // Get the text content:
                RenderableTextNode htn = TextHolder;

                if (htn == null)
                {
                    // Index is just 0.
                    return;
                }

                // Get the letter index:
                int index = htn.LetterIndex(clickEvent.clientX, clickEvent.clientY);

                // Move the caret there (requesting a redraw):
                MoveCaret(index, true);
            }
        }
예제 #3
0
        /// <summary>Gets the next/previous suitable newline index.</summary>
        public int FindNewline(int direction)
        {
            // Get the text content:
            RenderableTextNode htn = TextHolder;

            if (htn == null || htn.RenderData.Text == null || htn.RenderData.Text.Characters == null)
            {
                return(CaretIndex);
            }

            // Get the renderer so we can access the chars:
            TextRenderingProperty trp = htn.RenderData.Text;

            // First index to check is..
            int index = CaretIndex + direction;

            // Safety check:
            int max = trp.Characters.Length;

            if (index >= max)
            {
                index = max - 1;
            }
            else if (index < 0)
            {
                index = 0;
            }

            while (index > 0 && index < max)
            {
                // Check if char[index] is a newline:
                InfiniText.Glyph glyph = trp.Characters[index];

                if (glyph != null && glyph.Charcode == (int)'\n')
                {
                    // Got it!
                    if (direction == 1)
                    {
                        index++;
                    }
                    break;
                }

                // Next one:
                index += direction;
            }

            return(index);
        }
예제 #4
0
        public override void OnClickEvent(MouseEvent clickEvent)
        {
            // Ensure it's focused:
            focus();

            // Get the text content:
            RenderableTextNode htn = TextHolder;

            if (htn == null)
            {
                // Index is just 0.
                return;
            }

            // Get the letter index:
            int index = htn.LetterIndex(clickEvent.clientX, clickEvent.clientY);

            // Move the caret there (requesting a redraw):
            MoveCaret(index, true);
        }
예제 #5
0
        public override void OnComputeBox(Renderman renderer, Css.LayoutBox box, ref bool widthUndefined, ref bool heightUndefined)
        {
            // Locate the caret if we need to:
            if (Locate)
            {
                Locate = false;

                RenderableTextNode htn = TextHolder;
                Vector2            position;

                if (htn == null)
                {
                    // Just at 0,0:
                    position = Vector2.zero;
                }
                else
                {
                    // Clip:
                    if (Index >= htn.length)
                    {
                        Index = htn.length;
                    }

                    // Get the position of the given letter:
                    position = htn.GetPosition(Index);
                }

                // Scroll it if position is out of range:
                ScrollIfBeyond(ref position);

                // Set it in for this pass:
                box.Position.Top  = position.y;
                box.Position.Left = position.x;

                // Write it out:
                Style.Computed.ChangeTagProperty("left", new Css.Units.DecimalUnit(position.x), false);
                Style.Computed.ChangeTagProperty("top", new Css.Units.DecimalUnit(position.y), false);
            }
        }
예제 #6
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){
				
				// 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:
						InputPointer current=InputPointer.AllRaw[p];
						
						if(current.ID==touch.fingerId){
							
							// Got it!
							pointer=current;
							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.ID=touch.fingerId;
						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.Radius=touch.radius;
					tp.RadiusVariance=touch.radiusVariance;
					tp.LatestPressure=touch.pressure;
					
					// Is it a stylus?
					if(tp is StylusPointer){
						tp.UpdateStylus(touch.azimuthAngle,touch.altitudeAngle);
					}
					
					// Always a pressure of 1 otherwise (the 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;
					
					// Clear pressure (mouseup etc):
					pointer.SetPressure(0f);
					
					if(pointer.ActiveOverTarget!=null){
						
						// Shared event:
						MouseEvent mouseEvent=new MouseEvent(pointer.ScreenX,pointer.ScreenY,pointer.ButtonID,false);
						mouseEvent.trigger=pointer;
						mouseEvent.clientX=pointer.DocumentX;
						mouseEvent.clientY=pointer.DocumentY;
						mouseEvent.SetModifiers();
						mouseEvent.SetTrusted();
						
						// Trigger a mouseout (bubbles):
						mouseEvent.EventType="mouseout";
						mouseEvent.SetTrusted();
						pointer.ActiveOverTarget.dispatchEvent(mouseEvent);
						
						// And a mouseleave (doesn't bubble).
						mouseEvent.Reset();
						mouseEvent.bubbles=false;
						mouseEvent.EventType="mouseleave";
						pointer.ActiveOverTarget.dispatchEvent(mouseEvent);
						
						// Update the CSS (hover; typically out):
						IRenderableNode irn = (pointer.ActiveOverTarget as IRenderableNode);
						
						if(irn!=null){
							irn.ComputedStyle.RefreshLocal(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;
					EventTarget newActiveOver=TargetFromPoint(ref documentX,ref documentY,pointer);
					
					// Update docX/Y:
					pointer.DocumentX=documentX;
					pointer.DocumentY=documentY;
					
					// Get the old one:
					EventTarget oldActiveOver=pointer.ActiveOverTarget;
					
					// 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.eventTargetParentNode!=newActiveOver){
								mouseEvent.Reset();
								mouseEvent.bubbles=false;
								mouseEvent.EventType="mouseleave";
								mouseEvent.relatedTarget=newActiveOver;
								oldActiveOver.dispatchEvent(mouseEvent);
							}
							
						}
						
						// Update it:
						pointer.ActiveOverTarget=newActiveOver;
						
						if(oldActiveOver!=null){
							// Update the CSS (hover; typically out):
							IRenderableNode irn = (oldActiveOver as IRenderableNode);
							
							if(irn!=null){
								irn.ComputedStyle.RefreshLocal(true);
							}
						}
						
						if(newActiveOver!=null){
							// Update the CSS (hover; typically in)
							IRenderableNode irn = (newActiveOver as IRenderableNode);
							
							if(irn!=null){
								irn.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.getTitle();
							
							// And a mouseenter (doesn't bubble).
							// Only triggered if newActiveOver is *not* a child of oldActiveOver.
							if(newActiveOver.eventTargetParentNode!=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);
					
					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.ActivePressedTarget==null){
							
							// Trigger on unhandled:
							Unhandled.dispatchEvent(te);
							
						}else{
						
							pointer.ActivePressedTarget.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.ActiveUpdatingTarget=GetDraggable(pointer.ActivePressedTarget as Element);
							
							// Find the min drag distance:
							pointer.MinDragDistance=pointer.GetMinDragDistance();
							
						}
						
						if(pointer.MovedBeyondDragDistance){
							
							// Possibly dragging.
							
							// Actually marked as 'draggable'?
							if(pointer.ActiveUpdatingTarget!=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.ActivePressedTarget.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?
								IRenderableNode irn = (pointer.ActivePressedTarget as IRenderableNode);
								
								if(irn!=null){
									// It's renderable; can it be selected?
									ComputedStyle cs=irn.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.ActivePressedTarget 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.ActivePressedTarget!=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.ActivePressedTarget.dispatchEvent(de)){
								
								// Note that onDrag runs on the *dragging* element only.
								Element dragging;
								
								if(pointer.ActiveUpdatingTarget==null){
									dragging = (Element)pointer.ActivePressedTarget;
								}else{
									dragging = (Element)pointer.ActiveUpdatingTarget;
								}
								
								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.ActivePressedTarget!=null){
							
							DragEvent de=new DragEvent("drag");
							de.trigger=pointer;
							de.SetModifiers();
							de.SetTrusted();
							de.clientX=pointer.DocumentX;
							de.clientY=pointer.DocumentY;
							
							if(pointer.ActivePressedTarget.dispatchEvent(de)){
								
								// We can only select elements:
								Element pressedElement = (Element)pointer.ActivePressedTarget;
								
								// Get the current selection:
								Selection s=(pressedElement.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
			
		}
예제 #7
0
        /// <summary>Selects/ Deselects a whole range.</summary>
        internal void UpdateSelection(bool select, Range r)
        {
            if (r.startContainer == null)
            {
                return;
            }

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

            if (htn == null)
            {
                // Can't select this at the moment.
                Dom.Log.Add("Note: Attempted to select something that isn't text. If you want this to work, let us know!");
                return;
            }

            // Text selection from r.startOffset -> r.endOffset

            // Get the selection renderer:
            SelectionRenderingProperty srp = htn.RenderData.GetProperty(
                typeof(SelectionRenderingProperty)
                ) as SelectionRenderingProperty;

            if (select)
            {
                // Create if it doesn't exist:
                if (srp == null)
                {
                    // Create:
                    srp      = new SelectionRenderingProperty(htn.RenderData);
                    srp.Text = htn.RenderData.Text;

                    // Add it:
                    htn.RenderData.AddOrReplaceProperty(srp, typeof(SelectionRenderingProperty));
                }

                // Update range:
                if (r.endOffset < r.startOffset)
                {
                    // Dragged upwards:
                    srp.StartIndex = r.endOffset;
                    srp.EndIndex   = r.startOffset;
                }
                else
                {
                    srp.StartIndex = r.startOffset;
                    srp.EndIndex   = r.endOffset;
                }

                // Layout:
                srp.RequestLayout();
            }
            else if (srp != null)
            {
                // Remove:
                htn.RenderData.AddOrReplaceProperty(null, typeof(SelectionRenderingProperty));

                // Layout:
                srp.RequestLayout();
            }
        }