private void DrawBars(Rect r, int frameIndex) { ProfilerFrameDataIterator profilerFrameDataIterator = new ProfilerFrameDataIterator(); profilerFrameDataIterator.SetRoot(frameIndex, 0); int threadCount = profilerFrameDataIterator.GetThreadCount(frameIndex); if (Event.current.type == EventType.Repaint) { for (int i = 0; i < threadCount; i++) { profilerFrameDataIterator.SetRoot(frameIndex, i); float threadY = this.GetThreadY(r, i, threadCount); float height = this.GetThreadY(r, i + 1, threadCount) - threadY; Rect position = new Rect(r.x - 170f, threadY, 170f, height); Rect position2 = new Rect(r.x, threadY, r.width, height); ProfilerTimelineGUI.styles.rightPane.Draw(position2, false, false, false, false); ProfilerTimelineGUI.styles.leftPane.Draw(position, GUIContent.Temp(profilerFrameDataIterator.GetThreadName()), false, false, false, false); } } }
private void CalculateBars(Rect r, int frameIndex, float time) { ProfilerFrameDataIterator frameDataIterator = new ProfilerFrameDataIterator(); int groupCount = frameDataIterator.GetGroupCount(frameIndex); float num1 = 0.0f; frameDataIterator.SetRoot(frameIndex, 0); int threadCount = frameDataIterator.GetThreadCount(frameIndex); // ISSUE: object of a compiler-generated type is created // ISSUE: variable of a compiler-generated type ProfilerTimelineGUI.\u003CCalculateBars\u003Ec__AnonStoreyAD barsCAnonStoreyAd = new ProfilerTimelineGUI.\u003CCalculateBars\u003Ec__AnonStoreyAD(); // ISSUE: reference to a compiler-generated field // ISSUE: reference to a compiler-generated field // ISSUE: reference to a compiler-generated field // ISSUE: reference to a compiler-generated field for (barsCAnonStoreyAd.i = 0; barsCAnonStoreyAd.i < threadCount; barsCAnonStoreyAd.i = barsCAnonStoreyAd.i + 1) { // ISSUE: object of a compiler-generated type is created // ISSUE: variable of a compiler-generated type ProfilerTimelineGUI.\u003CCalculateBars\u003Ec__AnonStoreyAC barsCAnonStoreyAc = new ProfilerTimelineGUI.\u003CCalculateBars\u003Ec__AnonStoreyAC(); // ISSUE: reference to a compiler-generated field barsCAnonStoreyAc.\u003C\u003Ef__ref\u0024173 = barsCAnonStoreyAd; // ISSUE: reference to a compiler-generated field frameDataIterator.SetRoot(frameIndex, barsCAnonStoreyAd.i); // ISSUE: reference to a compiler-generated field barsCAnonStoreyAc.groupname = frameDataIterator.GetGroupName(); // ISSUE: reference to a compiler-generated method ProfilerTimelineGUI.GroupInfo groupInfo = this.groups.Find(new Predicate<ProfilerTimelineGUI.GroupInfo>(barsCAnonStoreyAc.\u003C\u003Em__1F5)); if (groupInfo == null) { groupInfo = new ProfilerTimelineGUI.GroupInfo(); // ISSUE: reference to a compiler-generated field groupInfo.name = barsCAnonStoreyAc.groupname; groupInfo.height = 20f; groupInfo.expanded = false; groupInfo.threads = new List<ProfilerTimelineGUI.ThreadInfo>(); this.groups.Add(groupInfo); // ISSUE: reference to a compiler-generated field // ISSUE: reference to a compiler-generated field if (barsCAnonStoreyAc.groupname == string.Empty || barsCAnonStoreyAc.groupname == "Unity Job System") groupInfo.expanded = true; } // ISSUE: reference to a compiler-generated method ProfilerTimelineGUI.ThreadInfo threadInfo1 = groupInfo.threads.Find(new Predicate<ProfilerTimelineGUI.ThreadInfo>(barsCAnonStoreyAc.\u003C\u003Em__1F6)); if (threadInfo1 == null) { threadInfo1 = new ProfilerTimelineGUI.ThreadInfo(); threadInfo1.name = frameDataIterator.GetThreadName(); threadInfo1.height = 0.0f; ProfilerTimelineGUI.ThreadInfo threadInfo2 = threadInfo1; ProfilerTimelineGUI.ThreadInfo threadInfo3 = threadInfo1; int num2 = !groupInfo.expanded ? 0 : 1; double num3; float num4 = (float) (num3 = (double) num2); threadInfo3.desiredWeight = (float) num3; double num5 = (double) num4; threadInfo2.weight = (float) num5; // ISSUE: reference to a compiler-generated field threadInfo1.threadIndex = barsCAnonStoreyAd.i; groupInfo.threads.Add(threadInfo1); } if ((double) threadInfo1.weight != (double) threadInfo1.desiredWeight) threadInfo1.weight = (float) ((double) threadInfo1.desiredWeight * (double) time + (1.0 - (double) threadInfo1.desiredWeight) * (1.0 - (double) time)); num1 += threadInfo1.weight; } float num6 = 16f * (float) groupCount; float num7 = (r.height - num6) / (num1 + 2f); using (List<ProfilerTimelineGUI.GroupInfo>.Enumerator enumerator1 = this.groups.GetEnumerator()) { while (enumerator1.MoveNext()) { using (List<ProfilerTimelineGUI.ThreadInfo>.Enumerator enumerator2 = enumerator1.Current.threads.GetEnumerator()) { while (enumerator2.MoveNext()) { ProfilerTimelineGUI.ThreadInfo current = enumerator2.Current; current.height = num7 * current.weight; } } } } this.groups[0].expanded = true; this.groups[0].height = 0.0f; this.groups[0].threads[0].height = 3f * num7; }
private void DoProfilerFrame(int frameIndex, Rect fullRect, bool ghost, ref int threadCount, float offset) { ProfilerFrameDataIterator iter = new ProfilerFrameDataIterator(); int threadCount1 = iter.GetThreadCount(frameIndex); if (ghost && threadCount1 != threadCount) return; iter.SetRoot(frameIndex, 0); if (!ghost) { threadCount = threadCount1; this.DrawGrid(fullRect, threadCount, iter.frameTimeMS); this.HandleFrameSelected(iter.frameTimeMS); } float num1 = fullRect.y; using (List<ProfilerTimelineGUI.GroupInfo>.Enumerator enumerator1 = this.groups.GetEnumerator()) { while (enumerator1.MoveNext()) { ProfilerTimelineGUI.GroupInfo current1 = enumerator1.Current; Rect r = fullRect; bool expanded = current1.expanded; if (expanded) num1 += current1.height; float num2 = num1; int count = current1.threads.Count; using (List<ProfilerTimelineGUI.ThreadInfo>.Enumerator enumerator2 = current1.threads.GetEnumerator()) { while (enumerator2.MoveNext()) { ProfilerTimelineGUI.ThreadInfo current2 = enumerator2.Current; iter.SetRoot(frameIndex, current2.threadIndex); r.y = num1; r.height = !expanded ? Math.Max((float) ((double) current1.height / (double) count - 1.0), 2f) : current2.height; this.DrawProfilingData(iter, r, current2.threadIndex, offset, ghost, expanded); num1 += r.height; } } if (!expanded) num1 = num2 + current1.height; } } }
private void DoProfilerFrame(int frameIndex, Rect fullRect, bool ghost, ref int threadCount, float offset) { ProfilerFrameDataIterator iter = new ProfilerFrameDataIterator(); int num = iter.GetThreadCount(frameIndex); if (!ghost || (num == threadCount)) { if (!ghost) { threadCount = num; } for (int i = 0; i < threadCount; i++) { Rect r = fullRect; r.y = this.GetThreadY(fullRect, i, threadCount); r.height = this.GetThreadY(fullRect, i + 1, threadCount) - r.y; iter.SetRoot(frameIndex, i); if ((i == 0) && !ghost) { this.DrawGrid(fullRect, threadCount, iter.frameTimeMS); this.HandleFrameSelected(iter.frameTimeMS); } this.DrawProfilingData(iter, r, i, offset, ghost); } } }
public void DoGUI(int frameIndex, float width, float ypos, float height) { Rect drawRect = new Rect(0f, ypos - 1f, width, height + 1f); float num = 169f; if (Event.current.type == EventType.Repaint) { ProfilerTimelineGUI.styles.profilerGraphBackground.Draw(drawRect, false, false, false, false); EditorStyles.toolbar.Draw(new Rect(0f, ypos + height - 15f, num, 15f), false, false, false, false); } bool flag = false; if (this.m_TimeArea == null) { flag = true; this.m_TimeArea = new ZoomableArea(); this.m_TimeArea.hRangeLocked = false; this.m_TimeArea.vRangeLocked = true; this.m_TimeArea.hSlider = true; this.m_TimeArea.vSlider = false; this.m_TimeArea.scaleWithWindow = true; this.m_TimeArea.rect = new Rect(drawRect.x + num - 1f, drawRect.y, drawRect.width - num, drawRect.height); this.m_TimeArea.margin = 10f; } if (flag) { NativeProfilerTimeline_InitializeArgs nativeProfilerTimeline_InitializeArgs = default(NativeProfilerTimeline_InitializeArgs); nativeProfilerTimeline_InitializeArgs.Reset(); nativeProfilerTimeline_InitializeArgs.profilerColors = ProfilerColors.colors; nativeProfilerTimeline_InitializeArgs.allocationSampleColor = ProfilerColors.allocationSample; nativeProfilerTimeline_InitializeArgs.internalSampleColor = ProfilerColors.internalSample; nativeProfilerTimeline_InitializeArgs.ghostAlpha = 0.3f; nativeProfilerTimeline_InitializeArgs.nonSelectedAlpha = 0.75f; nativeProfilerTimeline_InitializeArgs.guiStyle = ProfilerTimelineGUI.styles.bar.m_Ptr; nativeProfilerTimeline_InitializeArgs.lineHeight = 16f; nativeProfilerTimeline_InitializeArgs.textFadeOutWidth = 20f; nativeProfilerTimeline_InitializeArgs.textFadeStartWidth = 50f; NativeProfilerTimeline.Initialize(ref nativeProfilerTimeline_InitializeArgs); } ProfilerFrameDataIterator profilerFrameDataIterator = new ProfilerFrameDataIterator(); profilerFrameDataIterator.SetRoot(frameIndex, 0); this.m_TimeArea.hBaseRangeMin = 0f; this.m_TimeArea.hBaseRangeMax = profilerFrameDataIterator.frameTimeMS; if (flag) { this.PerformFrameSelected(profilerFrameDataIterator.frameTimeMS); } this.m_TimeArea.rect = new Rect(drawRect.x + num, drawRect.y, drawRect.width - num, drawRect.height); this.m_TimeArea.BeginViewGUI(); this.m_TimeArea.EndViewGUI(); drawRect = this.m_TimeArea.drawRect; this.CalculateBars(drawRect, frameIndex, this.animationTime); this.DrawBars(drawRect, frameIndex); GUI.BeginClip(this.m_TimeArea.drawRect); drawRect.x = 0f; drawRect.y = 0f; bool enabled = GUI.enabled; GUI.enabled = false; ProfilerFrameDataIterator profilerFrameDataIterator2 = new ProfilerFrameDataIterator(); int threadCount = profilerFrameDataIterator2.GetThreadCount(frameIndex); int previousFrameIndex = ProfilerDriver.GetPreviousFrameIndex(frameIndex); if (previousFrameIndex != -1) { profilerFrameDataIterator2.SetRoot(previousFrameIndex, 0); this.DoProfilerFrame(previousFrameIndex, drawRect, true, threadCount, -profilerFrameDataIterator2.frameTimeMS); } int nextFrameIndex = ProfilerDriver.GetNextFrameIndex(frameIndex); if (nextFrameIndex != -1) { profilerFrameDataIterator2.SetRoot(frameIndex, 0); this.DoProfilerFrame(nextFrameIndex, drawRect, true, threadCount, profilerFrameDataIterator2.frameTimeMS); } GUI.enabled = enabled; threadCount = 0; this.DoProfilerFrame(frameIndex, drawRect, false, threadCount, 0f); GUI.EndClip(); this.DoSelectionTooltip(frameIndex, this.m_TimeArea.drawRect); }
private void DoProfilerFrame(int frameIndex, Rect fullRect, bool ghost, ref int threadCount, float offset) { ProfilerFrameDataIterator profilerFrameDataIterator = new ProfilerFrameDataIterator(); int threadCount2 = profilerFrameDataIterator.GetThreadCount(frameIndex); if (ghost && threadCount2 != threadCount) { return; } if (!ghost) { threadCount = threadCount2; } for (int i = 0; i < threadCount; i++) { Rect r = fullRect; r.y = this.GetThreadY(fullRect, i, threadCount); r.height = this.GetThreadY(fullRect, i + 1, threadCount) - r.y; profilerFrameDataIterator.SetRoot(frameIndex, i); if (i == 0 && !ghost) { this.DrawGrid(fullRect, threadCount, profilerFrameDataIterator.frameTimeMS); this.HandleFrameSelected(profilerFrameDataIterator.frameTimeMS); } this.DrawProfilingData(profilerFrameDataIterator, r, i, offset, ghost); } }
public void DoGUI(int frameIndex, float width, float ypos, float height, bool detailView) { Rect drawRect = new Rect(0f, ypos - 1f, width, height + 1f); float num = 169f; if (Event.current.type == EventType.Repaint) { ProfilerTimelineGUI.styles.profilerGraphBackground.Draw(drawRect, false, false, false, false); EditorStyles.toolbar.Draw(new Rect(0f, ypos + height - 15f, num, 15f), false, false, false, false); } bool flag = false; if (this.m_TimeArea == null) { flag = true; this.m_TimeArea = new ZoomableArea(); this.m_TimeArea.hRangeLocked = false; this.m_TimeArea.vRangeLocked = true; this.m_TimeArea.hSlider = true; this.m_TimeArea.vSlider = false; this.m_TimeArea.scaleWithWindow = true; this.m_TimeArea.rect = new Rect(drawRect.x + num - 1f, drawRect.y, drawRect.width - num, drawRect.height); this.m_TimeArea.margin = 10f; } ProfilerFrameDataIterator profilerFrameDataIterator = new ProfilerFrameDataIterator(); profilerFrameDataIterator.SetRoot(frameIndex, 0); this.m_TimeArea.hBaseRangeMin = 0f; this.m_TimeArea.hBaseRangeMax = profilerFrameDataIterator.frameTimeMS; if (flag) { this.PerformFrameSelected(profilerFrameDataIterator.frameTimeMS); } this.m_TimeArea.rect = new Rect(drawRect.x + num, drawRect.y, drawRect.width - num, drawRect.height); this.m_TimeArea.BeginViewGUI(); this.m_TimeArea.EndViewGUI(); drawRect = this.m_TimeArea.drawRect; this.CalculateBars(drawRect, frameIndex, this.animationTime); this.DrawBars(drawRect, frameIndex); GUI.BeginClip(this.m_TimeArea.drawRect); drawRect.x = 0f; drawRect.y = 0f; bool enabled = GUI.enabled; GUI.enabled = false; ProfilerFrameDataIterator profilerFrameDataIterator2 = new ProfilerFrameDataIterator(); int threadCount = profilerFrameDataIterator2.GetThreadCount(frameIndex); int previousFrameIndex = ProfilerDriver.GetPreviousFrameIndex(frameIndex); if (previousFrameIndex != -1) { profilerFrameDataIterator2.SetRoot(previousFrameIndex, 0); this.DoProfilerFrame(previousFrameIndex, drawRect, true, threadCount, -profilerFrameDataIterator2.frameTimeMS, detailView); } int nextFrameIndex = ProfilerDriver.GetNextFrameIndex(frameIndex); if (nextFrameIndex != -1) { profilerFrameDataIterator2.SetRoot(frameIndex, 0); this.DoProfilerFrame(nextFrameIndex, drawRect, true, threadCount, profilerFrameDataIterator2.frameTimeMS, detailView); } GUI.enabled = enabled; threadCount = 0; this.DoProfilerFrame(frameIndex, drawRect, false, threadCount, 0f, detailView); GUI.EndClip(); }
private void DoProfilerFrame(int frameIndex, Rect fullRect, bool ghost, int threadCount, float offset, bool detailView) { ProfilerFrameDataIterator profilerFrameDataIterator = new ProfilerFrameDataIterator(); int threadCount2 = profilerFrameDataIterator.GetThreadCount(frameIndex); if (!ghost || threadCount2 == threadCount) { profilerFrameDataIterator.SetRoot(frameIndex, 0); if (!ghost) { this.DrawGrid(fullRect, threadCount, profilerFrameDataIterator.frameTimeMS); this.HandleFrameSelected(profilerFrameDataIterator.frameTimeMS); } float num = fullRect.y; foreach (ProfilerTimelineGUI.GroupInfo current in this.groups) { Rect r = fullRect; bool expanded = current.expanded; if (expanded) { num += current.height; } float num2 = num; int count = current.threads.Count; foreach (ProfilerTimelineGUI.ThreadInfo current2 in current.threads) { profilerFrameDataIterator.SetRoot(frameIndex, current2.threadIndex); r.y = num; r.height = ((!expanded) ? Math.Max(current.height / (float)count - 1f, 2f) : current2.height); if (detailView) { this.DrawProfilingDataDetailNative(r, frameIndex, current2.threadIndex, offset); } else { this.DrawProfilingData(profilerFrameDataIterator, r, frameIndex, current2.threadIndex, offset, ghost, expanded); } num += r.height; } if (!expanded) { num = num2 + current.height; } } if (this.m_SelectedName.Length > 0 && this.m_SelectedFrameId == frameIndex && !ghost) { string text = string.Format(((double)this.m_SelectedDur < 1.0) ? "{0}\n{1:f3}ms" : "{0}\n{1:f2}ms", this.m_SelectedName, this.m_SelectedDur); GUIContent content = new GUIContent(text); GUIStyle tooltip = ProfilerTimelineGUI.styles.tooltip; Vector2 vector = tooltip.CalcSize(content); float num3 = this.m_TimeArea.TimeToPixel(this.m_SelectedTime + this.m_SelectedDur * 0.5f, this.m_SelectedRect); if (num3 > this.m_SelectedRect.xMax) { num3 = this.m_SelectedRect.xMax - 20f; } if (num3 < this.m_SelectedRect.x) { num3 = this.m_SelectedRect.x + 20f; } Rect position = new Rect(num3 - 32f, this.m_SelectedY, 50f, 7f); Rect position2 = new Rect(num3, this.m_SelectedY + 6f, vector.x, vector.y); if (position2.xMax > this.m_SelectedRect.xMax + 20f) { position2.x = this.m_SelectedRect.xMax - position2.width + 20f; } if (position2.xMin < this.m_SelectedRect.xMin + 30f) { position2.x = this.m_SelectedRect.xMin + 30f; } GUI.Label(position, GUIContent.none, ProfilerTimelineGUI.styles.tooltipArrow); GUI.Label(position2, content, tooltip); } } }
public void DoGUI(FrameDataView frameDataView, float width, float ypos, float height) { if (frameDataView == null || !frameDataView.IsValid()) { GUILayout.Label(BaseStyles.noData, BaseStyles.label); return; } Rect fullRect = new Rect(0, ypos - 1, width, height + 1); float sideWidth = Chart.kSideWidth - 1; if (Event.current.type == EventType.Repaint) { styles.profilerGraphBackground.Draw(fullRect, false, false, false, false); // The bar in the lower left side that fills the space next to the horizontal scrollbar. EditorStyles.toolbar.Draw(new Rect(0, ypos + height - 15, sideWidth, 15), false, false, false, false); } bool initializing = false; if (m_TimeArea == null) { initializing = true; m_TimeArea = new ZoomableArea(); m_TimeArea.hRangeLocked = false; m_TimeArea.vRangeLocked = true; m_TimeArea.hSlider = true; m_TimeArea.vSlider = false; m_TimeArea.scaleWithWindow = true; m_TimeArea.rect = new Rect(fullRect.x + sideWidth - 1, fullRect.y, fullRect.width - sideWidth, fullRect.height); m_TimeArea.margin = 10; } if (initializing) { NativeProfilerTimeline_InitializeArgs args = new NativeProfilerTimeline_InitializeArgs(); args.Reset(); args.ghostAlpha = 0.3f; args.nonSelectedAlpha = 0.75f; args.guiStyle = styles.bar.m_Ptr; args.lineHeight = kLineHeight; args.textFadeOutWidth = kTextFadeOutWidth; args.textFadeStartWidth = kTextFadeStartWidth; NativeProfilerTimeline.Initialize(ref args); } var iter = new ProfilerFrameDataIterator(); int threadCount = iter.GetThreadCount(frameDataView.frameIndex); iter.SetRoot(frameDataView.frameIndex, 0); m_TimeArea.hBaseRangeMin = 0; m_TimeArea.hBaseRangeMax = iter.frameTimeMS; if (initializing) { PerformFrameSelected(iter.frameTimeMS); } m_TimeArea.rect = new Rect(fullRect.x + sideWidth, fullRect.y, fullRect.width - sideWidth, fullRect.height); m_TimeArea.BeginViewGUI(); m_TimeArea.EndViewGUI(); fullRect = m_TimeArea.drawRect; DrawGrid(fullRect, iter.frameTimeMS); MarkDeadOrClearThread(); CalculateBars(ref iter, fullRect, frameDataView.frameIndex, animationTime); DrawBars(fullRect, frameDataView.frameIndex); DoRangeSelection(m_TimeArea.drawRect); GUI.BeginClip(m_TimeArea.drawRect); fullRect.x = 0; fullRect.y = 0; bool oldEnabled = GUI.enabled; GUI.enabled = false; // Walk backwards to find how many previous frames we need to show. int maxContextFramesToShow = m_Window.IsRecording() ? 1 : 3; int numContextFramesToShow = maxContextFramesToShow; int currentFrame = frameDataView.frameIndex; float currentTime = 0; do { int prevFrame = ProfilerDriver.GetPreviousFrameIndex(currentFrame); if (prevFrame == -1) { break; } iter.SetRoot(prevFrame, 0); currentTime -= iter.frameTimeMS; currentFrame = prevFrame; --numContextFramesToShow; }while (currentTime > m_TimeArea.shownArea.x && numContextFramesToShow > 0); // Draw previous frames while (currentFrame != -1 && currentFrame != frameDataView.frameIndex) { iter.SetRoot(currentFrame, 0); DoProfilerFrame(currentFrame, fullRect, true, threadCount, currentTime); currentTime += iter.frameTimeMS; currentFrame = ProfilerDriver.GetNextFrameIndex(currentFrame); } // Draw next frames numContextFramesToShow = maxContextFramesToShow; currentFrame = frameDataView.frameIndex; currentTime = 0; while (currentTime < m_TimeArea.shownArea.x + m_TimeArea.shownArea.width && numContextFramesToShow >= 0) { if (frameDataView.frameIndex != currentFrame) { DoProfilerFrame(currentFrame, fullRect, true, threadCount, currentTime); } iter.SetRoot(currentFrame, 0); currentFrame = ProfilerDriver.GetNextFrameIndex(currentFrame); if (currentFrame == -1) { break; } currentTime += iter.frameTimeMS; --numContextFramesToShow; } GUI.enabled = oldEnabled; // Draw center frame last to get on top threadCount = 0; DoProfilerFrame(frameDataView.frameIndex, fullRect, false, threadCount, 0); GUI.EndClip(); // Draw tooltips on top of clip to be able to extend outside of timeline area DoSelectionTooltip(frameDataView.frameIndex, m_TimeArea.drawRect); }
private void CalculateBars(ref ProfilerFrameDataIterator iter, Rect r, int frameIndex, float time) { float visibleThreadCount = 0; iter.SetRoot(frameIndex, 0); int threadCount = iter.GetThreadCount(frameIndex); for (int i = 0; i < threadCount; ++i) { iter.SetRoot(frameIndex, i); string groupname = iter.GetGroupName(); GroupInfo group = groups.Find(g => g.name == groupname); if (group == null) { group = new GroupInfo(); group.name = groupname; group.height = kGroupHeight; group.expanded = false; group.threads = new List <ThreadInfo>(); groups.Add(group); } var threads = group.threads; ThreadInfo thread = threads.Find(t => t.threadIndex == i); if (thread == null) { thread = new ThreadInfo(); thread.name = iter.GetThreadName(); thread.height = 0; thread.weight = thread.desiredWeight = group.expanded ? 1 : 0; thread.threadIndex = i; group.threads.Add(thread); } thread.alive = true; if (thread.weight != thread.desiredWeight) { thread.weight = thread.desiredWeight * time + (1 - thread.desiredWeight) * (1 - time); } visibleThreadCount += thread.weight; } var groupheight = 0.0f; foreach (var group in groups) { if (group.threads.Count > 1) { groupheight += !group.expanded ? group.height : Math.Max(group.height, group.threads.Count * 2.0f); } } var remaining = r.height - groupheight; var heightPerThread = remaining / (visibleThreadCount + 1); // main thread gets 2 times the space foreach (var group in groups) { foreach (var thread in group.threads) { thread.height = heightPerThread * thread.weight; } } groups[0].expanded = true; groups[0].height = 0; if (groups[0].threads.Count > 0) { groups[0].threads[0].height = 2 * heightPerThread; } }