// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Input/CursorReply.h" #include "Input/Reply.h" #include "Layout/Geometry.h" #include "Rendering/RenderingCommon.h" #include "Styling/SlateTypes.h" #include "TraceServices/Model/NetProfiler.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/SCompoundWidget.h" // Insights #include "Insights/Common/FixedCircularBuffer.h" #include "Insights/NetworkingProfiler/ViewModels/PacketContentViewDrawHelper.h" #include "Insights/NetworkingProfiler/ViewModels/PacketContentViewport.h" #include "Insights/ViewModels/TooltipDrawState.h" class SScrollBar; class SNetworkingProfilerWindow; //////////////////////////////////////////////////////////////////////////////////////////////////// struct FNetworkPacketEventRef { FNetworkPacketEvent Event; bool bIsValid; FNetworkPacketEventRef() : Event(), bIsValid(false) { } FNetworkPacketEventRef(const FNetworkPacketEvent& InEvent) : Event(InEvent), bIsValid(true) { } FNetworkPacketEventRef(const FNetworkPacketEventRef& Other) : Event(Other.Event), bIsValid(Other.bIsValid) { } FNetworkPacketEventRef& operator=(const FNetworkPacketEventRef& Other) { Event = Other.Event; bIsValid = Other.bIsValid; return *this; } void Set(const FNetworkPacketEvent& InEvent) { Event = InEvent; bIsValid = true; } void Reset() { bIsValid = false; } bool IsValid() const { return bIsValid; } bool Equals(const FNetworkPacketEventRef& Other) const { return bIsValid == Other.bIsValid && Event.Equals(Other.Event); } static bool AreEquals(const FNetworkPacketEventRef& A, const FNetworkPacketEventRef& B) { return A.Equals(B); } }; //////////////////////////////////////////////////////////////////////////////////////////////////// /** * Widget used to present content of a network packet. */ class SPacketContentView: public SCompoundWidget { public: /** Number of pixels. */ static constexpr float MOUSE_SNAP_DISTANCE = 2.0f; enum class ECursorType { Default, Arrow, Hand, }; public: /** Default constructor. */ SPacketContentView(); /** Virtual destructor. */ virtual ~SPacketContentView(); /** Resets internal widget's data to the default one. */ void Reset(); SLATE_BEGIN_ARGS(SPacketContentView) {} SLATE_END_ARGS() void Construct(const FArguments& InArgs, TSharedPtr InProfilerWindow); /** * Ticks this widget. Override in derived classes, but always call the parent implementation. * @param AllottedGeometry The space allotted for this widget * @param InCurrentTime Current absolute real time * @param InDeltaTime Real time passed since last tick */ 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; virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FReply OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual FCursorReply OnCursorQuery(const FGeometry& MyGeometry, const FPointerEvent& CursorEvent) const override; virtual bool SupportsKeyboardFocus() const override { return true; } virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; // virtual FReply OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; void ResetPacket(); void SetPacket(uint32 InGameInstanceIndex, uint32 InConnectionIndex, Trace::ENetProfilerConnectionMode InConnectionMode, uint32 InPacketIndex, int64 InPacketBitSize); bool IsFilterByNetIdEnabled() const { return bFilterByNetId; } uint32 GetFilterNetId() const { return FilterNetId; } void SetFilterNetId(const uint32 InNetId); bool IsFilterByEventTypeEnabled() const { return bFilterByEventType; } uint32 GetFilterEventTypeIndex() const { return FilterEventTypeIndex; } const FText& GetFilterEventName() const { return FilterEventName; } void SetFilterEventType(const uint32 InEventTypeIndex, const FText& InEventName); void EnableFilterEventType(const uint32 InEventTypeIndex); void DisableFilterEventType(); FReply FindFirstEvent(); FReply FindPreviousEvent(); FReply FindNextEvent(); FReply FindLastEvent(); private: FReply FindPreviousPacket_OnClicked(); FReply FindNextPacket_OnClicked(); FText GetPacketText() const; void Packet_OnTextCommitted(const FText& InNewText, ETextCommit::Type InTextCommit); ECheckBoxState FilterByNetId_IsChecked() const; void FilterByNetId_OnCheckStateChanged(ECheckBoxState NewState); FText GetFilterNetIdText() const; void FilterNetId_OnTextCommitted(const FText& InNewText, ETextCommit::Type InTextCommit); ECheckBoxState FilterByEventType_IsChecked() const; void FilterByEventType_OnCheckStateChanged(ECheckBoxState NewState); FText GetFilterEventTypeText() const { return FilterEventName; } ECheckBoxState HighlightFilteredEvents_IsChecked() const; void HighlightFilteredEvents_OnCheckStateChanged(ECheckBoxState NewState); // void ShowContextMenu(const FPointerEvent& MouseEvent); /** Binds our UI commands to delegates. */ void BindCommands(); //////////////////////////////////////////////////////////////////////////////////////////////////// /** * Called when the user scrolls the horizontal scrollbar. * @param ScrollOffset Scroll offset as a fraction between 0 and 1. */ void HorizontalScrollBar_OnUserScrolled(float ScrollOffset); void UpdateHorizontalScrollBar(); void ZoomHorizontally(const float Delta, const float X); void BringIntoView(const float X1, const float X2); void BringEventIntoView(const FNetworkPacketEventRef& EventRef); //////////////////////////////////////////////////////////////////////////////////////////////////// uint32 GetPacketSequence(int32 PacketIndex) const; void UpdateState(); void UpdateHoveredEvent(); FNetworkPacketEventRef GetEventAtMousePosition(float X, float Y); void OnSelectedEventChanged(); void SelectHoveredEvent(); private: TSharedPtr ProfilerWindow; /** The track's viewport. Encapsulates info about position and scale. */ FPacketContentViewport Viewport; bool bIsViewportDirty; float NetEventsOffsetY; uint32 GameInstanceIndex; uint32 ConnectionIndex; Trace::ENetProfilerConnectionMode ConnectionMode; uint32 PacketIndex; uint32 PacketSequence; int64 PacketBitSize; // total number of bits; [bit] bool bFilterByEventType; uint32 FilterEventTypeIndex; FText FilterEventName; bool bFilterByNetId; uint32 FilterNetId; bool bHighlightFilteredEvents; /** Cached draw state of the packet content. */ TSharedRef DrawState; TSharedRef FilteredDrawState; bool bIsStateDirty; ////////////////////////////////////////////////// TSharedPtr HorizontalScrollBar; ////////////////////////////////////////////////// // Panning and Zooming behaviors /** The current mouse position. */ FVector2D MousePosition; /** Mouse position during the call on mouse button down. */ FVector2D MousePositionOnButtonDown; float ViewportPosXOnButtonDown; /** Mouse position during the call on mouse button up. */ FVector2D MousePositionOnButtonUp; bool bIsLMB_Pressed; bool bIsRMB_Pressed; /** True, if the user is currently interactively scrolling the view (ex.: by holding the left mouse button and dragging). */ bool bIsScrolling; ////////////////////////////////////////////////// // Selection FNetworkPacketEventRef HoveredEvent; FNetworkPacketEventRef SelectedEvent; FTooltipDrawState Tooltip; ////////////////////////////////////////////////// // Misc FGeometry ThisGeometry; /** Cursor type. */ ECursorType CursorType; // Debug stats TFixedCircularBuffer UpdateDurationHistory; mutable TFixedCircularBuffer DrawDurationHistory; mutable TFixedCircularBuffer OnPaintDurationHistory; mutable uint64 LastOnPaintTime; };