120 lines
5.7 KiB
C++
120 lines
5.7 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Fonts/SlateFontInfo.h"
|
|
#include "UObject/WeakObjectPtrTemplates.h"
|
|
#include "Widgets/SCompoundWidget.h"
|
|
|
|
class UNpcScheduleAsset;
|
|
|
|
/**
|
|
* A schedule's day drawn as one strip: an hour ruler across the top, one row of slots under it with
|
|
* the actions that claim them, and a legend under that naming every action, the window it holds and
|
|
* the anchor it happens at.
|
|
*
|
|
* It reads the day out of the actions' start times, because a start is all an FScheduledAction has:
|
|
* the end of a window is the next start in the schedule, which is also the rule the asset states for
|
|
* itself, so a 06:00-22:00 and a 22:00-06:00 pair tile the day, a window that runs past midnight is
|
|
* drawn as two halves of one slot with a marker where it carries on, and a schedule whose actions all
|
|
* start at one minute covers the whole day with each of them, which is what the game reads it as.
|
|
*
|
|
* Two actions authored at the same minute therefore claim one slot between them, and that is the only
|
|
* case that needs more than one row: the day is drawn on as many lanes as there are claims on the
|
|
* most-claimed minute, so a minute two actions fight over is seen rather than drawn twice in the same
|
|
* place.
|
|
*
|
|
* Nothing here is interactive. It says what the asset says and leaves the writing to the array above
|
|
* it, which is the one place an action can be authored.
|
|
*
|
|
* The strip draws itself from whatever width the panel gives it, read back at paint time, so it grows
|
|
* and shrinks with the details panel without ever being laid out again to do it. What is worked out
|
|
* ahead of painting - the slots, the ruler, the colours, the names - is worked out when the schedule
|
|
* changes and not while painting, because a rebuild is also what walks the level to name the anchors
|
|
* and that is not something to do once a frame.
|
|
*/
|
|
class SNpcScheduleTimeline : public SCompoundWidget
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS(SNpcScheduleTimeline)
|
|
: _Schedule(nullptr)
|
|
{
|
|
}
|
|
/** The asset to draw. Weak because a details panel outlives the asset it was opened on, and a
|
|
* deleted asset has to leave an empty strip rather than a dangling one. */
|
|
SLATE_ARGUMENT(TWeakObjectPtr<UNpcScheduleAsset>, Schedule)
|
|
SLATE_END_ARGS()
|
|
|
|
void Construct(const FArguments& InArgs);
|
|
|
|
//~ Begin SWidget interface
|
|
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
|
|
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
|
|
//~ End SWidget interface
|
|
|
|
protected:
|
|
virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override;
|
|
|
|
private:
|
|
/** One slot of the day: the window one action claims, which lane it is drawn on because something
|
|
* else claims that window too, and the two labels it is drawn with. Worked out by Rebuild. */
|
|
struct FSlotView
|
|
{
|
|
/** First minute of the day in the slot, 0 at midnight. */
|
|
int32 StartMinutes = 0;
|
|
|
|
/** The minute the slot ends at, exclusive, and past midnight rather than wrapped to it, so a
|
|
* slot that carries on at the start of the next day can be told from one that does not. */
|
|
int32 EndMinutes = 0;
|
|
|
|
/** Row the slot is drawn on. Only ever more than 0 under a window another action claims too. */
|
|
int32 LaneIndex = 0;
|
|
|
|
/** Colour of the activity, so that a legend row and its slot cannot disagree about it. */
|
|
FLinearColor Color = FLinearColor::Gray;
|
|
|
|
/** Activity and window, as it reads inside the slot: "Sleep 22:00 - 06:00". */
|
|
FText BlockLabel;
|
|
|
|
/** Activity, window and anchor, as it reads in the legend. Longer than BlockLabel because a
|
|
* slot can be far too narrow to hold anything and the legend is where the rest is said. */
|
|
FText LegendLabel;
|
|
};
|
|
|
|
/** A cheap read of everything the strip draws, so that a change can be noticed by reading the
|
|
* asset rather than by subscribing to every way one of its actions can be written: an element
|
|
* added, removed, reordered or edited inside a row all come out as a different signature here.
|
|
* What the strip does not draw is deliberately not in it, so moving an anchor to the side of the
|
|
* room it was already picked at does not make the strip rebuild itself. */
|
|
uint32 ComputeSignature() const;
|
|
|
|
/** Works the slots, the lanes and the legend out of the schedule, and names the anchors they point
|
|
* at with one walk of the open level. Does not repaint: the caller does that, because a rebuild
|
|
* during Construct happens before there is anything to repaint. */
|
|
void Rebuild(uint32 InSignature, double InCurrentTime);
|
|
|
|
/** The asset being drawn. Null while nothing has been assigned or after it was deleted. */
|
|
TWeakObjectPtr<UNpcScheduleAsset> Schedule;
|
|
|
|
/** Every slot of the day, in the order the day reads: earliest start first, and actions that share
|
|
* a start in the order the schedule holds them. The legend is drawn straight off this as well, so
|
|
* that a line and the slot it belongs to cannot come apart. */
|
|
TArray<FSlotView> Slots;
|
|
|
|
/** How many lanes the slots need. 1 whenever no two actions were authored at the same minute. */
|
|
int32 LaneCount = 0;
|
|
|
|
/** Labels of the hour ruler, one every third hour, made once because they never change. */
|
|
TArray<FText> HourLabels;
|
|
|
|
/** The signature of the schedule the strip was last built from. */
|
|
uint32 CachedSignature = 0;
|
|
|
|
/** When that build happened, so that the anchor names can be re-read on a slow timer. */
|
|
double LastBuildTime = 0.0;
|
|
|
|
/** The font the ruler, the slots and the legend are drawn in. */
|
|
FSlateFontInfo Font;
|
|
};
|