diff --git a/Source/Integration/InputModeRequest.cpp b/Source/Integration/InputModeRequest.cpp index 5027e12c..261a92c8 100644 --- a/Source/Integration/InputModeRequest.cpp +++ b/Source/Integration/InputModeRequest.cpp @@ -7,6 +7,15 @@ #include "InputModeRequest.h" #include "Common.h" +bool FlxInputModeRequest::operator<(const FlxInputModeRequest &Other) const +{ + // The highest priority request goes to the front of the array. + // Therefore, in this context, 'less than' means 'higher priority'. + // It's a little confusing. + if (ShowPointer != Other.ShowPointer) return ShowPointer > Other.ShowPointer; + return SequenceNumber > Other.SequenceNumber; +} + bool FlxInputModeRequest::operator==(const FlxInputModeRequest &Other) const { return (Widget == Other.Widget) && @@ -26,57 +35,68 @@ bool FlxInputModeRequests::SanityCheck(const FlxInputModeRequest &Request) return true; } -void FlxInputModeRequests::SplitHighLow(View &High, View &Low) + +int32 FlxInputModeRequests::FindWidget(UUserWidget *Widget) { - int32 NumHigh = 0; - while ((NumHigh < Requests.Num()) && (Requests[NumHigh].IsHighPrio())) NumHigh++; - int32 NumLow = Requests.Num() - NumHigh; - High = View(Requests.GetData(), NumHigh); - Low = View(Requests.GetData() + NumHigh, NumLow); + for (const FlxInputModeRequest &Req : Requests) + { + if (Req.Widget == Widget) return &Req - Requests.GetData(); + } + return Requests.Num(); } -void FlxInputModeRequests::Request(const FlxInputModeRequest &NewRequest) +void FlxInputModeRequests::BubbleItem(int32 Index) { - bool IsHigh = NewRequest.IsHighPrio(); + while ((Index > 0) && (Requests[Index] < Requests[Index - 1])) + { + Swap(Requests[Index], Requests[Index - 1]); + --Index; + } + while ((Index < Requests.Num() - 1) && (Requests[Index + 1] < Requests[Index])) + { + Swap(Requests[Index], Requests[Index + 1]); + ++Index; + } +} - // Divide the array into a high-priority slice and a low-priority slice. - View High, Low; - SplitHighLow(High, Low); +void FlxInputModeRequests::Request(const FlxInputModeRequest &NewRequest, bool UpdateSequence) +{ + int32 Index = FindWidget(NewRequest.Widget); - // Stamp this request with a fresh sequence number. - FlxInputModeRequest Stamped = NewRequest; - Stamped.SequenceNumber = ++NextSequenceNumber; + if (Index == Requests.Num()) + { + Requests.Emplace(NewRequest); + Requests[Index].SequenceNumber = ++NextSequenceNumber; + } + else + { + int32 SequenceNumber = Requests[Index].SequenceNumber; + if (UpdateSequence) SequenceNumber = ++NextSequenceNumber; + Requests[Index] = NewRequest; + Requests[Index].SequenceNumber = SequenceNumber; + } - // We're going to build a new version of the requests array. - TArray Updated; - - // Add all high priority requests to the updated array, new request first. - if (IsHigh) Updated.Add(Stamped); - for (const FlxInputModeRequest &Req : High) - if (Req.Widget != NewRequest.Widget) Updated.Add(Req); - - // Add all low priority requests to the updated array, new request first. - if (!IsHigh) Updated.Add(Stamped); - for (const FlxInputModeRequest &Req : Low) - if (Req.Widget != NewRequest.Widget) Updated.Add(Req); - - Swap(Requests, Updated); + BubbleItem(Index); } void FlxInputModeRequests::SetEnableInputComponent(UUserWidget *Widget, bool EnableInputComponent) { - for (FlxInputModeRequest &Req : Requests) + int32 Index = FindWidget(Widget); + + if (Index == Requests.Num()) { - if (Req.Widget == Widget) - { - Req.EnableInputComponent = EnableInputComponent; - return; - } + FlxInputModeRequest NewReq; + NewReq.Widget = Widget; + NewReq.EnableInputComponent = EnableInputComponent; + NewReq.SequenceNumber = ++NextSequenceNumber; + Requests.Emplace(NewReq); } - FlxInputModeRequest NewReq; - NewReq.Widget = Widget; - NewReq.EnableInputComponent = EnableInputComponent; - Request(NewReq); + else + { + Requests[Index].EnableInputComponent = EnableInputComponent; + } + + BubbleItem(Index); } void FlxInputModeRequests::Remove(UUserWidget *Widget) diff --git a/Source/Integration/InputModeRequest.h b/Source/Integration/InputModeRequest.h index 245fe4b1..fbbc582b 100644 --- a/Source/Integration/InputModeRequest.h +++ b/Source/Integration/InputModeRequest.h @@ -34,10 +34,7 @@ struct FlxInputModeRequest FlxInputModeRequest() = default; bool operator == (const FlxInputModeRequest &Other) const; - - // True if this request wants any high-priority resource: - // keyboard focus, the mouse pointer, or input blocking. - bool IsHighPrio() const { return Focus != nullptr || ShowPointer || BlockInput; } + bool operator < (const FlxInputModeRequest &Other) const; UPROPERTY(BlueprintReadWrite) UUserWidget* Widget = nullptr; @@ -73,19 +70,14 @@ private: int32 NextSequenceNumber = 0; public: - using View = TArrayView; - // Get the requests array. const TArray &GetRequests() const { return Requests; } // Sanity check a request to see if it is reasonable. static bool SanityCheck(const FlxInputModeRequest &Request); - // Divide Requests into a high-priority slice and a low-priority slice. - void SplitHighLow(View &High, View &Low); - // Apply a request. Replaces any previous request by the same widget. - void Request(const FlxInputModeRequest &NewRequest); + void Request(const FlxInputModeRequest &NewRequest, bool UpdateSequence = true); // Find the specified widget, and modify the 'EnableInputComponent' // flag. Adds the widget if it's not already present. @@ -96,4 +88,11 @@ public: // Remove any requests by dead widgets or widgets with no parents. void GarbageCollect(); + +private: + // Find specified widget. If not present, returns Requests.Num() + int32 FindWidget(UUserWidget *Widget); + + // Move item at Index to its proper place in the array by priority. + void BubbleItem(int32 Index); };