public static void Section(ref Vector2 position, float width, Func <Vector2, float, float> drawerFunc, string header = null, int id = 0) { bool hasHeader = !header.NullOrEmpty(); id = id != 0 ? id : drawerFunc.GetHashCode(); // header if (hasHeader) { Rect headerRect = new Rect(position.x, position.y, width, SectionHeaderHeight); Widgets_Labels.Label(headerRect, header, TextAnchor.LowerLeft, GameFont.Tiny, margin: 3 * Margin); position.y += SectionHeaderHeight; } // draw content Rect contentRect = new Rect( position.x, position.y, width, GetHeight(id) + 2 * Margin); // NOTE: we're updating height _after_ drawing, so the background is technically always one frame behind. GUI.DrawTexture(contentRect, Resources.SlightlyDarkBackground); var height = drawerFunc(position + new Vector2(Margin, Margin), width - 2 * Margin); position.y += height + 3 * Margin; _heights[id] = height; }
public override void DrawListEntry(Rect rect, bool overview = true, bool active = true) { // (detailButton) | name | (bar | last update)/(stamp) -> handled in Utilities.DrawStatusForListEntry // set up rects Rect labelRect = new Rect( Margin, Margin, rect.width - (active ? StatusRectWidth + 4 * Margin : 2 * Margin), rect.height - 2 * Margin), statusRect = new Rect(labelRect.xMax + Margin, Margin, StatusRectWidth, rect.height - 2 * Margin); // create label string string text = Label + "\n<i>"; foreach (AgeAndSex ageSex in Utilities_Livestock.AgeSexArray) { text += Trigger.pawnKind.GetTame(manager, ageSex).Count + "/" + Trigger.CountTargets[ageSex] + ", "; } text += Trigger.pawnKind.GetWild(manager).Count + "</i>"; string tooltip = Trigger.StatusTooltip; // do the drawing GUI.BeginGroup(rect); // draw label Widgets_Labels.Label(labelRect, text, tooltip); // if the bill has a manager job, give some more info. if (active) { this.DrawStatusForListEntry(statusRect, Trigger); } GUI.EndGroup(); }
public override void DrawTriggerConfig(ref Vector2 cur, float width, float entryHeight, string label = null, string tooltip = null, Action onClick = null) { // target threshold var thresholdLabelRect = new Rect( cur.x, cur.y, width, entryHeight); var searchIconRect = new Rect( thresholdLabelRect.xMax - Margin - entryHeight, cur.y, entryHeight, entryHeight); searchIconRect = searchIconRect.ContractedBy((searchIconRect.height - SmallIconSize) / 2); cur.y += entryHeight; var thresholdRect = new Rect( cur.x, cur.y, width, SliderHeight); cur.y += entryHeight; var useResourceListerToggleRect = new Rect( cur.x, cur.y, width, entryHeight); cur.y += entryHeight; Widgets.DrawHighlightIfMouseover(thresholdLabelRect); if (label.NullOrEmpty()) { label = "FMP.ThresholdCount".Translate(CurrentCount, TargetCount) + ":"; } if (tooltip.NullOrEmpty()) { tooltip = "FMP.ThresholdCountTooltip".Translate(CurrentCount, TargetCount); } Widgets_Labels.Label(thresholdLabelRect, label, tooltip); // add a little icon to mark interactivity GUI.DrawTexture(searchIconRect, Resources.Search); if (Widgets.ButtonInvisible(thresholdLabelRect)) { onClick?.Invoke(); Find.WindowStack.Add(DetailsWindow); } Utilities.DrawToggle(useResourceListerToggleRect, "FM.CountAllOnMap".Translate(), "FM.CountAllOnMap.Tip".Translate(), ref countAllOnMap, true); TargetCount = (int)GUI.HorizontalSlider(thresholdRect, TargetCount, 0, MaxUpperThreshold); }
private void DrawOverview(Rect canvas) { // setup rects var legendRect = new Rect(canvas.xMin, canvas.yMin, (canvas.width - Margin) / 2f, canvas.height - ButtonSize.y - Margin); var plotRect = new Rect(legendRect.xMax + Margin, canvas.yMin, (canvas.width - Margin) / 2f, canvas.height); var buttonsRect = new Rect(canvas.xMin, legendRect.yMax + Margin, (canvas.width - Margin) / 2f, ButtonSize.y); // draw the plot overallHistory.DrawPlot(plotRect); // draw the detailed legend overallHistory.DrawDetailedLegend(legendRect, ref _overallScrollPos, null); // draw period switcher var periodRect = buttonsRect; periodRect.width /= 2f; // label Widgets_Labels.Label(periodRect, "FME.PeriodShown".Translate(tradingHistory.periodShown.ToString()), "FME.PeriodShownTooltip".Translate(tradingHistory.periodShown.ToString())); // mark interactivity var searchIconRect = periodRect; searchIconRect.xMin = searchIconRect.xMax - searchIconRect.height; if (searchIconRect.height > SmallIconSize) { // center it. searchIconRect = searchIconRect.ContractedBy((searchIconRect.height - SmallIconSize) / 2); } GUI.DrawTexture(searchIconRect, Resources.Search); Widgets.DrawHighlightIfMouseover(periodRect); if (Widgets.ButtonInvisible(periodRect)) { var periodOptions = new List <FloatMenuOption>(); for (var i = 0; i < History.periods.Length; i++) { var period = History.periods[i]; periodOptions.Add(new FloatMenuOption(period.ToString(), delegate { tradingHistory.periodShown = period; overallHistory.periodShown = period; })); } Find.WindowStack.Add(new FloatMenu(periodOptions)); } }
private void DrawPawnOverviewRow(Pawn pawn, Rect rect) { // column width float colWidth = rect.width / 4 - Margin; // cell rects var nameRect = new Rect(colWidth * 0, rect.yMin, colWidth, ListEntryHeight); var activityRect = new Rect(colWidth * 1, rect.yMin, colWidth * 2.5f, ListEntryHeight); var priorityRect = new Rect(colWidth * 3.5f, rect.yMin, colWidth * .5f, ListEntryHeight); // name Widgets.DrawHighlightIfMouseover(nameRect); // on click select and jump to location if (Widgets.ButtonInvisible(nameRect)) { Find.MainTabsRoot.EscapeCurrentTab(); CameraJumper.TryJump(pawn.PositionHeld, pawn.Map); Find.Selector.ClearSelection(); if (pawn.Spawned) { Find.Selector.Select(pawn); } } Widgets_Labels.Label(nameRect, pawn.Name.ToStringShort, "FM.ClickToJumpTo".Translate(pawn.LabelCap), TextAnchor.MiddleLeft, margin: Margin); // current activity (if curDriver != null) string activityString = pawn.jobs.curDriver?.GetReport() ?? "FM.NoCurJob".Translate(); Widgets_Labels.Label(activityRect, activityString, pawn.jobs.curDriver?.GetReport(), TextAnchor.MiddleCenter, margin: Margin, font: GameFont.Tiny); // priority button Rect priorityPosition = new Rect(0f, 0f, 24f, 24f).CenteredOnXIn(priorityRect) .CenteredOnYIn(priorityRect); Text.Font = GameFont.Medium; WidgetsWork.DrawWorkBoxFor(priorityPosition.xMin, priorityPosition.yMin, pawn, WorkTypeDef, false); Text.Font = GameFont.Small; }
public override void DrawListEntry(Rect rect, bool overview = true, bool active = true) { // (detailButton) | name | (bar | last update)/(stamp) -> handled in Utilities.DrawStatusForListEntry // set up rects Rect labelRect = new Rect( Margin, Margin, rect.width - (active ? StatusRectWidth + 4 * Margin : 2 * Margin), rect.height - 2 * Margin); Rect statusRect = new Rect(labelRect.xMax + Margin, Margin, StatusRectWidth, rect.height - 2 * Margin); // create label string string text = Label + "\n"; string subtext = string.Join(", ", Targets); if (subtext.Fits(labelRect)) { text += subtext.Italic(); } else { text += "multiple".Translate().Italic(); } // do the drawing GUI.BeginGroup(rect); // draw label Widgets_Labels.Label(labelRect, text, subtext, TextAnchor.MiddleLeft, margin: Margin); // if the bill has a manager job, give some more info. if (active) { this.DrawStatusForListEntry(statusRect, Trigger); } GUI.EndGroup(); }
public void DrawPawnOverview(Rect rect) { // table body viewport var tableOutRect = new Rect(0f, ListEntryHeight, rect.width, rect.height - ListEntryHeight); var tableViewRect = new Rect(0f, ListEntryHeight, rect.width, Workers.Count * ListEntryHeight); if (tableViewRect.height > tableOutRect.height) { tableViewRect.width -= ScrollbarWidth; } // column width float colWidth = tableViewRect.width / 4 - Margin; // column headers var nameColumnHeaderRect = new Rect(colWidth * 0, 0f, colWidth, ListEntryHeight); var activityColumnHeaderRect = new Rect(colWidth * 1, 0f, colWidth * 2.5f, ListEntryHeight); var priorityColumnHeaderRect = new Rect(colWidth * 3.5f, 0f, colWidth * .5f, ListEntryHeight); // label for priority column string workLabel = Find.PlaySettings.useWorkPriorities ? "FM.Priority".Translate() : "FM.Enabled".Translate(); // begin drawing GUI.BeginGroup(rect); // draw labels Widgets_Labels.Label(nameColumnHeaderRect, WorkTypeDef.pawnLabel + "FM.PluralSuffix".Translate(), TextAnchor.LowerCenter); Widgets_Labels.Label(activityColumnHeaderRect, "FM.Activity".Translate(), TextAnchor.LowerCenter); Widgets_Labels.Label(priorityColumnHeaderRect, workLabel, TextAnchor.LowerCenter); // begin scrolling area Widgets.BeginScrollView(tableOutRect, ref _workersScrollPosition, tableViewRect); GUI.BeginGroup(tableViewRect); // draw pawn rows Vector2 cur = Vector2.zero; for (var i = 0; i < Workers.Count; i++) { var row = new Rect(cur.x, cur.y, tableViewRect.width, ListEntryHeight); if (i % 2 == 0) { Widgets.DrawAltRect(row); } try { DrawPawnOverviewRow(Workers[i], row); } catch // pawn death, etc. { // rehresh the list and skip drawing untill the next GUI tick. RefreshWorkers(); Widgets.EndScrollView(); return; } cur.y += ListEntryHeight; } // end scrolling area GUI.EndGroup(); Widgets.EndScrollView(); // done! GUI.EndGroup(); }
public override void DrawTriggerConfig(ref Vector2 cur, float width, float entryHeight, string label = null, string tooltip = null, List <Designation> designations = null, Action onOpenFilterDetails = null, Func <Designation, string> designationLabelGetter = null) { var hasTargets = !designations.NullOrEmpty(); // target threshold var thresholdLabelRect = new Rect( cur.x, cur.y, width - (hasTargets ? SmallIconSize + Margin * 2 : 0f), entryHeight); var detailsWindowButtonRect = new Rect( thresholdLabelRect.xMax - SmallIconSize - Margin, cur.y + (entryHeight - SmallIconSize) / 2f, SmallIconSize, SmallIconSize); var targetsButtonRect = new Rect( thresholdLabelRect.xMax + Margin, cur.y + (entryHeight - SmallIconSize) / 2f, SmallIconSize, SmallIconSize ); cur.y += entryHeight; var thresholdRect = new Rect( cur.x, cur.y, width, SliderHeight); cur.y += entryHeight; var useResourceListerToggleRect = new Rect( cur.x, cur.y, width, entryHeight); cur.y += entryHeight; Widgets.DrawHighlightIfMouseover(thresholdLabelRect); if (label.NullOrEmpty()) { label = "FMP.ThresholdCount".Translate(CurrentCount, TargetCount) + ":"; } if (tooltip.NullOrEmpty()) { tooltip = "FMP.ThresholdCountTooltip".Translate(CurrentCount, TargetCount); } Widgets_Labels.Label(thresholdLabelRect, label, tooltip); // add a little icon to mark interactivity GUI.color = Mouse.IsOver(thresholdLabelRect) ? GenUI.MouseoverColor : Color.white; GUI.DrawTexture(detailsWindowButtonRect, Resources.Cog); GUI.color = Color.white; if (Widgets.ButtonInvisible(thresholdLabelRect)) { onOpenFilterDetails?.Invoke(); Find.WindowStack.Add(DetailsWindow); } // target list if (hasTargets) { if (Widgets.ButtonImage(targetsButtonRect, Resources.Search)) { List <FloatMenuOption> options = new List <FloatMenuOption>(); foreach (var designation in designations) { string option = string.Empty; Action onClick = () => Find.WindowStack.TryRemove(typeof(MainTabWindow_Manager), false); Action onHover = null; if (designation.target.HasThing) { var thing = designation.target.Thing; option = designationLabelGetter?.Invoke(designation) ?? thing.LabelCap; onClick += () => CameraJumper.TryJumpAndSelect(thing); onHover += () => CameraJumper.TryJump(thing); } else { var cell = designation.target.Cell; var map = Find.CurrentMap; // designation.map would be better, but that's private. We should only ever be looking at jobs on the current map anyway, // so I suppose it doesn't matter -- Fluffy. option = designationLabelGetter?.Invoke(designation) ?? cell.GetTerrain(map).LabelCap; onClick += () => CameraJumper.TryJump(cell, map); onHover += () => CameraJumper.TryJump(cell, map); } options.Add(new FloatMenuOption(option, onClick, MenuOptionPriority.Default, onHover)); } Find.WindowStack.Add(new FloatMenu(options)); } } Utilities.DrawToggle(useResourceListerToggleRect, "FM.CountAllOnMap".Translate(), "FM.CountAllOnMap.Tip".Translate(), ref countAllOnMap, true); TargetCount = (int)GUI.HorizontalSlider(thresholdRect, TargetCount, 0, MaxUpperThreshold); }
public void DrawDetailedLegend(Rect canvas, ref Vector2 scrollPos, int?max, bool positiveOnly = false, bool negativeOnly = false) { // set sign int sign = negativeOnly ? -1 : 1; List <Chapter> ChaptersOrdered = _chapters .Where(chapter => !positiveOnly || chapter.pages[periodShown].Any(i => i > 0)) .Where(chapter => !negativeOnly || chapter.pages[periodShown].Any(i => i < 0)) .OrderByDescending(chapter => chapter.Last(periodShown) * sign).ToList(); // get out early if no chapters. if (ChaptersOrdered.Count == 0) { GUI.DrawTexture(canvas.ContractedBy(Margin), Resources.SlightlyDarkBackground); Widgets_Labels.Label(canvas, "FM.HistoryNoChapters".Translate(), TextAnchor.MiddleCenter, color: Color.grey); return; } // max float _max = max ?? (DrawMaxMarkers ? ChaptersOrdered.Max(chapter => chapter.TrueMax) : ChaptersOrdered.FirstOrDefault()?.Last(periodShown) * sign) ?? 0; // cell height var height = 30f; var barHeight = 18f; // n rows int n = ChaptersOrdered.Count; // scrolling region Rect viewRect = canvas; viewRect.height = n * height; if (viewRect.height > canvas.height) { viewRect.width -= 16f + Margin; canvas.width -= Margin; canvas.height -= 1f; } Widgets.BeginScrollView(canvas, ref scrollPos, viewRect); for (var i = 0; i < n; i++) { // set up rects var row = new Rect(0f, height * i, viewRect.width, height); Rect icon = new Rect(Margin, height * i, height, height).ContractedBy(Margin / 2f); // icon is square, size defined by height. var bar = new Rect(Margin + height, height * i, viewRect.width - height - Margin, height); // if icons should not be drawn make the bar full size. if (!DrawIcons) { bar.xMin -= height + Margin; } // bar details. Rect barBox = bar.ContractedBy((height - barHeight) / 2f); Rect barFill = barBox.ContractedBy(2f); float maxWidth = barFill.width; if (MaxPerChapter) { barFill.width *= ChaptersOrdered[i].Last(periodShown) * sign / (float)ChaptersOrdered[i].TrueMax; } else { barFill.width *= ChaptersOrdered[i].Last(periodShown) * sign / _max; } GUI.BeginGroup(viewRect); // if DrawIcons and a thing is set, draw the icon. ThingDef thing = ChaptersOrdered[i].ThingDefCount.thingDef; if (DrawIcons && thing != null) { // draw the icon in correct proportions float proportion = GenUI.IconDrawScale(thing); Widgets.DrawTextureFitted(icon, thing.uiIcon, proportion); // draw counts in upper left corner if (DrawCounts) { Utilities.LabelOutline(icon, ChaptersOrdered[i].ThingDefCount.count.ToString(), null, TextAnchor.UpperLeft, 0f, GameFont.Tiny, Color.white, Color.black); } } // if desired, draw ghost bar if (DrawMaxMarkers) { Rect ghostBarFill = barFill; ghostBarFill.width = MaxPerChapter ? maxWidth : maxWidth * (ChaptersOrdered[i].TrueMax / _max); GUI.color = new Color(1f, 1f, 1f, .2f); GUI.DrawTexture(ghostBarFill, ChaptersOrdered[i].Texture); // coloured texture GUI.color = Color.white; } // draw the main bar. GUI.DrawTexture(barBox, Resources.SlightlyDarkBackground); GUI.DrawTexture(barFill, ChaptersOrdered[i].Texture); // coloured texture GUI.DrawTexture(barFill, Resources.BarShader); // slightly fancy overlay (emboss). // draw on bar info if (DrawInfoInBar) { string info = ChaptersOrdered[i].label + ": " + FormatCount(ChaptersOrdered[i].Last(periodShown) * sign); if (DrawMaxMarkers) { info += " / " + FormatCount(ChaptersOrdered[i].TrueMax); } // offset label a bit downwards and to the right Rect rowInfoRect = row; rowInfoRect.y += 3f; rowInfoRect.x += Constants.Margin * 2; // x offset float xOffset = DrawIcons && thing != null ? height + Margin * 2 : Margin * 2; Utilities.LabelOutline(rowInfoRect, info, null, TextAnchor.MiddleLeft, xOffset, GameFont.Tiny, Color.white, Color.black); } // are we currently showing this line? bool shown = _chaptersShown.Contains(ChaptersOrdered[i]); // tooltip on entire row string tooltip = ChaptersOrdered[i].label + ": " + FormatCount(Mathf.Abs(ChaptersOrdered[i].Last(periodShown))); tooltip += "FM.HistoryClickToEnable".Translate(shown ? "hide" : "show", ChaptersOrdered[i].label); TooltipHandler.TipRegion(row, tooltip); // handle input if (Widgets.ButtonInvisible(row)) { if (Event.current.button == 0) { if (shown) { _chaptersShown.Remove(ChaptersOrdered[i]); } else { _chaptersShown.Add(ChaptersOrdered[i]); } } else if (Event.current.button == 1) { _chaptersShown.Clear(); _chaptersShown.Add(ChaptersOrdered[i]); } } // UI feedback for disabled row if (!shown) { GUI.DrawTexture(row, Resources.SlightlyDarkBackground); } GUI.EndGroup(); } Widgets.EndScrollView(); }
public void DrawPlot(Rect rect, int target = 0, string label = "", bool positiveOnly = false, bool negativeOnly = false) { // set sign int sign = negativeOnly ? -1 : 1; // subset chapters List <Chapter> chapters = _chaptersShown.Where(chapter => !positiveOnly || chapter.pages[periodShown].Any(i => i > 0)) .Where(chapter => !negativeOnly || chapter.pages[periodShown].Any(i => i < 0)) .ToList(); // get out early if no chapters. if (chapters.Count == 0) { GUI.DrawTexture(rect.ContractedBy(Margin), Resources.SlightlyDarkBackground); Widgets_Labels.Label(rect, "FM.HistoryNoChapters".Translate(), TextAnchor.MiddleCenter, color: Color.grey); return; } // stuff we need Rect plot = rect.ContractedBy(Margin); plot.xMin += _yAxisMargin; // maximum of all chapters. int max = CeilToPrecision(Math.Max(chapters.Select(c => c.Max(periodShown, !negativeOnly)).Max(), target) * 1.2f); // size, and pixels per node. float w = plot.width; float h = plot.height; float wu = w / Size; // width per section float hu = h / max; // height per count int bi = max / (Breaks + 1); // count per break float bu = hu * bi; // height per break // plot the line(s) GUI.DrawTexture(plot, Resources.SlightlyDarkBackground); GUI.BeginGroup(plot); foreach (Chapter chapter in chapters) { chapter.Plot(periodShown, plot.AtZero(), wu, hu, sign); } // handle mouseover events if (Mouse.IsOver(plot.AtZero())) { // very conveniently this is the position within the current group. Vector2 pos = Event.current.mousePosition; var upos = new Vector2(pos.x / wu, (plot.height - pos.y) / hu); // get distances float[] distances = chapters.Select(c => Math.Abs(c.ValueAt(periodShown, (int)upos.x, sign) - upos.y)).ToArray(); // get the minimum index float min = int.MaxValue; var minIndex = 0; for (var i = 0; i < distances.Count(); i++) { if (distances[i] < min) { minIndex = i; min = distances[i]; } } // closest line Chapter closest = chapters[minIndex]; // do minimum stuff. var realpos = new Vector2(pos.x, plot.height - closest.ValueAt(periodShown, (int)upos.x, sign) * hu); var blipRect = new Rect(realpos.x - SmallIconSize / 2f, realpos.y - SmallIconSize / 2f, SmallIconSize, SmallIconSize); GUI.color = closest.lineColor; GUI.DrawTexture(blipRect, Resources.StageB); GUI.color = DefaultLineColor; // get orientation of tooltip Vector2 tippos = realpos + new Vector2(Margin, Margin); string tip = chapters[minIndex].label + ": " + FormatCount(chapters[minIndex].ValueAt(periodShown, (int)upos.x, sign)); Vector2 tipsize = Text.CalcSize(tip); bool up = false, left = false; if (tippos.x + tipsize.x > plot.width) { left = true; tippos.x -= tipsize.x + 2 * +Margin; } if (tippos.y + tipsize.y > plot.height) { up = true; tippos.y -= tipsize.y + 2 * Margin; } var anchor = TextAnchor.UpperLeft; if (up && left) { anchor = TextAnchor.LowerRight; } if (up && !left) { anchor = TextAnchor.LowerLeft; } if (!up && left) { anchor = TextAnchor.UpperRight; } var tooltipRect = new Rect(tippos.x, tippos.y, tipsize.x, tipsize.y); Widgets_Labels.Label(tooltipRect, tip, anchor: anchor, font: GameFont.Tiny); } // draw target line if (DrawTargetLine) { GUI.color = Color.gray; for (var i = 0; i < plot.width / DashLength; i += 2) { Widgets.DrawLineHorizontal(i * DashLength, plot.height - target * hu, DashLength); } } // draw legend int lineCount = _chapters.Count; if (AllowTogglingLegend && lineCount > 1 && DrawInlineLegend) { var rowHeight = 20f; var lineLength = 30f; var labelWidth = 100f; Vector2 cur = Vector2.zero; foreach (Chapter chapter in _chapters) { GUI.color = chapter.lineColor; Widgets.DrawLineHorizontal(cur.x, cur.y + rowHeight / 2f, lineLength); cur.x += lineLength; Widgets_Labels.Label(ref cur, labelWidth, rowHeight, chapter.label, font: GameFont.Tiny); cur.x = 0f; } GUI.color = Color.white; } GUI.EndGroup(); // plot axis GUI.BeginGroup(rect); Text.Anchor = TextAnchor.MiddleRight; Text.Font = GameFont.Tiny; // draw ticks + labels for (var i = 1; i < Breaks + 1; i++) { Widgets.DrawLineHorizontal(_yAxisMargin + Margin / 2, plot.height - i * bu, Margin); var labRect = new Rect(0f, plot.height - i * bu - 4f, _yAxisMargin, 20f); Widgets.Label(labRect, FormatCount(i * bi)); } Text.Font = GameFont.Small; Text.Anchor = TextAnchor.UpperLeft; GUI.color = Color.white; rect = rect.AtZero(); // ugh, I'm tired, just work. // period / variables picker if (DrawOptions) { var switchRect = new Rect(rect.xMax - SmallIconSize - Margin, rect.yMin + Margin, SmallIconSize, SmallIconSize); Widgets.DrawHighlightIfMouseover(switchRect); if (Widgets.ButtonImage(switchRect, Resources.Cog)) { List <FloatMenuOption> options = periods.Select( p => new FloatMenuOption("FM.HistoryPeriod".Translate() + ": " + p.ToString(), delegate { periodShown = p; })).ToList(); if (AllowTogglingLegend && _chapters.Count > 1) // add option to show/hide legend if appropriate. { options.Add(new FloatMenuOption("FM.HistoryShowHideLegend".Translate(), delegate { DrawInlineLegend = !DrawInlineLegend; })); } Find.WindowStack.Add(new FloatMenu(options)); } } GUI.EndGroup(); }