initial commit; cv 0.0.3
This commit is contained in:
175
Api/UserWidget.hpp
Normal file
175
Api/UserWidget.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <Unreal/NameTypes.hpp>
|
||||
|
||||
#include "Widget.hpp"
|
||||
#include "WidgetTree.hpp"
|
||||
|
||||
namespace PalUIExtension::Api
|
||||
{
|
||||
// ------------------------------------------------------------------
|
||||
// UUserWidget. Base for every WBP_..._C generated class.
|
||||
//
|
||||
// NAMESPACE: this file previously declared itself in
|
||||
// PalStatusOverlay::Api while every other header in the tree is in
|
||||
// PalUIExtension::Api. Nothing included it, so nothing caught it -- the
|
||||
// first #include from dllmain.cpp would have failed to find any of
|
||||
// these types. Fixed; if you have local code referring to
|
||||
// PalStatusOverlay::Api::UserWidget, that is why it no longer resolves.
|
||||
// Static/WidgetRegistry.hpp had the same split and is fixed to match.
|
||||
//
|
||||
// GetWidgetFromName is NOT available on this build. It does not appear
|
||||
// in the UserWidget.h you pulled from UMG.zip, which is UHT's own
|
||||
// generated listing of every UFUNCTION this class has. Stock UE ships
|
||||
// it BlueprintPure; this build either stripped it or the dump is
|
||||
// incomplete.
|
||||
//
|
||||
// That is no longer an obstacle rather than a caveat: FindWidget below
|
||||
// walks the widget tree instead of calling it. See WidgetTree.hpp for
|
||||
// why walking beats both the missing UFUNCTION and the global-object
|
||||
// scan that UnrealApiCall::FindInstance does.
|
||||
// ------------------------------------------------------------------
|
||||
class UserWidget : public Widget
|
||||
{
|
||||
public:
|
||||
static auto ClassPath() -> const TCHAR* { return STR("/Script/UMG.UserWidget"); }
|
||||
static auto DebugTag() -> const TCHAR* { return STR("UserWidget"); }
|
||||
|
||||
UserWidget() = default;
|
||||
explicit UserWidget(UObject* Obj)
|
||||
: Widget(Obj, ClassOf<UserWidget>(), DebugTag()) {}
|
||||
|
||||
// ---- the widget tree ------------------------------------------
|
||||
//
|
||||
// WidgetTree is a plain UPROPERTY (Transient/DuplicateTransient,
|
||||
// not a bitfield) -- direct property read, no ProcessEvent frame.
|
||||
auto GetWidgetTree() const -> WidgetTree
|
||||
{
|
||||
return WidgetTree::FromUserWidget(m_obj);
|
||||
}
|
||||
|
||||
// Find a widget by its designer name anywhere in THIS widget's
|
||||
// tree. Replaces the GetWidgetFromName call this class used to make
|
||||
// opportunistically.
|
||||
//
|
||||
// Scope defaults to ThisTreeOnly -- names are unique per tree, not
|
||||
// globally, and a nested WBP has its own "Text_PalName" just like
|
||||
// its parent does. See WidgetTree::EScope.
|
||||
auto FindWidget(const TCHAR* Name,
|
||||
WidgetTree::EScope Scope = WidgetTree::EScope::ThisTreeOnly) -> Widget
|
||||
{
|
||||
return GetWidgetTree().Find(Name, Scope);
|
||||
}
|
||||
|
||||
auto FindWidgetObject(const TCHAR* Name,
|
||||
WidgetTree::EScope Scope = WidgetTree::EScope::ThisTreeOnly) -> UObject*
|
||||
{
|
||||
return GetWidgetTree().FindObjectByName(Name, Scope);
|
||||
}
|
||||
|
||||
// Typed variant: UserWidget{W}.FindWidgetAs<CanvasPanel>(STR("Canvas_Base"))
|
||||
template <typename T>
|
||||
auto FindWidgetAs(const TCHAR* Name,
|
||||
WidgetTree::EScope Scope = WidgetTree::EScope::ThisTreeOnly) -> T
|
||||
{
|
||||
return GetWidgetTree().FindAs<T>(Name, Scope);
|
||||
}
|
||||
|
||||
// ---- bound widget properties ------------------------------------
|
||||
//
|
||||
// The OTHER way to reach a child, and the cheaper one when it
|
||||
// applies. UMG promotes any widget marked "Is Variable" in the
|
||||
// designer to a UPROPERTY on the generated class, so the pointer
|
||||
// sits at a fixed offset -- no walk at all. PalDetailWidget's
|
||||
// CanvasBase()/TextPalName()/etc. are exactly this.
|
||||
//
|
||||
// The catch, and the reason FindWidget still earns its place: this
|
||||
// only works for widgets that were marked as variables. Anything
|
||||
// left unpromoted (most auto-named CanvasPanel_N containers) has no
|
||||
// property and can only be found by walking.
|
||||
auto BoundObject(const TCHAR* Name) const -> UObject*
|
||||
{
|
||||
return TryObjectProperty(Name);
|
||||
}
|
||||
|
||||
// Property first, tree walk second. Use this when you do not know
|
||||
// whether a given child was promoted to a variable, and do not want
|
||||
// to care.
|
||||
auto ChildObject(const TCHAR* Name,
|
||||
WidgetTree::EScope Scope = WidgetTree::EScope::ThisTreeOnly) -> UObject*
|
||||
{
|
||||
if (UObject* Bound = BoundObject(Name)) return Bound;
|
||||
return FindWidgetObject(Name, Scope);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto Child(const TCHAR* Name,
|
||||
WidgetTree::EScope Scope = WidgetTree::EScope::ThisTreeOnly) -> T
|
||||
{
|
||||
UObject* O = ChildObject(Name, Scope);
|
||||
if (!O)
|
||||
{
|
||||
Output::send<LogLevel::Warning>(
|
||||
STR("[{}] no child named '{}' (neither a bound variable nor in the tree)\n"),
|
||||
m_tag, Name);
|
||||
return T{};
|
||||
}
|
||||
if (!ObjectIsA<T>(O))
|
||||
{
|
||||
Output::send<LogLevel::Warning>(
|
||||
STR("[{}] child '{}' resolved to {}, which is not a {}\n"),
|
||||
m_tag, Name, O->GetFullName(), T::DebugTag());
|
||||
return T{};
|
||||
}
|
||||
return T{ O };
|
||||
}
|
||||
|
||||
// ---- viewport lifecycle -------------------------------------------
|
||||
auto AddToViewport(int32 ZOrder) -> bool
|
||||
{
|
||||
struct P { int32 ZOrder; } p{ ZOrder };
|
||||
return Call(STR("AddToViewport"), p);
|
||||
}
|
||||
auto RemoveFromViewport() -> bool { return CallVoid(STR("RemoveFromViewport")); }
|
||||
|
||||
auto GetIsVisible() -> std::optional<bool> { return CallForReturn<bool>(STR("GetIsVisible")); }
|
||||
|
||||
// BlueprintImplementableEvent. Dispatch is by the object's own
|
||||
// class chain regardless of native-vs-event, so this call works
|
||||
// the same either way -- but if no Blueprint graph overrides it,
|
||||
// the engine's default thunk hands back bool's zero value (false),
|
||||
// not an error. A false here does not prove non-interactable.
|
||||
auto IsInteractable() -> std::optional<bool> { return CallForReturn<bool>(STR("IsInteractable")); }
|
||||
|
||||
// ---- cosmetic setters ----------------------------------------------
|
||||
auto SetPadding(FMargin_ InPadding) -> bool
|
||||
{
|
||||
struct P { FMargin_ InPadding; } p{ InPadding };
|
||||
return Call(STR("SetPadding"), p);
|
||||
}
|
||||
auto SetColorAndOpacity(FLinearColor_ InColorAndOpacity) -> bool
|
||||
{
|
||||
struct P { FLinearColor_ InColorAndOpacity; } p{ InColorAndOpacity };
|
||||
return Call(STR("SetColorAndOpacity"), p);
|
||||
}
|
||||
auto SetForegroundColor(FSlateColor_ InForegroundColor) -> bool
|
||||
{
|
||||
struct P { FSlateColor_ InForegroundColor; } p{ InForegroundColor };
|
||||
return Call(STR("SetForegroundColor"), p);
|
||||
}
|
||||
|
||||
// ---- plain properties ------------------------------------------
|
||||
auto GetPriority() const -> std::optional<int32> { return PropertyValue<int32>(STR("Priority")); }
|
||||
auto GetColorAndOpacity()const -> std::optional<FLinearColor_>{ return PropertyValue<FLinearColor_>(STR("ColorAndOpacity")); }
|
||||
auto GetPaddingValue() const -> std::optional<FMargin_> { return PropertyValue<FMargin_>(STR("Padding")); }
|
||||
// bIsFocusable / bStopAction / bHasScriptImplementedTick /
|
||||
// bHasScriptImplementedPaint are packed uint8:1 bitfields -- not
|
||||
// exposed, same reasoning as UWidget::bIsEnabled in Widget.hpp.
|
||||
// No UFUNCTION getter exists for any of them either; there is no
|
||||
// clean substitute, only a byte read and a manual mask.
|
||||
|
||||
protected:
|
||||
UserWidget(UObject* Obj, UClass* Expected, const TCHAR* Tag)
|
||||
: Widget(Obj, Expected, Tag) {}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user