public bool DoTimeline(Rect timeRect) { bool hasModifiedData = false; Init(); m_Rect = timeRect; float timeAreaStart = m_TimeArea.PixelToTime(timeRect.xMin, timeRect); float timeAreaStop = m_TimeArea.PixelToTime(timeRect.xMax, timeRect); if (!Mathf.Approximately(timeAreaStart, StartTime)) { StartTime = timeAreaStart; GUI.changed = true; } if (!Mathf.Approximately(timeAreaStop, StopTime)) { StopTime = timeAreaStop; GUI.changed = true; } Time = Mathf.Max(Time, 0f); if (Event.current.type == EventType.Repaint) { m_TimeArea.rect = timeRect; } m_TimeArea.BeginViewGUI(); m_TimeArea.EndViewGUI(); GUI.BeginGroup(timeRect); { Event evt = Event.current; Rect r = new Rect(0, 0, timeRect.width, timeRect.height); Rect headerRect = new Rect(0, 0, timeRect.width, 18); Rect bodyRect = new Rect(0, 18, timeRect.width, 132); // get the relevant positions in pixels float srcStart = m_TimeArea.TimeToPixel(SrcStartTime, r); float srcStop = m_TimeArea.TimeToPixel(SrcStopTime, r); float dstStart = m_TimeArea.TimeToPixel(DstStartTime, r) + m_DstDragOffset; float dstStop = m_TimeArea.TimeToPixel(DstStopTime, r) + m_DstDragOffset; float transStart = m_TimeArea.TimeToPixel(TransitionStartTime, r) + m_LeftThumbOffset; float transStop = m_TimeArea.TimeToPixel(TransitionStopTime, r) + m_RightThumbOffset; float playPoint = m_TimeArea.TimeToPixel(Time, r); // get the relevant Rects Rect srcRect = new Rect(srcStart, 85, srcStop - srcStart, 32); Rect dstRect = new Rect(dstStart, 117, dstStop - dstStart, 32); Rect transHeaderRect = new Rect(transStart, 0, transStop - transStart, 18); Rect transRect = new Rect(transStart, 18, transStop - transStart, r.height - 18); Rect leftThumbRect = new Rect(transStart - 9, 5, 9, 15); Rect rightThumbRect = new Rect(transStop, 5, 9, 15); Rect playHeadRect = new Rect(playPoint - 7, 4, 15, 15); // handle keyboard if (evt.type == EventType.KeyDown) { if (EditorGUIUtility.keyboardControl == id) { if (m_DragState == DragStates.Destination) { m_DstDragOffset = 0f; } } if (m_DragState == DragStates.LeftSelection) { m_LeftThumbOffset = 0f; } if (m_DragState == DragStates.RightSelection) { m_RightThumbOffset = 0f; } if (m_DragState == DragStates.Playhead) { m_TimeOffset = 0f; } if (m_DragState == DragStates.FullSelection) { m_LeftThumbOffset = 0f; m_RightThumbOffset = 0f; } } // handle mouse down if (evt.type == EventType.MouseDown) { if (r.Contains(evt.mousePosition)) { EditorGUIUtility.hotControl = id; EditorGUIUtility.keyboardControl = id; if (playHeadRect.Contains(evt.mousePosition)) { m_DragState = DragStates.Playhead; m_TimeStartDrag = m_TimeArea.TimeToPixel(Time, r); } else if (srcRect.Contains(evt.mousePosition)) { m_DragState = DragStates.Source; } else if (dstRect.Contains(evt.mousePosition)) { m_DragState = DragStates.Destination; } else if (leftThumbRect.Contains(evt.mousePosition)) { m_DragState = DragStates.LeftSelection; } else if (rightThumbRect.Contains(evt.mousePosition)) { m_DragState = DragStates.RightSelection; } else if (transHeaderRect.Contains(evt.mousePosition)) { m_DragState = DragStates.FullSelection; } else if (headerRect.Contains(evt.mousePosition)) { m_DragState = DragStates.TimeArea; } else if (bodyRect.Contains(evt.mousePosition)) { m_DragState = DragStates.TimeArea; } else { m_DragState = DragStates.None; } evt.Use(); } } // handle mouse drag if (evt.type == EventType.MouseDrag) { if (EditorGUIUtility.hotControl == id) { switch (m_DragState) { case DragStates.Source: case DragStates.TimeArea: m_TimeArea.m_Translation.x += evt.delta.x; break; case DragStates.Destination: m_DstDragOffset += evt.delta.x; EnforceConstraints(); break; case DragStates.LeftSelection: // clamp the delta when off range if ((evt.delta.x > 0 && evt.mousePosition.x > srcStart) || (evt.delta.x < 0 && evt.mousePosition.x < transStop)) { m_LeftThumbOffset += evt.delta.x; } EnforceConstraints(); break; case DragStates.RightSelection: // clamp the delta when off range if (evt.delta.x > 0 && evt.mousePosition.x > transStart || evt.delta.x < 0) { m_RightThumbOffset += evt.delta.x; } EnforceConstraints(); break; case DragStates.FullSelection: m_RightThumbOffset += evt.delta.x; m_LeftThumbOffset += evt.delta.x; EnforceConstraints(); break; case DragStates.Playhead: if ((evt.delta.x > 0 && evt.mousePosition.x > srcStart) || (evt.delta.x < 0 && evt.mousePosition.x <= m_TimeArea.TimeToPixel(SampleStopTime, r))) { m_TimeOffset += evt.delta.x; } Time = m_TimeArea.PixelToTime(m_TimeStartDrag + m_TimeOffset, r); break; case DragStates.None: break; } evt.Use(); GUI.changed = true; } } // handle mouse up both when it happens over the control area and outside control area (case 834214) if (Event.current.GetTypeForControl(id) == EventType.MouseUp) { SrcStartTime = m_TimeArea.PixelToTime(srcStart, r); SrcStopTime = m_TimeArea.PixelToTime(srcStop, r); DstStartTime = m_TimeArea.PixelToTime(dstStart, r); DstStopTime = m_TimeArea.PixelToTime(dstStop, r); TransitionStartTime = m_TimeArea.PixelToTime(transStart, r); TransitionStopTime = m_TimeArea.PixelToTime(transStop, r); GUI.changed = true; m_DragState = DragStates.None; hasModifiedData = WasDraggingData(); m_LeftThumbOffset = 0f; m_RightThumbOffset = 0f; m_TimeOffset = 0f; m_DstDragOffset = 0f; EditorGUIUtility.hotControl = 0; evt.Use(); } // draw the background boxes GUI.Box(headerRect, GUIContent.none, styles.header); GUI.Box(bodyRect, GUIContent.none, styles.background); // draw ticks and curves on top of background boxes m_TimeArea.DrawMajorTicks(bodyRect, 30); GUIContent srcContent = EditorGUIUtility.TempContent(SrcName); // draw src Loop int srcLoopCount = srcLoop ? (1 + (int)((transStop - srcRect.xMin) / (srcRect.xMax - srcRect.xMin))) : 1; Rect loopRect = srcRect; if (srcRect.width < 10) // if smaller than 10 pixel, group { loopRect = new Rect(srcRect.x, srcRect.y, (srcRect.xMax - srcRect.xMin) * srcLoopCount, srcRect.height); srcLoopCount = 1; } for (int loopSrcIt = 0; loopSrcIt < srcLoopCount; loopSrcIt++) { GUI.BeginGroup(loopRect, GUIContent.none, styles.leftBlock); float widthBefore = transStart - loopRect.xMin; float widthDuring = transStop - transStart; float widthAfter = (loopRect.xMax - loopRect.xMin) - (widthBefore + widthDuring); if (widthBefore > 0) { GUI.Box(new Rect(0, 0, widthBefore, srcRect.height), GUIContent.none, styles.onLeft); } if (widthDuring > 0) { GUI.Box(new Rect(widthBefore, 0, widthDuring, srcRect.height), GUIContent.none, styles.onOff); } if (widthAfter > 0) { GUI.Box(new Rect(widthBefore + widthDuring, 0, widthAfter, srcRect.height), GUIContent.none, styles.offRight); } float srcAlphaTarget = 1f; float srcLabelRight = styles.block.CalcSize(srcContent).x; float srcPercentLeft = Mathf.Max(0, widthBefore) - 20; float srcPercentRight = srcPercentLeft + 15; if (srcPercentLeft < srcLabelRight && srcPercentRight > 0f && m_DragState == DragStates.LeftSelection) { srcAlphaTarget = 0f; } GUI.EndGroup(); float srcAlpha = styles.leftBlock.normal.textColor.a; if (!Mathf.Approximately(srcAlpha, srcAlphaTarget) && Event.current.type == EventType.Repaint) { srcAlpha = Mathf.Lerp(srcAlpha, srcAlphaTarget, 0.1f); styles.leftBlock.normal.textColor = new Color(styles.leftBlock.normal.textColor.r, styles.leftBlock.normal.textColor.g, styles.leftBlock.normal.textColor.b, srcAlpha); HandleUtility.Repaint(); } GUI.Box(loopRect, srcContent, styles.leftBlock); loopRect = new Rect(loopRect.xMax, 85, loopRect.xMax - loopRect.xMin, 32); } GUIContent dstContent = EditorGUIUtility.TempContent(DstName); int dstLoopCount = dstLoop ? (1 + (int)((transStop - dstRect.xMin) / (dstRect.xMax - dstRect.xMin))) : 1; loopRect = dstRect; if (dstRect.width < 10) // if smaller than 10 pixel, group { loopRect = new Rect(dstRect.x, dstRect.y, (dstRect.xMax - dstRect.xMin) * dstLoopCount, dstRect.height); dstLoopCount = 1; } for (int loopDstIt = 0; loopDstIt < dstLoopCount; loopDstIt++) { // draw the DST box GUI.BeginGroup(loopRect, GUIContent.none, styles.rightBlock); float widthBefore = transStart - loopRect.xMin; float widthDuring = transStop - transStart; float widthAfter = (loopRect.xMax - loopRect.xMin) - (widthBefore + widthDuring); if (widthBefore > 0) { GUI.Box(new Rect(0, 0, widthBefore, dstRect.height), GUIContent.none, styles.offLeft); } if (widthDuring > 0) { GUI.Box(new Rect(widthBefore, 0, widthDuring, dstRect.height), GUIContent.none, styles.offOn); } if (widthAfter > 0) { GUI.Box(new Rect(widthBefore + widthDuring, 0, widthAfter, dstRect.height), GUIContent.none, styles.onRight); } float dstAlphaTarget = 1f; float dstLabelRight = styles.block.CalcSize(dstContent).x; float dstPercentLeft = Mathf.Max(0, widthBefore) - 20; float dstPercentRight = dstPercentLeft + 15; if (dstPercentLeft < dstLabelRight && dstPercentRight > 0f && (m_DragState == DragStates.LeftSelection || m_DragState == DragStates.Destination)) { dstAlphaTarget = 0f; } GUI.EndGroup(); float dstAlpha = styles.rightBlock.normal.textColor.a; if (!Mathf.Approximately(dstAlpha, dstAlphaTarget) && Event.current.type == EventType.Repaint) { dstAlpha = Mathf.Lerp(dstAlpha, dstAlphaTarget, 0.1f); styles.rightBlock.normal.textColor = new Color(styles.rightBlock.normal.textColor.r, styles.rightBlock.normal.textColor.g, styles.rightBlock.normal.textColor.b, dstAlpha); HandleUtility.Repaint(); } GUI.Box(loopRect, dstContent, styles.rightBlock); loopRect = new Rect(loopRect.xMax, loopRect.yMin, loopRect.xMax - loopRect.xMin, 32); } // draw the transition selection box in the body GUI.Box(transRect, GUIContent.none, styles.select); // draw the transition selection box in the header GUI.Box(transHeaderRect, GUIContent.none, styles.selectHead); m_TimeArea.TimeRuler(headerRect, 30); // draw the thumbs GUI.Box(leftThumbRect, GUIContent.none, (m_HasExitTime) ? styles.handLeft : styles.handLeftPrev); GUI.Box(rightThumbRect, GUIContent.none, styles.handRight); // playhead and bar GUI.Box(playHeadRect, GUIContent.none, styles.playhead); Color oldColor = Handles.color; Handles.color = Color.white; Handles.DrawLine(new Vector3(playPoint, 19, 0), new Vector3(playPoint, r.height, 0)); Handles.color = oldColor; bool oneFrameSrc = (SrcStopTime - SrcStartTime) < 1.0f / 30.0f; bool oneFrameDst = (DstStopTime - DstStartTime) < 1.0f / 30.0f; // show normalized time label when moving destination state if (m_DragState == DragStates.Destination && !oneFrameDst) { Rect transLabelRect = new Rect(transStart - 50, dstRect.y, 45, dstRect.height); string transLabel = String.Format("{0:0%}", (transStart - dstStart) / (dstStop - dstStart)); GUI.Box(transLabelRect, EditorGUIUtility.TempContent(transLabel), styles.timeBlockRight); } // show normalized time label on left side when moving left edge of transition if (m_DragState == DragStates.LeftSelection) { if (!oneFrameSrc) { Rect srcLabelRect = new Rect(transStart - 50, srcRect.y, 45, srcRect.height); string srcLabel = String.Format("{0:0%}", (transStart - srcStart) / (srcStop - srcStart)); GUI.Box(srcLabelRect, EditorGUIUtility.TempContent(srcLabel), styles.timeBlockRight); } if (!oneFrameDst) { Rect dstLabelRect = new Rect(transStart - 50, dstRect.y, 45, dstRect.height); string dstLabel = String.Format("{0:0%}", (transStart - dstStart) / (dstStop - dstStart)); GUI.Box(dstLabelRect, EditorGUIUtility.TempContent(dstLabel), styles.timeBlockRight); } } // show normalized time label on right side when moving right edge of transition if (m_DragState == DragStates.RightSelection) { if (!oneFrameSrc) { Rect srcLabelRect = new Rect(transStop + 5, srcRect.y, 45, srcRect.height); string srcLabel = String.Format("{0:0%}", (transStop - srcStart) / (srcStop - srcStart)); GUI.Box(srcLabelRect, EditorGUIUtility.TempContent(srcLabel), styles.timeBlockLeft); } if (!oneFrameDst) { Rect dstLabelRect = new Rect(transStop + 5, dstRect.y, 45, dstRect.height); string dstLabel = String.Format("{0:0%}", (transStop - dstStart) / (dstStop - dstStart)); GUI.Box(dstLabelRect, EditorGUIUtility.TempContent(dstLabel), styles.timeBlockLeft); } } DoPivotCurves(); } GUI.EndGroup(); return(hasModifiedData); }