void HandlePendingEvents(Rect Canvas, List <DataStreamMeta> Streams) { System.Func <Vector2, TimeUnit?> CanvasPositionToTime = (Position) => { return(PositionToTime(Canvas, Position)); }; System.Func <Vector2, StreamAndTime> CanvasPositionToStreamAndTime = (Position) => { int?StreamIndex; var Time = PositionToTime(Canvas, Position, Streams, out StreamIndex); return(new StreamAndTime(Streams[StreamIndex.Value], Time.Value)); }; Input.ProcessScroll((ScrollTime) => { ScrollTimeLeft.Time += ScrollTime.Time; StickyScroll = false; }); Input.ProcessSelect(CanvasPositionToTime, (SelectTime) => { LastStickySelectTime = null; if (SelectTime.HasValue) { OnSelectTime(SelectTime.Value); } }); Input.ProcessHover(CanvasPositionToTime, (HoverTime) => { OnMouseHover(HoverTime); }); if (Input.MouseDragCurrentPosition.HasValue) { // new drag if (CurrentDrag == null) { CurrentDrag = new DragMeta(); CurrentDrag.DragAmount = new TimeUnit(0); CurrentDrag.GrabTime = PositionToTime(Canvas, Input.MouseDragCurrentPosition.Value, Streams, out CurrentDrag.StreamIndex); // check is draggable CurrentDrag.Draggable = false; try { var Stream = Streams[CurrentDrag.StreamIndex.Value]; CurrentDrag.Draggable = Stream.Draggable; } catch { CurrentDrag.Draggable = false; } } else { if (CurrentDrag.Draggable) { // update drag var NewDragTime = PositionToTime(Canvas, Input.MouseDragCurrentPosition.Value); if (CurrentDrag.GrabTime.HasValue && NewDragTime.HasValue) { CurrentDrag.DragAmount = new TimeUnit(NewDragTime.Value.Time - CurrentDrag.GrabTime.Value.Time); } } } Input.MouseDragCurrentPosition = null; } // drag released if (Input.MouseDragEndPosition.HasValue) { // invoke the drag try { var Stream = Streams[CurrentDrag.StreamIndex.Value]; if (Stream.OnDragged != null) { Stream.OnDragged(CurrentDrag.GrabTime.Value, CurrentDrag.DragAmount); } } catch (System.Exception e) { Debug.LogException(e); } CurrentDrag = null; Input.MouseDragEndPosition = null; } if (Input.MouseJumpPrevPos.HasValue) { try { int?StreamIndex; var JumpFromTime = PositionToTime(Canvas, Input.MouseJumpPrevPos.Value, Streams, out StreamIndex); // get prev pos in stream var PrevItemTime = new TimeUnit(JumpFromTime.Value.Time - 1); var PrevItem = Bridge.GetNearestOrPrevStreamData(Streams[StreamIndex.Value], ref PrevItemTime); // want the item to appear under mouse (where we clicked) var ScrollOffset = JumpFromTime.Value.Time - ScrollTimeLeft.Time; var PrevTimeLeft = PrevItemTime.Time - ScrollOffset; ScrollTimeLeft = new TimeUnit(PrevTimeLeft); } catch (System.Exception) { // probably no more data EditorApplication.Beep(); //Debug.LogException(e); } finally { Input.MouseJumpPrevPos = null; } } if (Input.MouseJumpNextPos.HasValue) { try { int?StreamIndex; var JumpFromTime = PositionToTime(Canvas, Input.MouseJumpNextPos.Value, Streams, out StreamIndex); var NextItemTime = new TimeUnit(JumpFromTime.Value.Time + 1); var NextItem = Bridge.GetNearestOrNextStreamData(Streams[StreamIndex.Value], ref NextItemTime); // want the item to appear under mouse (where we clicked) var ScrollOffset = JumpFromTime.Value.Time - ScrollTimeLeft.Time; var NextTimeLeft = NextItemTime.Time - ScrollOffset; ScrollTimeLeft = new TimeUnit(NextTimeLeft); } catch (System.Exception) { // probably no more data EditorApplication.Beep(); //Debug.LogException(e); } finally { Input.MouseJumpNextPos = null; } } Input.ProcessMenuClick(CanvasPositionToStreamAndTime, (StreamAndTime) => { if (StreamAndTime.Stream.OnCreateContextMenu == null) { EditorApplication.Beep(); return; } // create the menu and add items to it var Menu = new GenericMenu(); EnumCommand AppendMenuItem = (Label, Lambda) => { if (string.IsNullOrEmpty(Label) || Label.EndsWith("-")) { // todo; use path Menu.AddSeparator(null); } else if (Lambda == null) { Menu.AddDisabledItem(new GUIContent(Label)); } else { // argh damned delegates GenericMenu.MenuFunction Callback = () => { Lambda(); }; Menu.AddItem(new GUIContent(Label), false, Callback); } }; StreamAndTime.Stream.OnCreateContextMenu(StreamAndTime.Time, AppendMenuItem); Menu.ShowAsContext(); }); }
public void Draw(Rect CanvasRect, TimeUnit LeftTime, TimeUnit RightTime, TimeUnit?SelectedTime, TimeUnit?HoverTime, DataBridge Data, List <DataStreamMeta> Streams, DragMeta DragMeta) { EditorGUI.DrawRect(CanvasRect, CanvasBackgroundColour); //DrawWholeView (Canvas, LeftTime, RightTime, Data); var StreamRects = new Rect[Streams.Count]; for (int s = 0; s < Streams.Count; s++) { var st0 = (s + 0) / (float)Streams.Count; var st1 = (s + 1) / (float)Streams.Count; var StreamBorder = 1; var Top = Mathf.Lerp(CanvasRect.min.y + StreamBorder, CanvasRect.max.y, st0); var Bot = Mathf.Lerp(CanvasRect.min.y + StreamBorder, CanvasRect.max.y, st1) - StreamBorder; var Left = CanvasRect.min.x + StreamBorder; var Right = CanvasRect.max.x - StreamBorder; var StreamRect = new Rect(Left, Top, Right - Left, Bot - Top); StreamRects [s] = StreamRect; } var DrawCap = MaxDataDraws; Rect?FirstSelectionRect = null; // draw streams for (int s = 0; s < Streams.Count; s++) { var StreamRect = StreamRects [s]; var Stream = Streams [s]; EditorGUI.DrawRect(StreamRect, StreamBackgroundColour); var StreamColour = Stream.Colour; // get all the data in the visible region var StreamDatas = Data.GetStreamData(Stream, LeftTime, RightTime); var StreamDataRect = new Rect(0, 0, 1, 1); var MinWidthPx = 1; System.Func <TimeUnit, TimeUnit, Color, DataState, Rect> DrawMarker = (DataTimeLeft, DataTimeRight, Colour, State) => { var LeftNorm = GetTimeNormalised(LeftTime, RightTime, DataTimeLeft); var RightNorm = GetTimeNormalised(LeftTime, RightTime, DataTimeRight); StreamDataRect.x = LeftNorm; StreamDataRect.width = RightNorm - LeftNorm; var DrawStreamDataRect = PopMath.RectMult(StreamDataRect, StreamRect); DrawStreamDataRect.width = Mathf.Max(MinWidthPx, DrawStreamDataRect.width); if (DrawStreamDataRect.width <= 2.0f) { DrawStreamDataRect.width = MinWidthPx; } // giant rects kill performance (CPU renderer??) DrawStreamDataRect = DrawStreamDataRect.ClipToParent(StreamRect); if (State == DataState.Loaded) { EditorGUI.DrawRect(DrawStreamDataRect, Colour); } else { var StripeHeight = 2; int i = 0; var yoffset = (DrawStreamDataRect.height % StripeHeight) - (StripeHeight / 2.0f); for (var y = 0; y < DrawStreamDataRect.height + StripeHeight; y += StripeHeight, i++) { if (i % 3 == 2) { continue; } var Rect = DrawStreamDataRect; Rect.y = y + yoffset + DrawStreamDataRect.yMin; Rect.height = StripeHeight; // clip if (Rect.yMin > DrawStreamDataRect.yMax) { continue; } Rect.yMin = Mathf.Max(Rect.yMin, DrawStreamDataRect.yMin); Rect.yMax = Mathf.Min(Rect.yMax, DrawStreamDataRect.yMax); EditorGUI.DrawRect(Rect, Colour); } } return(DrawStreamDataRect); }; System.Func <TimeUnit, TimeUnit, Color, DataState, Rect> DrawData = (DataTimeLeft, DataTimeRight, Colour, State) => { var DrawStreamDataRect = DrawMarker(DataTimeLeft, DataTimeRight, Colour, State); // put some notches in long data // gr: correct the notches for the clipping change // gr: also, on mega long data, this causes a giant loop. start & end at nearest (also fixes above) var DurationMs = DataTimeRight.Time - DataTimeLeft.Time; var MaxLoopDuration = 10000; var NotchStep = Stream.NotchStepMs.HasValue ? Stream.NotchStepMs.Value : DurationMs; for (int NotchMs = NotchStep; NotchMs < DurationMs && DurationMs < MaxLoopDuration; NotchMs += NotchStep) { var LeftNorm = GetTimeNormalised(LeftTime, RightTime, new TimeUnit(DataTimeLeft.Time + NotchMs)); //var RightNorm = LeftNorm; StreamDataRect.x = LeftNorm; StreamDataRect.width = 0; var NotchDrawStreamDataRect = PopMath.RectMult(StreamDataRect, StreamRect); NotchDrawStreamDataRect.width = MinWidthPx; NotchDrawStreamDataRect = NotchDrawStreamDataRect.ClipToParent(StreamRect); EditorGUI.DrawRect(NotchDrawStreamDataRect, BlockNotchColour); } // change cursor if this is draggable if (Stream.Draggable) { EditorGUIUtility.AddCursorRect(DrawStreamDataRect, MouseCursor.Pan); } return(DrawStreamDataRect); }; System.Func <TimeUnit, Color, Rect> DrawLine = (DataTimeLeft, Colour) => { var SelectedTimeDuration = 16; var DataTimeRight = new TimeUnit(DataTimeLeft.Time + SelectedTimeDuration); return(DrawMarker(DataTimeLeft, DataTimeRight, Colour, DataState.Loaded)); }; // draw hover underneath if (HoverTime.HasValue) { var SelectedTimeLeft = HoverTime.Value; DrawLine(SelectedTimeLeft, HoverColour); } foreach (var StreamData in StreamDatas) { if (DrawCap-- <= 0) { break; } DrawData(StreamData.GetStartTime(), StreamData.GetEndTime(), StreamColour, StreamData.GetStatus()); // draw again offset by drag if (DragMeta != null && DragMeta.Draggable && DragMeta.StreamIndex == s) { var DraggedStartTime = new TimeUnit(StreamData.GetStartTime().Time + DragMeta.DragAmount.Time); var DraggedEndTime = new TimeUnit(StreamData.GetEndTime().Time + DragMeta.DragAmount.Time); DrawData(DraggedStartTime, DraggedEndTime, DragColour, StreamData.GetStatus()); } } // draw selection over the top if (SelectedTime.HasValue) { var SelectedTimeLeft = SelectedTime.Value; var Rect = DrawLine(SelectedTimeLeft, SelectionColour); if (!FirstSelectionRect.HasValue) { FirstSelectionRect = Rect; } } // draw text over that var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.LowerLeft; LabelStyle.fontStyle = StreamLabelFontStyle; LabelStyle.normal.textColor = StreamLabelColour; EditorGUI.DropShadowLabel(StreamRect, Stream.Name, LabelStyle); } // draw time labels { var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.UpperLeft; LabelStyle.fontStyle = TimeLabelFontStyle; LabelStyle.normal.textColor = TimeLabelColour; EditorGUI.DropShadowLabel(CanvasRect, "|< " + LeftTime.GetLabel(false), LabelStyle); } { var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.UpperRight; LabelStyle.fontStyle = TimeLabelFontStyle; LabelStyle.normal.textColor = TimeLabelColour; EditorGUI.DropShadowLabel(CanvasRect, RightTime.GetLabel(false) + " >|", LabelStyle); } if (SelectedTime.HasValue && FirstSelectionRect.HasValue) { var LabelStyle = new GUIStyle(); LabelStyle.alignment = TextAnchor.UpperLeft; LabelStyle.fontStyle = SelectedTimeLabelFontStyle; LabelStyle.normal.textColor = SelectedTimeLabelColour; var Label = "\n<<" + SelectedTime.Value.GetLabel(true); EditorGUI.DropShadowLabel(FirstSelectionRect.Value, Label, LabelStyle); } if (DrawCap <= 0) { Debug.Log("Exceeded draw cap"); } }