[
  {
    "path": ".gitignore",
    "content": "# Visual Studio 2015 user specific files\n.vs/\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n*.ipa\n\n# These project files can be generated by the engine\n*.xcodeproj\n*.xcworkspace\n*.sln\n*.suo\n*.opensdf\n*.sdf\n*.VC.db\n*.VC.opendb\n\n# Precompiled Assets\nSourceArt/**/*.png\nSourceArt/**/*.tga\n\n# Binary Files\nBinaries/*\nPlugins/*/Binaries/*\n\n# Builds\nBuild/*\n\n# Whitelist PakBlacklist-<BuildConfiguration>.txt files\n!Build/*/\nBuild/*/**\n!Build/*/PakBlacklist*.txt\n\n# Don't ignore icon files in Build\n!Build/**/*.ico\n\n# Built data for maps\n*_BuiltData.uasset\n\n# Configuration files generated by the Editor\nSaved/*\n\n# Compiled source files for the engine to use\nIntermediate/*\nPlugins/*/Intermediate/*\n\n# Cache files for the editor to use\nDerivedDataCache/*\n"
  },
  {
    "path": "FairyGUI.uplugin",
    "content": "{\n\t\"FileVersion\": 3,\n\t\"Version\": 1,\n\t\"VersionName\": \"1.0\",\n\t\"FriendlyName\": \"FairyGUI\",\n\t\"Description\": \"FairyGUI is a cross-engine UI Solution\",\n\t\"Category\": \"UI\",\n\t\"CreatedBy\": \"fairygui.com\",\n\t\"CreatedByURL\": \"https://fairygui.com\",\n\t\"DocsURL\": \"\",\n\t\"MarketplaceURL\": \"\",\n\t\"SupportURL\": \"\",\n\t\"CanContainContent\": true,\n\t\"IsBetaVersion\": false,\n\t\"IsExperimentalVersion\": false,\n\t\"Installed\": false,\n\t\"Modules\": [\n\t\t{\n\t\t\t\"Name\": \"FairyGUI\",\n\t\t\t\"Type\": \"Runtime\",\n\t\t\t\"LoadingPhase\": \"Default\"\n\t\t},\n\t\t{\n\t\t\t\"Name\": \"FairyGUIEditor\",\n\t\t\t\"Type\": \"Editor\",\n\t\t\t\"LoadingPhase\": \"Default\"\n\t\t}\n\t]\n}"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 FairyGUI\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# FairyGUI-unreal\nA flexible UI framework for Unreal Engine\n\nSuggest to start from [Examples](https://github.com/fairygui/FairyGUI-unreal-example)"
  },
  {
    "path": "Source/FairyGUI/FairyGUI.Build.cs",
    "content": "// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.\n\nusing UnrealBuildTool;\n\npublic class FairyGUI : ModuleRules\n{\n\tpublic FairyGUI(ReadOnlyTargetRules Target) : base(Target)\n\t{\n\t\tPCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;\n\t\t\n\t\tPublicIncludePaths.AddRange(\n\t\t\tnew string[] {\n\t\t\t\t// ... add public include paths required here ...\n\t\t\t}\n\t\t\t);\n\t\t\t\t\n\t\t\n\t\tPrivateIncludePaths.AddRange(\n\t\t\tnew string[] {\n\t\t\t\t// ... add other private include paths required here ...\n\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\n\t\tPublicDependencyModuleNames.AddRange(\n\t\t\tnew string[]\n\t\t\t{\n\t\t\t\t\"Core\",\n\t\t\t\t// ... add other public dependencies that you statically link with here ...\n\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\n\t\tPrivateDependencyModuleNames.AddRange(\n\t\t\tnew string[]\n\t\t\t{\n\t\t\t\t\"CoreUObject\",\n\t\t\t\t\"Engine\",\n                \"InputCore\",\n                \"Slate\",\n\t\t\t\t\"SlateCore\",\n\t\t\t\t// ... add private dependencies that you statically link with here ...\t\n\t\t\t}\n\t\t\t);\n\n        if (Target.bBuildEditor == true)\n        {\n            PrivateDependencyModuleNames.Add(\"UnrealEd\");\n        }\n\n        DynamicallyLoadedModuleNames.AddRange(\n\t\t\tnew string[]\n\t\t\t{\n\t\t\t\t// ... add any modules that your module loads dynamically here ...\n\t\t\t}\n\t\t\t);\n\t}\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Event/EventContext.cpp",
    "content": "#include \"Event/EventContext.h\"\n"
  },
  {
    "path": "Source/FairyGUI/Private/Event/EventTypes.cpp",
    "content": "#include \"Event/EventTypes.h\"\n\nconst FName FUIEvents::Click(\"Click\");\nconst FName FUIEvents::TouchBegin(\"TouchBegin\");\nconst FName FUIEvents::TouchMove(\"TouchMove\");\nconst FName FUIEvents::TouchEnd(\"TouchEnd\");\nconst FName FUIEvents::RollOver(\"RollOver\");\nconst FName FUIEvents::RollOut(\"RollOut\");\nconst FName FUIEvents::MouseWheel(\"MouseWheel\");\n\nconst FName FUIEvents::DragStart(\"DragStart\");\nconst FName FUIEvents::DragMove(\"DragMove\");\nconst FName FUIEvents::DragEnd(\"DragEnd\");\nconst FName FUIEvents::Drop(\"Drop\");\n\nconst FName FUIEvents::AddedToStage(\"AddedToStage\");\nconst FName FUIEvents::RemovedFromStage(\"RemovedFromStage\");\n\nconst FName FUIEvents::Changed(\"Changed\");\nconst FName FUIEvents::ClickItem(\"ClickItem\");\nconst FName FUIEvents::ClickLink(\"ClickLink\");\nconst FName FUIEvents::GearStop(\"GearStop\");\n\nconst FName FUIEvents::Scroll(\"Scroll\");\nconst FName FUIEvents::ScrollEnd(\"ScrollEnd\");\nconst FName FUIEvents::PullDownRelease(\"PullDownRelease\");\nconst FName FUIEvents::PullUpRelease(\"PullUpRelease\");\n\nconst FName FUIEvents::Submit(\"Submit\");\n"
  },
  {
    "path": "Source/FairyGUI/Private/FairyApplication.cpp",
    "content": "#include \"FairyApplication.h\"\n#include \"Framework/Application/SlateApplication.h\"\n#include \"Slate/SGameLayerManager.h\"\n#include \"UIPackageAsset.h\"\n#include \"UI/GRoot.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/UIObjectFactory.h\"\n#include \"UI/PackageItem.h\"\n#include \"UI/GWindow.h\"\n#include \"UI/PopupMenu.h\"\n#include \"UI/DragDropManager.h\"\n#include \"Tween/TweenManager.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Utils/ByteBuffer.h\"\n\nTMap<uint32, UFairyApplication*> UFairyApplication::Instances;\n\nstruct FMyScopedSwitchWorldHack\n{\n    FMyScopedSwitchWorldHack(UWorld* World)\n    {\n        PrevWorld = GWorld;\n        GWorld = World;\n    }\n\n    ~FMyScopedSwitchWorldHack()\n    {\n        GWorld = PrevWorld;\n    }\n    UWorld* PrevWorld;\n};\n\nUFairyApplication::FTouchInfo::FTouchInfo() :\n    UserIndex(0),\n    PointerIndex(0),\n    bDown(false),\n    DownPosition(0, 0),\n    bClickCancelled(false),\n    ClickCount(0)\n{\n}\n\nUFairyApplication::FInputProcessor::FInputProcessor(UFairyApplication* InApplication)\n{\n    Application = InApplication;\n}\n\nvoid UFairyApplication::FInputProcessor::Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Cursor)\n{\n}\n\nbool UFairyApplication::FInputProcessor::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent)\n{\n    Application->PreviewDownEvent(MouseEvent);\n\n    return false;\n}\n\nbool UFairyApplication::FInputProcessor::HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent)\n{\n    Application->PreviewUpEvent(MouseEvent);\n    return false;\n}\n\nbool UFairyApplication::FInputProcessor::HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent)\n{\n    Application->PreviewMoveEvent(MouseEvent);\n    return false;\n}\n\nUFairyApplication* UFairyApplication::Get(UObject* WorldContextObject)\n{\n    UWorld* World = WorldContextObject->GetWorld();\n    verifyf(World != nullptr, TEXT(\"Null World?\"));\n    verifyf(World->IsGameWorld(), TEXT(\"Not a Game World?\"));\n\n    UFairyApplication* Instance = Instances.FindRef(World->GetGameInstance()->GetUniqueID());\n    if (Instance == nullptr)\n    {\n        Instance = NewObject<UFairyApplication>();\n        Instances.Add(World->GetGameInstance()->GetUniqueID(), Instance);\n        Instance->GameInstance = World->GetGameInstance();\n        Instance->AddToRoot();\n        Instance->OnCreate();\n    }\n    return Instance;\n}\n\nvoid UFairyApplication::Destroy()\n{\n    FUIObjectFactory::PackageItemExtensions.Reset();\n    FUIObjectFactory::LoaderExtension = nullptr;\n\n    UNTexture::DestroyWhiteTexture();\n    UUIPackageStatic::Destroy();\n    FUIConfig::Config = FUIConfig(); //Reset Configuration to default values\n\n    for (auto& it : Instances)\n    {\n        it.Value->RemoveFromRoot();\n        it.Value->OnDestroy();\n    }\n    Instances.Reset();\n}\n\nUFairyApplication::UFairyApplication() :\n    bSoundEnabled(true),\n    SoundVolumeScale(1)\n{\n    LastTouch = new FTouchInfo();\n    Touches.Add(LastTouch);\n}\n\nvoid UFairyApplication::OnCreate()\n{\n    ViewportClient = GameInstance->GetWorld()->GetGameViewport();\n    if (ViewportClient == nullptr)\n        return;\n\n    ViewportWidget = ViewportClient->GetGameViewportWidget();\n\n    DragDropManager = NewObject<UDragDropManager>(this);\n    DragDropManager->CreateAgent();\n\n    PostTickDelegateHandle = FSlateApplication::Get().OnPostTick().AddUObject(this, &UFairyApplication::OnSlatePostTick);\n\n    InputProcessor = MakeShareable(new FInputProcessor(this));\n    FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor);\n\n}\n\nvoid UFairyApplication::OnDestroy()\n{\n    FTweenManager::Singleton.Reset();\n\n    if (InputProcessor.IsValid())\n        FSlateApplication::Get().UnregisterInputPreProcessor(InputProcessor);\n\n    if (PostTickDelegateHandle.IsValid())\n        FSlateApplication::Get().OnPostTick().Remove(PostTickDelegateHandle);\n}\n\nUGRoot* UFairyApplication::GetUIRoot() const\n{\n    if (UIRoot == nullptr)\n    {\n        UFairyApplication* This = const_cast<UFairyApplication*>(this);\n        This->UIRoot = NewObject<UGRoot>(This);\n        This->UIRoot->AddToViewport();\n    }\n\n    return UIRoot;\n}\n\nvoid UFairyApplication::CallAfterSlateTick(FSimpleDelegate Callback)\n{\n    PostTickMulticastDelegate.Add(Callback);\n}\n\nvoid UFairyApplication::OnSlatePostTick(float DeltaTime)\n{\n    if (PostTickMulticastDelegate.IsBound())\n    {\n        FSimpleMulticastDelegate Clone = PostTickMulticastDelegate;\n        PostTickMulticastDelegate.Clear();\n        Clone.Broadcast();\n    }\n\n    if (bNeedCheckPopups)\n    {\n        bNeedCheckPopups = false;\n\n        if (UIRoot != nullptr)\n            UIRoot->CheckPopups(nullptr);\n    }\n}\n\nFVector2D UFairyApplication::GetTouchPosition(int32 InUserIndex, int32 InPointerIndex)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex);\n    if (TouchInfo != nullptr)\n        return TouchInfo->Event.GetScreenSpacePosition();\n    else\n        return FVector2D::ZeroVector;\n}\n\nint32 UFairyApplication::GetTouchCount() const\n{\n    int32 Count = 0;\n    for (auto& it : Touches)\n    {\n        if (it.bDown)\n            Count++;\n    }\n\n    return Count;\n}\n\nUGObject* UFairyApplication::GetObjectUnderPoint(const FVector2D& ScreenspacePosition)\n{\n    TArray<TSharedRef<SWindow>> Windows;\n    Windows.Add(ViewportClient->GetWindow().ToSharedRef());\n    FWidgetPath WidgetPath = FSlateApplication::Get().LocateWindowUnderMouse(ScreenspacePosition, Windows, false);\n\n    if (WidgetPath.IsValid())\n        return SDisplayObject::GetWidgetGObject(WidgetPath.GetLastWidget());\n    else\n        return nullptr;\n}\n\nvoid UFairyApplication::CancelClick(int32 InUserIndex, int32 InPointerIndex)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex);\n    if (TouchInfo != nullptr)\n        TouchInfo->bClickCancelled = true;\n}\n\nvoid UFairyApplication::PlaySound(const FString& URL, float VolumnScale)\n{\n    if (!bSoundEnabled)\n        return;\n\n    TSharedPtr<FPackageItem> SoundItem = UUIPackage::GetItemByURL(URL);\n    if (SoundItem.IsValid())\n    {\n        SoundItem->Load();\n        FSlateApplication::Get().PlaySound(*SoundItem->Sound);\n    }\n}\n\nvoid UFairyApplication::SetSoundEnabled(bool bEnabled)\n{\n    bSoundEnabled = bEnabled;\n}\n\nvoid UFairyApplication::SetSoundVolumeScale(float VolumnScale)\n{\n    SoundVolumeScale = VolumnScale;\n}\n\nbool UFairyApplication::DispatchEvent(const FName& EventType, const TSharedRef<SWidget>& Initiator, const FNVariant& Data)\n{\n    UGObject* Obj = SDisplayObject::GetWidgetGObject(Initiator);\n    if (Obj == nullptr)\n        return false;\n\n    UEventContext* Context = BorrowEventContext();\n    Context->Type = EventType;\n    Context->Initiator = Obj;\n    Context->Sender = Obj;\n    Context->Data = Data;\n\n    Context->Sender->InvokeEventDelegate(Context);\n\n    ReturnEventContext(Context);\n\n    return Context->bDefaultPrevented;\n}\n\nvoid UFairyApplication::BubbleEvent(const FName& EventType, const TSharedRef<SWidget>& Initiator, const FNVariant& Data)\n{\n    TArray<UGObject*> CallChain;\n    SDisplayObject::GetWidgetPathToRoot(Initiator, CallChain);\n    if (CallChain.Num() == 0)\n        return;\n\n    InternalBubbleEvent(EventType, CallChain, Data);\n}\n\nvoid UFairyApplication::InternalBubbleEvent(const FName& EventType, const TArray<UGObject*>& CallChain, const FNVariant& Data)\n{\n    UEventContext* Context = BorrowEventContext();\n    Context->Type = EventType;\n    Context->Initiator = CallChain[0];\n    Context->Data = Data;\n\n    for (auto& it : CallChain)\n    {\n        Context->Sender = it;\n        it->InvokeEventDelegate(Context);\n\n        if (Context->bIsMouseCaptor)\n        {\n            Context->bIsMouseCaptor = false;\n            AddMouseCaptor(Context->GetUserIndex(), (int32)Context->GetPointerIndex(), it);\n        }\n\n        if (Context->IsPropagationStopped())\n            break;\n    }\n\n    ReturnEventContext(Context);\n}\n\nvoid UFairyApplication::BroadcastEvent(const FName& EventType, const TSharedRef<SWidget>& Initiator, const FNVariant& Data)\n{\n    TArray<UGObject*> CallChain;\n    SDisplayObject::GetWidgetDescendants(Initiator, CallChain);\n    if (CallChain.Num() == 0)\n        return;\n\n    UEventContext* Context = BorrowEventContext();\n    Context->Type = EventType;\n    Context->Data = Data;\n\n    for (auto& it : CallChain)\n    {\n        Context->Sender = it;\n        Context->Initiator = it;\n        it->InvokeEventDelegate(Context);\n    }\n\n    ReturnEventContext(Context);\n}\n\nUEventContext* UFairyApplication::BorrowEventContext()\n{\n    UEventContext* Context;\n    if (EventContextPool.Num() > 0)\n    {\n        Context = EventContextPool.Pop();\n        Context->bDefaultPrevented = false;\n        Context->bStopped = false;\n        Context->bIsMouseCaptor = false;\n    }\n    else\n        Context = NewObject<UEventContext>(this);\n    Context->PointerEvent = &LastTouch->Event;\n    Context->ClickCount = LastTouch->ClickCount;\n    //Context->KeyEvent = &LastKeyEvent;\n\n    return Context;\n}\n\nvoid UFairyApplication::ReturnEventContext(UEventContext* Context)\n{\n    Context->Data.Reset();\n    EventContextPool.Add(Context);\n}\n\nvoid UFairyApplication::AddMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex);\n    if (TouchInfo != nullptr && !TouchInfo->MouseCaptors.Contains(InTarget))\n        TouchInfo->MouseCaptors.Add(InTarget);\n}\n\nvoid UFairyApplication::RemoveMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex);\n    if (TouchInfo != nullptr)\n        TouchInfo->MouseCaptors.Remove(InTarget);\n}\n\nbool UFairyApplication::HasMouseCaptor(int32 InUserIndex, int32 InPointerIndex)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(InUserIndex, InPointerIndex);\n    return TouchInfo != nullptr && TouchInfo->MouseCaptors.Num() > 0;\n}\n\nUFairyApplication::FTouchInfo* UFairyApplication::GetTouchInfo(const FPointerEvent& MouseEvent)\n{\n    FTouchInfo* TouchInfo = nullptr;\n    for (auto& it : Touches)\n    {\n        if (it.UserIndex == MouseEvent.GetUserIndex() && it.PointerIndex == (int32)MouseEvent.GetPointerIndex())\n        {\n            TouchInfo = &it;\n            break;\n        }\n    }\n\n    if (TouchInfo == nullptr)\n    {\n        TouchInfo = new FTouchInfo();\n        Touches.Add(TouchInfo);\n        TouchInfo->UserIndex = MouseEvent.GetUserIndex();\n        TouchInfo->PointerIndex = (int32)MouseEvent.GetPointerIndex();\n    }\n\n    LastTouch = TouchInfo;\n    return TouchInfo;\n}\n\nUFairyApplication::FTouchInfo* UFairyApplication::GetTouchInfo(int32 InUserIndex, int32 InPointerIndex)\n{\n    if (InUserIndex == -1 && InPointerIndex == -1)\n        return LastTouch;\n\n    for (auto& it : Touches)\n    {\n        if (it.UserIndex == InUserIndex && it.PointerIndex == InPointerIndex)\n        {\n            return &it;\n        }\n    }\n    return nullptr;\n}\n\nvoid UFairyApplication::PreviewDownEvent(const FPointerEvent& MouseEvent)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    TouchInfo->Event = MouseEvent;\n    TouchInfo->bDown = true;\n    TouchInfo->DownPosition = MouseEvent.GetScreenSpacePosition();\n    TouchInfo->bClickCancelled = false;\n    TouchInfo->ClickCount = 1;\n    TouchInfo->MouseCaptors.Reset();\n    TouchInfo->bToClearCaptors = false;\n    TouchInfo->DownPath.Reset();\n\n    bNeedCheckPopups = true;\n}\n\nvoid UFairyApplication::PreviewUpEvent(const FPointerEvent& MouseEvent)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    TouchInfo->Event = MouseEvent;\n    TouchInfo->bDown = false;\n    TouchInfo->bToClearCaptors = true;\n\n    if (TouchInfo->MouseCaptors.Num() > 0)\n    {\n        FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n        int32 cnt = TouchInfo->MouseCaptors.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            auto& Captor = TouchInfo->MouseCaptors[i];\n            if (Captor.IsValid() && Captor->OnStage())\n            {\n                DispatchEvent(FUIEvents::TouchEnd, Captor->GetDisplayObject());\n            }\n        }\n    }\n}\n\nvoid UFairyApplication::PreviewMoveEvent(const FPointerEvent& MouseEvent)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    TouchInfo->Event = MouseEvent;\n\n    if ((TouchInfo->DownPosition - MouseEvent.GetScreenSpacePosition()).GetAbsMax() > 50)\n        TouchInfo->bClickCancelled = true;\n\n    if (!TouchInfo->bToClearCaptors && TouchInfo->MouseCaptors.Num() > 0)\n    {\n        FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n        int32 cnt = TouchInfo->MouseCaptors.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            auto& Captor = TouchInfo->MouseCaptors[i];\n            if (Captor.IsValid() && Captor->OnStage())\n            {\n                DispatchEvent(FUIEvents::TouchMove, Captor->GetDisplayObject());\n            }\n        }\n    }\n}\n\nFReply UFairyApplication::OnWidgetMouseButtonDown(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n\n    UGObject* InitialGObject = nullptr;\n    TSharedPtr<SWidget> Ptr = Widget;\n    while (Ptr.IsValid() && Ptr != ViewportWidget)\n    {\n        TouchInfo->DownPath.Add(Ptr);\n\n        if (InitialGObject == nullptr && Ptr->GetTag() == SDisplayObject::SDisplayObjectTag)\n        {\n            InitialGObject = StaticCastSharedPtr<SDisplayObject>(Ptr)->GObject.Get();\n        }\n\n        Ptr = Ptr->GetParentWidget();\n    }\n\n    bNeedCheckPopups = false;\n    if (UIRoot != nullptr)\n        UIRoot->CheckPopups(&Widget.Get());\n\n    BubbleEvent(FUIEvents::TouchBegin, Widget);\n\n    return FReply::Handled();\n}\n\nFReply UFairyApplication::OnWidgetMouseButtonUp(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    if (TouchInfo == nullptr)\n        return FReply::Handled().ReleaseMouseCapture();\n\n    TArray<UGObject*> CallChain;\n    SDisplayObject::GetWidgetPathToRoot(Widget, CallChain);\n    if (CallChain.Num() > 0)\n    {\n        for (auto& it : TouchInfo->MouseCaptors)\n        {\n            if (it.IsValid())\n                CallChain.RemoveSingle(it.Get());\n        }\n\n        if (CallChain.Num() > 0)\n            InternalBubbleEvent(FUIEvents::TouchEnd, CallChain, FNVariant::Null);\n    }\n    TouchInfo->MouseCaptors.Reset();\n\n    if (!TouchInfo->bClickCancelled)\n    {\n        TSharedPtr<SWidget> Ptr = Widget;\n        while (Ptr.IsValid() && Ptr != ViewportWidget)\n        {\n            if (TouchInfo->DownPath.Contains(Ptr))\n            {\n                BubbleEvent(FUIEvents::Click, Ptr.ToSharedRef());\n                break;\n            }\n\n            Ptr = Ptr->GetParentWidget();\n        }\n    }\n\n    TouchInfo->DownPath.Reset();\n\n    return FReply::Handled().ReleaseMouseCapture();\n}\n\nFReply UFairyApplication::OnWidgetMouseMove(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    return FReply::Handled();\n}\n\nFReply UFairyApplication::OnWidgetMouseButtonDoubleClick(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    TouchInfo->ClickCount = 2;\n\n    return OnWidgetMouseButtonDown(Widget, MyGeometry, MouseEvent);\n}\n\nvoid UFairyApplication::OnWidgetMouseEnter(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    DispatchEvent(FUIEvents::RollOver, Widget);\n}\n\nvoid UFairyApplication::OnWidgetMouseLeave(const TSharedRef<SWidget>& Widget, const FPointerEvent& MouseEvent)\n{\n    FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    DispatchEvent(FUIEvents::RollOut, Widget);\n}\n\nFReply UFairyApplication::OnWidgetMouseWheel(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    FMyScopedSwitchWorldHack SwitchWorld(GameInstance->GetWorld());\n\n    FTouchInfo* TouchInfo = GetTouchInfo(MouseEvent);\n    TouchInfo->Event = MouseEvent;\n\n    BubbleEvent(FUIEvents::MouseWheel, Widget);\n\n    return FReply::Handled();\n}"
  },
  {
    "path": "Source/FairyGUI/Private/FairyBlueprintLibrary.cpp",
    "content": "#include \"FairyBlueprintLibrary.h\"\n#include \"UI/UIConfig.h\"\n#include \"UI/UIObjectFactory.h\"\n#include \"Tween/GTween.h\"\n\nconst FUIConfig& UFairyBlueprintLibrary::GetUIConfig()\n{\n    return FUIConfig::Config;\n}\n\nvoid UFairyBlueprintLibrary::SetUIConfig(const FUIConfig& InConfig)\n{\n    FUIConfig::Config = InConfig;\n}\n\nbool UFairyBlueprintLibrary::GetVariantAsBool(UPARAM(ref) FNVariant& InVariant)\n{\n    return InVariant.AsBool();\n}\n\nint32 UFairyBlueprintLibrary::GetVariantAsInt(UPARAM(ref) FNVariant& InVariant)\n{\n    return InVariant.AsInt();\n}\n\nfloat UFairyBlueprintLibrary::GetVariantAsFloat(UPARAM(ref) FNVariant& InVariant)\n{\n    return InVariant.AsFloat();\n}\n\nFString UFairyBlueprintLibrary::GetVariantAsString(UPARAM(ref) FNVariant& InVariant)\n{\n    return InVariant.AsString();\n}\n\nFColor UFairyBlueprintLibrary::GetVariantAsColor(UPARAM(ref) FNVariant& InVariant)\n{\n    return InVariant.AsColor();\n}\n\nUObject* UFairyBlueprintLibrary::GetVariantAsUObject(UPARAM(ref) FNVariant& InVariant, TSubclassOf<UObject> ClassType)\n{\n    return InVariant.AsUObject();\n}\n\nFNVariant& UFairyBlueprintLibrary::SetVariantBool(UPARAM(ref) FNVariant& InVariant, bool bInValue)\n{\n    InVariant = bInValue;\n    return InVariant;\n}\n\nFNVariant& UFairyBlueprintLibrary::SetVariantInt(UPARAM(ref) FNVariant& InVariant, int32 InValue)\n{\n    InVariant = InValue;\n    return InVariant;\n}\n\nFNVariant& UFairyBlueprintLibrary::SetVariantFloat(UPARAM(ref) FNVariant& InVariant, float InValue)\n{\n    InVariant = InValue;\n    return InVariant;\n}\n\nFNVariant& UFairyBlueprintLibrary::SetVariantString(UPARAM(ref) FNVariant& InVariant, const FString& InValue)\n{\n    InVariant = InValue;\n    return InVariant;\n}\n\nFNVariant& UFairyBlueprintLibrary::SetVariantColor(UPARAM(ref) FNVariant& InVariant, const FColor& InValue)\n{\n    InVariant = InValue;\n    return InVariant;\n}\n\nFNVariant& UFairyBlueprintLibrary::SetVariantUObject(UPARAM(ref) FNVariant& InVariant, UObject* InValue)\n{\n    InVariant = (void*)InValue;\n    return InVariant;\n}\n\nFTweenerHandle UFairyBlueprintLibrary::TweenFloat(float StartValue, float EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete)\n{\n    const UObject* Target = nullptr;\n    if (OnUpdate.IsBound())\n        Target = OnUpdate.GetUObject();\n    else\n        Target = OnComplete.GetUObject();\n\n    if (Target == nullptr)\n        return FTweenerHandle();\n\n    FGTweener* Tweener = FGTween::To(StartValue, EndValue, Duration)\n        ->SetEase(EaseType)\n        ->SetRepeat(Repeat)\n        ->SetTarget(const_cast<UObject*>(Target));\n    if (OnUpdate.IsBound())\n    {\n        Tweener->OnUpdate(FTweenDelegate::CreateLambda([OnUpdate](FGTweener* Tweener) {\n            OnUpdate.ExecuteIfBound(Tweener->Value, Tweener->DeltaValue);\n        }));\n    }\n\n    if (OnComplete.IsBound())\n    {\n        Tweener->OnComplete(FSimpleDelegate::CreateLambda([OnComplete]() {\n            OnComplete.ExecuteIfBound();\n        }));\n    }\n\n    return Tweener->GetHandle();\n}\n\nFTweenerHandle UFairyBlueprintLibrary::TweenVector2(const FVector2D& StartValue, const FVector2D& EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete)\n{\n    const UObject* Target = nullptr;\n    if (OnUpdate.IsBound())\n        Target = OnUpdate.GetUObject();\n    else\n        Target = OnComplete.GetUObject();\n\n    if (Target == nullptr)\n        return FTweenerHandle();\n\n    FGTweener* Tweener = FGTween::To(StartValue, EndValue, Duration)\n        ->SetEase(EaseType)\n        ->SetRepeat(Repeat)\n        ->SetTarget(const_cast<UObject*>(Target));\n\n    if (OnUpdate.IsBound())\n    {\n        Tweener->OnUpdate(FTweenDelegate::CreateLambda([OnUpdate](FGTweener* Tweener) {\n            OnUpdate.ExecuteIfBound(Tweener->Value, Tweener->DeltaValue);\n        }));\n    }\n\n    if (OnComplete.IsBound())\n    {\n        Tweener->OnComplete(FSimpleDelegate::CreateLambda([OnComplete]() {\n            OnComplete.ExecuteIfBound();\n        }));\n    }\n\n    return Tweener->GetHandle();\n}\n\nvoid UFairyBlueprintLibrary::KillTween(UPARAM(ref) FTweenerHandle& Handle, bool bSetComplete)\n{\n    FGTween::Kill(Handle, bSetComplete);\n}\n\nvoid UFairyBlueprintLibrary::SetPackageItemExtension(const FString& URL, TSubclassOf<UGComponent> ClassType)\n{\n    FUIObjectFactory::SetExtension(URL, ClassType);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/FairyCommons.cpp",
    "content": "#include \"FairyCommons.h\"\n#include \"Framework/Application/SlateApplication.h\"\n\nDEFINE_LOG_CATEGORY(LogFairyGUI);\n\nconst FString G_EMPTY_STRING(\"\");"
  },
  {
    "path": "Source/FairyGUI/Private/FairyGUIModule.cpp",
    "content": "// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.\n\n#include \"FairyGUIModule.h\"\n#if WITH_EDITOR\n#include \"Editor.h\"\n#include \"FairyApplication.h\"\n#endif\n#include \"UI/UIConfig.h\"\n\n#define LOCTEXT_NAMESPACE \"FFairyGUIModule\"\n\nvoid FFairyGUIModule::StartupModule()\n{\n\t// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module\n\n#if WITH_EDITOR\n    EndPieDelegateHandle = FEditorDelegates::EndPIE.AddLambda([](bool boolSent) {\n        UE_LOG(LogFairyGUI, Log, TEXT(\"Application destroy\"));\n\n        UFairyApplication::Destroy();\n    });\n#endif\n}\n\nvoid FFairyGUIModule::ShutdownModule()\n{\n\t// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,\n\t// we call this function before unloading the module.\n\n#if WITH_EDITOR\n    FEditorDelegates::EndPIE.Remove(EndPieDelegateHandle);\n#endif\n}\n\n#undef LOCTEXT_NAMESPACE\n\t\nIMPLEMENT_MODULE(FFairyGUIModule, FairyGUI)"
  },
  {
    "path": "Source/FairyGUI/Private/Tween/EaseManager.cpp",
    "content": "#include \"Tween/EaseManager.h\"\n\nstatic const float _PiOver2 = (PI * 0.5f);\nstatic const float _TwoPi = (PI * 2);\n\nclass Bounce\n{\npublic:\n    static float EaseIn(float Time, float Duration);\n    static float EaseOut(float Time, float Duration);\n    static float EaseInOut(float Time, float Duration);\n};\n\nfloat EaseManager::Evaluate(EEaseType EaseType, float Time, float Duration, float OvershootOrAmplitude, float Period)\n{\n    switch (EaseType)\n    {\n    case EEaseType::Linear:\n        return Time / Duration;\n    case EEaseType::SineIn:\n        return -FMath::Cos(Time / Duration * _PiOver2) + 1;\n    case EEaseType::SineOut:\n        return FMath::Sin(Time / Duration * _PiOver2);\n    case EEaseType::SineInOut:\n        return -0.5f * (FMath::Cos(PI * Time / Duration) - 1);\n    case EEaseType::QuadIn:\n        Time /= Duration;\n        return Time * Time;\n    case EEaseType::QuadOut:\n        Time /= Duration;\n        return -Time * (Time - 2);\n    case EEaseType::QuadInOut:\n        Time /= Duration * 0.5f;\n        if (Time < 1) return 0.5f * Time * Time;\n        --Time;\n        return -0.5f * (Time * (Time - 2) - 1);\n    case EEaseType::CubicIn:\n        Time /= Duration;\n        return Time * Time * Time;\n    case EEaseType::CubicOut:\n        Time = Time / Duration - 1;\n        return Time * Time * Time + 1;\n    case EEaseType::CubicInOut:\n        Time /= Duration * 0.5f;\n        if (Time < 1) return 0.5f * Time * Time * Time;\n        Time -= 2;\n        return 0.5f * (Time * Time * Time + 2);\n    case EEaseType::QuartIn:\n        Time /= Duration;\n        return Time * Time * Time * Time;\n    case EEaseType::QuartOut:\n        Time = Time / Duration - 1;\n        return -(Time * Time * Time * Time - 1);\n    case EEaseType::QuartInOut:\n        Time /= Duration * 0.5f;\n        if (Time < 1) return 0.5f * Time * Time * Time * Time;\n        Time -= 2;\n        return -0.5f * (Time * Time * Time * Time - 2);\n    case EEaseType::QuintIn:\n        Time /= Duration;\n        return Time * Time * Time * Time * Time;\n    case EEaseType::QuintOut:\n        Time = Time / Duration - 1;\n        return (Time * Time * Time * Time * Time + 1);\n    case EEaseType::QuintInOut:\n        Time /= Duration * 0.5f;\n        if (Time < 1) return 0.5f * Time * Time * Time * Time * Time;\n        Time -= 2;\n        return 0.5f * (Time * Time * Time * Time * Time + 2);\n    case EEaseType::ExpoIn:\n        return (Time == 0) ? 0 : FMath::Pow(2, 10 * (Time / Duration - 1));\n    case EEaseType::ExpoOut:\n        if (Time == Duration) return 1;\n        return (-FMath::Pow(2, -10 * Time / Duration) + 1);\n    case EEaseType::ExpoInOut:\n        if (Time == 0) return 0;\n        if (Time == Duration) return 1;\n        if ((Time /= Duration * 0.5f) < 1) return 0.5f * FMath::Pow(2, 10 * (Time - 1));\n        return 0.5f * (-FMath::Pow(2, -10 * --Time) + 2);\n    case EEaseType::CircIn:\n        Time /= Duration;\n        return -(FMath::Sqrt(1 - Time * Time) - 1);\n    case EEaseType::CircOut:\n        Time = Time / Duration - 1;\n        return FMath::Sqrt(1 - Time * Time);\n    case EEaseType::CircInOut:\n        Time /= Duration * 0.5f;\n        if (Time < 1) return -0.5f * (FMath::Sqrt(1 - Time * Time) - 1);\n        Time -= 2;\n        return 0.5f * (FMath::Sqrt(1 - Time * Time) + 1);\n    case EEaseType::ElasticIn:\n        float s0;\n        if (Time == 0) return 0;\n        if ((Time /= Duration) == 1) return 1;\n        if (Period == 0) Period = Duration * 0.3f;\n        if (OvershootOrAmplitude < 1)\n        {\n            OvershootOrAmplitude = 1;\n            s0 = Period / 4;\n        }\n        else s0 = Period / _TwoPi * FMath::Asin(1 / OvershootOrAmplitude);\n        Time -= 1;\n        return -(OvershootOrAmplitude * FMath::Pow(2, 10 * Time) * FMath::Sin((Time * Duration - s0) * _TwoPi / Period));\n    case EEaseType::ElasticOut:\n        float s1;\n        if (Time == 0) return 0;\n        if ((Time /= Duration) == 1) return 1;\n        if (Period == 0) Period = Duration * 0.3f;\n        if (OvershootOrAmplitude < 1)\n        {\n            OvershootOrAmplitude = 1;\n            s1 = Period / 4;\n        }\n        else s1 = Period / _TwoPi * FMath::Asin(1 / OvershootOrAmplitude);\n        return (OvershootOrAmplitude * FMath::Pow(2, -10 * Time) * FMath::Sin((Time * Duration - s1) * _TwoPi / Period) + 1);\n    case EEaseType::ElasticInOut:\n        float s;\n        if (Time == 0) return 0;\n        if ((Time /= Duration * 0.5f) == 2) return 1;\n        if (Period == 0) Period = Duration * (0.3f * 1.5f);\n        if (OvershootOrAmplitude < 1)\n        {\n            OvershootOrAmplitude = 1;\n            s = Period / 4;\n        }\n        else s = Period / _TwoPi * FMath::Asin(1 / OvershootOrAmplitude);\n        if (Time < 1)\n        {\n            Time -= 1;\n            return -0.5f * (OvershootOrAmplitude * FMath::Pow(2, 10 * Time) * FMath::Sin((Time * Duration - s) * _TwoPi / Period));\n        }\n            \n        Time -= 1;\n        return OvershootOrAmplitude * FMath::Pow(2, -10 * Time) * FMath::Sin((Time * Duration - s) * _TwoPi / Period) * 0.5f + 1;\n    case EEaseType::BackIn:\n        Time /= Duration;\n        return Time * Time * ((OvershootOrAmplitude + 1) * Time - OvershootOrAmplitude);\n    case EEaseType::BackOut:\n        Time = Time / Duration - 1;\n        return (Time * Time * ((OvershootOrAmplitude + 1) * Time + OvershootOrAmplitude) + 1);\n    case EEaseType::BackInOut:\n        Time /= Duration * 0.5f;\n        OvershootOrAmplitude *= (1.525f);\n        if (Time < 1) return 0.5f * (Time * Time * ((OvershootOrAmplitude + 1) * Time - OvershootOrAmplitude));\n        Time -= 2;\n        return 0.5f * (Time * Time * ((OvershootOrAmplitude + 1) * Time + OvershootOrAmplitude) + 2);\n    case EEaseType::BounceIn:\n        return Bounce::EaseIn(Time, Duration);\n    case EEaseType::BounceOut:\n        return Bounce::EaseOut(Time, Duration);\n    case EEaseType::BounceInOut:\n        return Bounce::EaseInOut(Time, Duration);\n\n    default:\n        Time /= Duration;\n        return -Time * (Time - 2);\n    }\n}\n\nfloat Bounce::EaseIn(float Time, float Duration)\n{\n    return 1 - EaseOut(Duration - Time, Duration);\n}\n\nfloat Bounce::EaseOut(float Time, float Duration)\n{\n    Time /= Duration;\n    if (Time < (1 / 2.75f))\n    {\n        return (7.5625f * Time * Time);\n    }\n    if (Time < (2 / 2.75f))\n    {\n        Time -= (1.5f / 2.75f);\n        return (7.5625f * Time * Time + 0.75f);\n    }\n    if (Time < (2.5f / 2.75f))\n    {\n        Time -= (2.25f / 2.75f);\n        return (7.5625f * Time * Time + 0.9375f);\n    }\n    Time -= (2.625f / 2.75f);\n    return (7.5625f * Time * Time + 0.984375f);\n}\n\nfloat Bounce::EaseInOut(float Time, float Duration)\n{\n    if (Time < Duration * 0.5f)\n    {\n        return EaseIn(Time * 2, Duration) * 0.5f;\n    }\n    return EaseOut(Time * 2 - Duration, Duration) * 0.5f + 0.5f;\n}\n\n"
  },
  {
    "path": "Source/FairyGUI/Private/Tween/GPath.cpp",
    "content": "#include \"Tween/GPath.h\"\n\nFGPathPoint::FGPathPoint(const FVector& InPos)\n{\n    Pos = InPos;\n    Control1 = FVector::ZeroVector;\n    Control2 = FVector::ZeroVector;\n    CurveType = ECurveType::CRSpline;\n}\n\nFGPathPoint::FGPathPoint(const FVector& InPos, const FVector& InControl)\n{\n    Pos = InPos;\n    Control1 = InControl;\n    Control2 = FVector::ZeroVector;\n    CurveType = ECurveType::Bezier;\n}\n\nFGPathPoint::FGPathPoint(const FVector& InPos, const FVector& InControl1, const FVector& InControl2)\n{\n    Pos = InPos;\n    Control1 = InControl1;\n    Control2 = InControl2;\n    CurveType = ECurveType::CubicBezier;\n}\n\nFGPathPoint::FGPathPoint(const FVector& InPos, ECurveType InCurveType)\n{\n    Pos = InPos;\n    Control1 = FVector::ZeroVector;\n    Control2 = FVector::ZeroVector;\n    CurveType = InCurveType;\n}\n\nFGPath::FGPath()\n    : FullLength(0)\n{\n}\n\nvoid FGPath::Create(const FGPathPoint* InPoints, int32 Count)\n{\n    Segments.Reset();\n    Points.Reset();\n    FullLength = 0;\n\n    if (Count == 0)\n        return;\n\n    TArray<FVector> SplinePoints;\n    const FGPathPoint* prev = InPoints;\n    if (prev->CurveType == FGPathPoint::ECurveType::CRSpline)\n        SplinePoints.Add(prev->Pos);\n\n    for (int32 i = 1; i < Count; i++)\n    {\n        const FGPathPoint* current = InPoints + i;\n\n        if (prev->CurveType != FGPathPoint::ECurveType::CRSpline)\n        {\n            FSegment seg;\n            seg.Type = prev->CurveType;\n            seg.PointStart = Points.Num();\n            if (prev->CurveType == FGPathPoint::ECurveType::Straight)\n            {\n                seg.PointCount = 2;\n                Points.Add(prev->Pos);\n                Points.Add(current->Pos);\n            }\n            else if (prev->CurveType == FGPathPoint::ECurveType::Bezier)\n            {\n                seg.PointCount = 3;\n                Points.Add(prev->Pos);\n                Points.Add(current->Pos);\n                Points.Add(prev->Control1);\n            }\n            else if (prev->CurveType == FGPathPoint::ECurveType::CubicBezier)\n            {\n                seg.PointCount = 4;\n                Points.Add(prev->Pos);\n                Points.Add(current->Pos);\n                Points.Add(prev->Control1);\n                Points.Add(prev->Control2);\n            }\n            seg.Length = FVector::Dist(prev->Pos, current->Pos);\n            FullLength += seg.Length;\n            Segments.Add(MoveTemp(seg));\n        }\n\n        if (current->CurveType != FGPathPoint::ECurveType::CRSpline)\n        {\n            if (SplinePoints.Num() > 0)\n            {\n                SplinePoints.Add(current->Pos);\n                CreateSplineSegment(SplinePoints);\n            }\n        }\n        else\n            SplinePoints.Add(current->Pos);\n\n        prev = current;\n    }\n\n    if (SplinePoints.Num() > 1)\n        CreateSplineSegment(SplinePoints);\n}\n\nvoid FGPath::CreateSplineSegment(TArray<FVector>& SplinePoints)\n{\n    int32 cnt = SplinePoints.Num();\n    SplinePoints.Insert(SplinePoints[0], 0);\n    SplinePoints.Add(SplinePoints[cnt]);\n    SplinePoints.Add(SplinePoints[cnt]);\n    cnt += 3;\n\n    FSegment seg;\n    seg.Type = FGPathPoint::ECurveType::CRSpline;\n    seg.PointStart = Points.Num();\n    seg.PointCount = cnt;\n    for (auto& it : SplinePoints)\n        Points.Add(it);\n\n    seg.Length = 0;\n    for (int32 i = 1; i < cnt; i++)\n        seg.Length += FVector::Dist(SplinePoints[i - 1], SplinePoints[i]);\n    FullLength += seg.Length;\n    Segments.Add(MoveTemp(seg));\n    SplinePoints.Reset();\n}\n\nvoid FGPath::Clear()\n{\n    Segments.Reset();\n    Points.Reset();\n}\n\nFVector FGPath::GetPointAt(float Time)\n{\n    Time = FMath::Clamp<float>(Time, 0, 1);\n    int32 cnt = Segments.Num();\n    if (cnt == 0)\n        return FVector::ZeroVector;\n\n    if (Time == 1)\n    {\n        const FSegment& seg = Segments[cnt - 1];\n\n        if (seg.Type == FGPathPoint::ECurveType::Straight)\n            return FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], Time);\n        else if (seg.Type == FGPathPoint::ECurveType::Bezier || seg.Type == FGPathPoint::ECurveType::CubicBezier)\n            return OnBezierCurve(seg.PointStart, seg.PointCount, Time);\n        else\n            return OnCRSplineCurve(seg.PointStart, seg.PointCount, Time);\n    }\n\n    float len = Time * FullLength;\n    FVector pt;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        const FSegment& seg = Segments[i];\n\n        len -= seg.Length;\n        if (len < 0)\n        {\n            Time = 1 + len / seg.Length;\n\n            if (seg.Type == FGPathPoint::ECurveType::Straight)\n                pt = FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], Time);\n            else if (seg.Type == FGPathPoint::ECurveType::Bezier || seg.Type == FGPathPoint::ECurveType::CubicBezier)\n                pt = OnBezierCurve(seg.PointStart, seg.PointCount, Time);\n            else\n                pt = OnCRSplineCurve(seg.PointStart, seg.PointCount, Time);\n\n            break;\n        }\n    }\n\n    return pt;\n}\n\nfloat FGPath::GetSegmentLength(int32 SegmentIndex)\n{\n    return Segments[SegmentIndex].Length;\n}\n\nvoid FGPath::GetPointsInSegment(int32 SegmentIndex, float t0, float t1,\n    TArray<FVector>& OutPoints, TArray<float>* OutTimeArray, float PointDensity)\n{\n    if (OutTimeArray != nullptr)\n        OutTimeArray->Add(t0);\n    const FSegment& seg = Segments[SegmentIndex];\n    if (seg.Type == FGPathPoint::ECurveType::Straight)\n    {\n        OutPoints.Add(FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], t0));\n        OutPoints.Add(FMath::Lerp(Points[seg.PointStart], Points[seg.PointStart + 1], t1));\n    }\n    else if (seg.Type == FGPathPoint::ECurveType::Bezier || seg.Type == FGPathPoint::ECurveType::CubicBezier)\n    {\n        OutPoints.Add(OnBezierCurve(seg.PointStart, seg.PointCount, t0));\n        int32 SmoothAmount = FMath::Min(FMath::FloorToInt(seg.Length * PointDensity), 50);\n        for (int32 j = 0; j <= SmoothAmount; j++)\n        {\n            float t = (float)j / SmoothAmount;\n            if (t > t0 && t < t1)\n            {\n                OutPoints.Add(OnBezierCurve(seg.PointStart, seg.PointCount, t));\n                if (OutTimeArray != nullptr)\n                    OutTimeArray->Add(t);\n            }\n        }\n        OutPoints.Add(OnBezierCurve(seg.PointStart, seg.PointCount, t1));\n    }\n    else\n    {\n        OutPoints.Add(OnCRSplineCurve(seg.PointStart, seg.PointCount, t0));\n        int32 SmoothAmount = FMath::Min(FMath::FloorToInt(seg.Length * PointDensity), 50);\n        for (int32 j = 0; j <= SmoothAmount; j++)\n        {\n            float t = (float)j / SmoothAmount;\n            if (t > t0 && t < t1)\n            {\n                OutPoints.Add(OnCRSplineCurve(seg.PointStart, seg.PointCount, t));\n                if (OutTimeArray != nullptr)\n                    OutTimeArray->Add(t);\n            }\n        }\n        OutPoints.Add(OnCRSplineCurve(seg.PointStart, seg.PointCount, t1));\n    }\n\n    if (OutTimeArray != nullptr)\n        OutTimeArray->Add(t1);\n}\n\nvoid FGPath::GetAllPoints(TArray<FVector>& OutPoints, float PointDensity)\n{\n    int32 cnt = Segments.Num();\n    for (int32 i = 0; i < cnt; i++)\n        GetPointsInSegment(i, 0, 1, OutPoints, nullptr, PointDensity);\n}\n\nstatic float repeat(float t, float length)\n{\n    return t - FMath::FloorToFloat(t / length) * length;\n}\n\nFVector FGPath::OnCRSplineCurve(int32 PointStart, int32 PointCount, float Time)\n{\n    int32 adjustedIndex = FMath::FloorToFloat(Time * (PointCount - 4)) + PointStart; //Since the equation works with 4 points, we adjust the starting point depending on t to return a point on the specific segment\n\n    FVector result;\n\n    FVector p0 = Points[adjustedIndex];\n    FVector p1 = Points[adjustedIndex + 1];\n    FVector p2 = Points[adjustedIndex + 2];\n    FVector p3 = Points[adjustedIndex + 3];\n\n    float adjustedT = (Time == 1.f) ? 1.f : repeat(Time * (PointCount - 4), 1.f); // Then we adjust t to be that value on that new piece of segment... for t == 1f don't use repeat (that would return 0f);\n\n    float t0 = ((-adjustedT + 2.f) * adjustedT - 1.f) * adjustedT * 0.5f;\n    float t1 = (((3.f * adjustedT - 5.f) * adjustedT) * adjustedT + 2.f) * 0.5f;\n    float t2 = ((-3.f * adjustedT + 4.f) * adjustedT + 1.f) * adjustedT * 0.5f;\n    float t3 = ((adjustedT - 1.f) * adjustedT * adjustedT) * 0.5f;\n\n    result.X = p0.X * t0 + p1.X * t1 + p2.X * t2 + p3.X * t3;\n    result.Y = p0.Y * t0 + p1.Y * t1 + p2.Y * t2 + p3.Y * t3;\n    result.Z = p0.Z * t0 + p1.Z * t1 + p2.Z * t2 + p3.Z * t3;\n\n    return result;\n}\n\nFVector FGPath::OnBezierCurve(int32 PointStart, int32 PointCount, float Time)\n{\n    float t2 = 1.0f - Time;\n    FVector p0 = Points[PointStart];\n    FVector p1 = Points[PointStart + 1];\n    FVector cp0 = Points[PointStart + 2];\n\n    if (PointCount == 4)\n    {\n        FVector cp1 = Points[PointStart + 3];\n        return t2 * t2 * t2 * p0 + 3.f * t2 * t2 * Time * cp0 + 3.f * t2 * Time * Time * cp1 + Time * Time * Time * p1;\n    }\n    else\n        return t2 * t2 * p0 + 2.f * t2 * Time * cp0 + Time * Time * p1;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Tween/GTween.cpp",
    "content": "#include \"Tween/GTween.h\"\n#include \"Tween/TweenManager.h\"\n#include \"UI/GProgressBar.h\"\n\nFGTweener* FGTween::To(float StartValue, float EndValue, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration);\n}\n\nFGTweener* FGTween::To(const FVector2D& StartValue, const FVector2D & EndValue, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration);\n}\n\nFGTweener* FGTween::To(const FVector& StartValue, const FVector & EndValue, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration);\n}\n\nFGTweener* FGTween::To(const FVector4& StartValue, const FVector4 & EndValue, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration);\n}\n\nFGTweener* FGTween::To(const FColor& StartValue, const FColor & EndValue, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration);\n}\n\nFGTweener* FGTween::ToDouble(double StartValue, double EndValue, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->To(StartValue, EndValue, Duration);\n}\n\nFGTweener* FGTween::DelayedCall(float Delay)\n{\n    return FTweenManager::Singleton.CreateTween()->SetDelay(Delay);\n}\n\nFGTweener* FGTween::Shake(const FVector2D& StartValue, float Amplitude, float Duration)\n{\n    return FTweenManager::Singleton.CreateTween()->Shake(StartValue, Amplitude, Duration);\n}\n\nbool FGTween::IsTweening(const FTweenerHandle& Handle)\n{\n    return FTweenManager::Singleton.IsTweening(Handle);\n}\n\nbool FGTween::IsTweening(UObject* Target)\n{\n    return FTweenManager::Singleton.IsTweening(Target);\n}\n\nvoid FGTween::Kill(FTweenerHandle& Handle, bool bSetComplete)\n{\n    FTweenManager::Singleton.KillTween(Handle, bSetComplete);\n}\n\nvoid FGTween::Kill(UObject* Target, bool bSetComplete)\n{\n    FTweenManager::Singleton.KillTweens(Target, bSetComplete);\n}\n\nFGTweener* FGTween::GetTween(const FTweenerHandle& Handle)\n{\n    return FTweenManager::Singleton.GetTween(Handle);\n}\n\nFGTweener* FGTween::GetTween(UObject * Target)\n{\n    return FTweenManager::Singleton.GetTween(Target);\n}\n\nvoid FGTweenAction::MoveX(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetX(Tweener->Value.X);\n}\n\nvoid FGTweenAction::MoveY(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetY(Tweener->Value.X);\n}\n\nvoid FGTweenAction::Move(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetPosition(Tweener->Value.GetVec2());\n}\n\nvoid FGTweenAction::SetWidth(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetWidth(Tweener->Value.X);\n}\n\nvoid FGTweenAction::SetHeight(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetHeight(Tweener->Value.X);\n}\n\nvoid FGTweenAction::SetSize(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetSize(Tweener->Value.GetVec2());\n}\n\nvoid FGTweenAction::ScaleX(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetScaleX(Tweener->Value.X);\n}\n\nvoid FGTweenAction::ScaleY(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetScaleY(Tweener->Value.X);\n}\n\nvoid FGTweenAction::ScaleXY(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetScale(Tweener->Value.GetVec2());\n}\n\nvoid FGTweenAction::Rotate(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetRotation(Tweener->Value.X);\n}\n\nvoid FGTweenAction::SetAlpha(FGTweener* Tweener)\n{\n    UGObject * target = Cast<UGObject>(Tweener->GetTarget());\n    target->SetAlpha(Tweener->Value.X);\n}\n\nvoid FGTweenAction::SetProgress(FGTweener* Tweener)\n{\n    UGProgressBar * target = Cast<UGProgressBar>(Tweener->GetTarget());\n    target->Update(Tweener->Value.X);\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Tween/GTweener.cpp",
    "content": "#include \"Tween/GTweener.h\"\n#include \"Tween/EaseManager.h\"\n#include \"Tween/GPath.h\"\n#include \"UI/GObject.h\"\n\nFGTweener::FGTweener()\n{\n}\n\nFGTweener::~FGTweener()\n{\n}\n\nFGTweener* FGTweener::SetDelay(float InValue)\n{\n    Delay = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetDuration(float InValue)\n{\n    Duration = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetBreakpoint(float InValue)\n{\n    Breakpoint = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetEase(EEaseType InValue)\n{\n    EaseType = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetEasePeriod(float InValue)\n{\n    EasePeriod = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetEaseOvershootOrAmplitude(float InValue)\n{\n    EaseOvershootOrAmplitude = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetRepeat(int32 InRepeat, bool bInYoyo)\n{\n    Repeat = InRepeat;\n    bYoyo = bInYoyo;\n    return this;\n}\n\nFGTweener* FGTweener::SetTimeScale(float InValue)\n{\n    TimeScale = InValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetSnapping(bool bInValue)\n{\n    bSnapping = bInValue;\n    return this;\n}\n\nFGTweener* FGTweener::SetTarget(UObject* InTarget)\n{\n    Target = InTarget;\n    return this;\n}\n\nFGTweener* FGTweener::SetUserData(const FNVariant& InData)\n{\n    UserData = InData;\n    return this;\n}\n\nFGTweener* FGTweener::SetPath(TSharedPtr<FGPath> InPath)\n{\n    Path = InPath;\n    return this;\n}\n\nFGTweener* FGTweener::OnUpdate(FTweenDelegate Callback)\n{\n    OnUpdateCallback = Callback;\n    return this;\n}\n\nFGTweener* FGTweener::OnStart(FTweenDelegate Callback)\n{\n    OnStartCallback = Callback;\n    return this;\n}\n\nFGTweener* FGTweener::OnComplete(FTweenDelegate Callback)\n{\n    OnCompleteCallback = Callback;\n    return this;\n}\n\nFGTweener* FGTweener::OnUpdate(FSimpleDelegate Callback)\n{\n    OnUpdateCallback.BindLambda([Callback](FGTweener*) {\n        Callback.ExecuteIfBound();\n    });\n    return this;\n}\n\nFGTweener* FGTweener::OnStart(FSimpleDelegate Callback)\n{\n    OnStartCallback.BindLambda([Callback](FGTweener*) {\n        Callback.ExecuteIfBound();\n    });\n    return this;\n}\n\nFGTweener* FGTweener::OnComplete(FSimpleDelegate Callback)\n{\n    OnCompleteCallback.BindLambda([Callback](FGTweener*) {\n        Callback.ExecuteIfBound();\n    });\n    return this;\n}\n\nFGTweener* FGTweener::SetPaused(bool bInPaused)\n{\n    bPaused = bInPaused;\n    return this;\n}\n\nvoid FGTweener::Seek(float Time)\n{\n    if (bKilled)\n        return;\n\n    ElapsedTime = Time;\n    if (ElapsedTime < Delay)\n    {\n        if (bStarted)\n            ElapsedTime = Delay;\n        else\n            return;\n    }\n\n    Update();\n}\n\nvoid FGTweener::Kill(bool bSetComplete)\n{\n    if (bKilled)\n        return;\n\n    if (bSetComplete)\n    {\n        if (Ended == 0)\n        {\n            if (Breakpoint >= 0)\n                ElapsedTime = Delay + Breakpoint;\n            else if (Repeat >= 0)\n                ElapsedTime = Delay + Duration * (Repeat + 1);\n            else\n                ElapsedTime = Delay + Duration * 2;\n            Update();\n        }\n\n        OnCompleteCallback.ExecuteIfBound(this);\n    }\n\n    bKilled = true;\n}\n\nFGTweener* FGTweener::To(float InStart, float InEnd, float InDuration)\n{\n    ValueSize = 1;\n    StartValue.X = InStart;\n    EndValue.X = InEnd;\n    Value.X = InStart;\n    Duration = InDuration;\n    return this;\n}\n\nFGTweener* FGTweener::To(const FVector2D& InStart, const FVector2D& InEnd, float InDuration)\n{\n    ValueSize = 2;\n    StartValue.SetVec2(InStart);\n    EndValue.SetVec2(InEnd);\n    Value.SetVec2(InStart);\n    Duration = InDuration;\n    return this;\n}\n\nFGTweener* FGTweener::To(const FVector& InStart, const FVector& InEnd, float InDuration)\n{\n    ValueSize = 3;\n    StartValue.SetVec3(InStart);\n    EndValue.SetVec3(InEnd);\n    Value.SetVec3(InStart);\n    Duration = InDuration;\n    return this;\n}\n\nFGTweener* FGTweener::To(const FVector4& InStart, const FVector4& InEnd, float InDuration)\n{\n    ValueSize = 4;\n    StartValue.SetVec4(InStart);\n    EndValue.SetVec4(InEnd);\n    Value.SetVec4(InStart);\n    Duration = InDuration;\n    return this;\n}\n\nFGTweener* FGTweener::To(const FColor& InStart, const FColor& InEnd, float InDuration)\n{\n    ValueSize = 4;\n    StartValue.SetColor(InStart);\n    EndValue.SetColor(InEnd);\n    Value.SetColor(InStart);\n    Duration = InDuration;\n    return this;\n}\n\nFGTweener* FGTweener::To(double InStart, double InEnd, float InDuration)\n{\n    ValueSize = 5;\n    StartValue.D = InStart;\n    EndValue.D = InEnd;\n    Value.D = InStart;\n    Duration = InDuration;\n    return this;\n}\n\nFGTweener* FGTweener::Shake(const FVector2D& InStart, float InAmplitude, float InDuration)\n{\n    ValueSize = 6;\n    StartValue.SetVec2(InStart);\n    StartValue.W = InAmplitude;\n    Duration = InDuration;\n    EaseType = EEaseType::Linear;\n    return this;\n}\n\nvoid FGTweener::Init()\n{\n    Delay = 0;\n    Duration = 0;\n    Breakpoint = -1;\n    EaseType = EEaseType::QuadOut;\n    TimeScale = 1;\n    EasePeriod = 0;\n    EaseOvershootOrAmplitude = 1.70158f;\n    bSnapping = false;\n    Repeat = 0;\n    bYoyo = false;\n    ValueSize = 0;\n    bStarted = false;\n    bPaused = false;\n    bKilled = false;\n    ElapsedTime = 0;\n    NormalizedTime = 0;\n    Ended = 0;\n    StartValue.Reset();\n    EndValue.Reset();\n    Value.Reset();\n    DeltaValue.Reset();\n}\n\nvoid FGTweener::Reset()\n{\n    Target.Reset();\n    UserData.Reset();\n    Path.Reset();\n    OnStartCallback.Unbind();\n    OnUpdateCallback.Unbind();\n    OnCompleteCallback.Unbind();\n}\n\nvoid FGTweener::Update(float DeltaTime)\n{\n    if (Ended != 0) //Maybe completed by seek\n    {\n        OnCompleteCallback.ExecuteIfBound(this);\n        bKilled = true;\n        return;\n    }\n\n    if (TimeScale != 1)\n        DeltaTime *= TimeScale;\n    if (DeltaTime == 0)\n        return;\n\n    ElapsedTime += DeltaTime;\n    Update();\n\n    if (Ended != 0)\n    {\n        if (!bKilled)\n        {\n            OnCompleteCallback.ExecuteIfBound(this);\n            bKilled = true;\n        }\n    }\n}\n\nvoid FGTweener::Update()\n{\n    Ended = 0;\n\n    if (ValueSize == 0) //DelayedCall\n    {\n        if (ElapsedTime >= Delay + Duration)\n            Ended = 1;\n\n        return;\n    }\n\n    if (!bStarted)\n    {\n        if (ElapsedTime < Delay)\n            return;\n\n        bStarted = true;\n        OnStartCallback.ExecuteIfBound(this);\n        if (bKilled)\n            return;\n    }\n\n    bool reversed = false;\n    float tt = ElapsedTime - Delay;\n    if (Breakpoint >= 0 && tt >= Breakpoint)\n    {\n        tt = Breakpoint;\n        Ended = 2;\n    }\n\n    if (Repeat != 0)\n    {\n        int32 round = FMath::FloorToInt(tt / Duration);\n        tt -= Duration * round;\n        if (bYoyo)\n            reversed = round % 2 == 1;\n\n        if (Repeat > 0 && Repeat - round < 0)\n        {\n            if (bYoyo)\n                reversed = Repeat % 2 == 1;\n            tt = Duration;\n            Ended = 1;\n        }\n    }\n    else if (tt >= Duration)\n    {\n        tt = Duration;\n        Ended = 1;\n    }\n\n    NormalizedTime = EaseManager::Evaluate(EaseType, reversed ? (Duration - tt) : tt, Duration,\n        EaseOvershootOrAmplitude, EasePeriod);\n\n    Value.Reset();\n    DeltaValue.Reset();\n\n    if (ValueSize == 5)\n    {\n        double d = StartValue.D + (EndValue.D - StartValue.D) * NormalizedTime;\n        if (bSnapping)\n            d = round(d);\n        DeltaValue.D = d - Value.D;\n        Value.D = d;\n        Value.X = (float)d;\n    }\n    else if (ValueSize == 6)\n    {\n        if (Ended == 0)\n        {\n            float r = StartValue.W * (1 - NormalizedTime);\n            float rx = (FMath::RandRange(0, 1) * 2 - 1) * r;\n            float ry = (FMath::RandRange(0, 1) * 2 - 1) * r;\n            rx = rx > 0 ? FMath::CeilToFloat(rx) : FMath::FloorToFloat(rx);\n            ry = ry > 0 ? FMath::CeilToFloat(ry) : FMath::FloorToFloat(ry);\n\n            DeltaValue.X = rx;\n            DeltaValue.Y = ry;\n            Value.X = StartValue.X + rx;\n            Value.Y = StartValue.Y + ry;\n        }\n        else\n            Value.SetVec3(StartValue.GetVec3());\n    }\n    else if (Path.IsValid())\n    {\n        FVector vec3 = Path->GetPointAt(NormalizedTime);\n        if (bSnapping)\n        {\n            vec3.X = FMath::RoundToFloat(vec3.X);\n            vec3.Y = FMath::RoundToFloat(vec3.Y);\n            vec3.Z = FMath::RoundToFloat(vec3.Z);\n        }\n        DeltaValue.SetVec3(vec3 - Value.GetVec3());\n        Value.SetVec3(vec3);\n    }\n    else\n    {\n        for (int32 i = 0; i < ValueSize; i++)\n        {\n            float n1 = StartValue[i];\n            float n2 = EndValue[i];\n            float f = n1 + (n2 - n1) * NormalizedTime;\n            if (bSnapping)\n                f = FMath::RoundToFloat(f);\n            DeltaValue[i] = f - Value[i];\n            Value[i] = f;\n        }\n        Value.D = Value.X;\n    }\n\n    OnUpdateCallback.ExecuteIfBound(this);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Tween/TweenManager.cpp",
    "content": "#include \"Tween/TweenManager.h\"\n#include \"Tween/GTweener.h\"\n\nFTweenManager FTweenManager::Singleton;\n\nFTweenManager::FTweenManager()\n{\n    TotalActiveTweens = 0;\n    ArrayLength = 30;\n    ActiveTweens = new FGTweener*[ArrayLength];\n}\n\nFTweenManager::~FTweenManager()\n{\n    Reset();\n    delete []ActiveTweens;\n}\n\nvoid FTweenManager::Reset()\n{\n    for (auto it : TweenerPool)\n        delete it;\n    TweenerPool.Reset();\n\n    int32 cnt = TotalActiveTweens;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FGTweener* tweener = ActiveTweens[i];\n        if (tweener != nullptr)\n            delete tweener;\n    }\n    TotalActiveTweens = 0;\n}\n\nFGTweener* FTweenManager::CreateTween()\n{\n    FGTweener* tweener;\n    int32 cnt = TweenerPool.Num();\n    if (cnt > 0)\n    {\n        tweener = TweenerPool.Pop();\n        tweener->Handle.IncreaseSerialNumber();\n    }\n    else\n    {\n        TweenerInstanceCount++;\n        if (!ensureMsgf(TweenerInstanceCount != FTweenerHandle::MaxIndex, TEXT(\"Tweener index number has wrapped around!\")))\n        {\n            TweenerInstanceCount = 0;\n        }\n        tweener = new FGTweener();\n        tweener->Handle.SetIndex(TweenerInstanceCount);\n    }\n    tweener->Init();\n    ActiveTweens[TotalActiveTweens++] = tweener;\n\n    if (TotalActiveTweens == ArrayLength)\n    {\n        int32 newLen = ArrayLength + FMath::CeilToInt(ArrayLength * 0.5f);\n        FGTweener** newArray = new FGTweener*[newLen];\n        FMemory::Memcpy(newArray, ActiveTweens, ArrayLength * sizeof(FGTweener*));\n        delete []ActiveTweens;\n        ActiveTweens = newArray;\n        ArrayLength = newLen;\n    }\n\n    return tweener;\n}\n\nbool FTweenManager::KillTween(FTweenerHandle & Handle, bool bCompleted)\n{\n    int32 cnt = TotalActiveTweens;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FGTweener* tweener = ActiveTweens[i];\n        if (tweener != nullptr && tweener->Handle == Handle && !tweener->bKilled)\n        {\n            Handle.Invalidate();\n            tweener->Kill(bCompleted);\n            return true;\n        }\n    }\n\n    Handle.Invalidate();\n    return false;\n}\n\nbool FTweenManager::KillTweens(UObject* Target, bool bCompleted)\n{\n    if (Target == nullptr)\n        return false;\n\n    bool flag = false;\n    int32 cnt = TotalActiveTweens;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FGTweener* tweener = ActiveTweens[i];\n        if (tweener != nullptr && tweener->Target.Get() == Target && !tweener->bKilled)\n        {\n            tweener->Kill(bCompleted);\n            flag = true;\n        }\n    }\n\n    return flag;\n}\n\nFGTweener* FTweenManager::GetTween(FTweenerHandle const& Handle)\n{\n    if (!Handle.IsValid())\n        return nullptr;\n\n    int32 cnt = TotalActiveTweens;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FGTweener* tweener = ActiveTweens[i];\n        if (tweener != nullptr && tweener->Handle == Handle && !tweener->bKilled)\n        {\n            return tweener;\n        }\n    }\n\n    return nullptr;\n}\n\nFGTweener* FTweenManager::GetTween(UObject* Target)\n{\n    if (Target == nullptr)\n        return nullptr;\n\n    int32 cnt = TotalActiveTweens;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FGTweener* tweener = ActiveTweens[i];\n        if (tweener != nullptr && tweener->Target.Get() == Target && !tweener->bKilled)\n        {\n            return tweener;\n        }\n    }\n\n    return nullptr;\n}\n\nvoid FTweenManager::Tick(float DeltaTime)\n{\n    int32 cnt = TotalActiveTweens;\n    int32 freePosStart = -1;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FGTweener* tweener = ActiveTweens[i];\n        if (tweener == nullptr)\n        {\n            if (freePosStart == -1)\n                freePosStart = i;\n        }\n        else if (tweener->bKilled)\n        {\n            tweener->Reset();\n            TweenerPool.Add(tweener);\n            ActiveTweens[i] = nullptr;\n\n            if (freePosStart == -1)\n                freePosStart = i;\n        }\n        else\n        {\n            if (tweener->Target.IsStale())\n                tweener->bKilled = true;\n            else if (!tweener->bPaused)\n                tweener->Update(DeltaTime);\n\n            if (freePosStart != -1)\n            {\n                ActiveTweens[freePosStart] = tweener;\n                ActiveTweens[i] = nullptr;\n                freePosStart++;\n            }\n        }\n    }\n\n    if (freePosStart >= 0)\n    {\n        if (TotalActiveTweens != cnt) //new tweens added\n        {\n            int32 j = cnt;\n            cnt = TotalActiveTweens - cnt;\n            for (int32 i = 0; i < cnt; i++)\n                ActiveTweens[freePosStart++] = ActiveTweens[j++];\n        }\n        TotalActiveTweens = freePosStart;\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Tween/TweenValue.cpp",
    "content": "#include \"Tween/TweenValue.h\"\n\nFTweenValue::FTweenValue() :X(0), Y(0), Z(0), W(0), D(0)\n{\n}\n\nFVector2D FTweenValue::GetVec2() const\n{\n    return FVector2D(X, Y);\n}\n\nvoid FTweenValue::SetVec2(const FVector2D & Value)\n{\n    X = Value.X;\n    Y = Value.Y;\n}\n\nFVector FTweenValue::GetVec3() const\n{\n    return FVector(X, Y, Z);\n}\n\nvoid FTweenValue::SetVec3(const FVector & Value)\n{\n    X = Value.X;\n    Y = Value.Y;\n    Z = Value.Z;\n}\n\nFVector4 FTweenValue::GetVec4() const\n{\n    return FVector4(X, Y, Z, W);\n}\n\nvoid FTweenValue::SetVec4(const FVector4 & Value)\n{\n    X = Value.X;\n    Y = Value.Y;\n    Z = Value.Z;\n    W = Value.W;\n}\n\nFColor FTweenValue::GetColor() const\n{\n    return FColor(X * 255, Y * 255, Z * 255, W * 255);\n}\n\nvoid FTweenValue::SetColor(const FColor & Value)\n{\n    X = Value.R / 255.f;\n    Y = Value.G / 255.f;\n    Z = Value.B / 255.f;\n    W = Value.A / 255.f;\n}\n\nfloat FTweenValue::operator[](int32 Index) const\n{\n    verifyf(Index < 4, TEXT(\"Index out of bounds: %d\"), Index);\n\n    switch (Index)\n    {\n    case 0:\n        return X;\n    case 1:\n        return Y;\n    case 2:\n        return Z;\n    case 3:\n        return W;\n    default:\n        return X;\n    }\n}\n\nfloat& FTweenValue::operator[](int32 Index)\n{\n    verifyf(Index < 4, TEXT(\"Index out of bounds: %d\"), Index);\n\n    switch (Index)\n    {\n    case 0:\n        return X;\n    case 1:\n        return Y;\n    case 2:\n        return Z;\n    case 3:\n        return W;\n    default:\n        return X;\n    }\n}\n\nvoid FTweenValue::Reset()\n{\n    X = Y = Z = W = 0;\n    D = 0;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/ControllerAction/ChangePageAction.cpp",
    "content": "#include \"UI/ControllerAction/ChangePageAction.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"UI/GComponent.h\"\n\nvoid FChangePageAction::Setup(FByteBuffer* Buffer)\n{\n    FControllerAction::Setup(Buffer);\n\n    ObjectID = Buffer->ReadS();\n    ControllerName = Buffer->ReadS();\n    TargetPage = Buffer->ReadS();\n}\n\nvoid FChangePageAction::Enter(UGController* Controller)\n{\n    if (ControllerName.IsEmpty())\n        return;\n\n    UGComponent* gcom;\n    if (!ObjectID.IsEmpty())\n        gcom = Cast<UGComponent>(Cast<UGComponent>(Controller->GetOuter())->GetChildByID(ObjectID));\n    else\n        gcom = Cast<UGComponent>(Controller->GetOuter());\n    if (gcom != nullptr)\n    {\n        UGController* cc = gcom->GetController(ControllerName);\n        if (cc != nullptr && cc != Controller && !cc->bChanging)\n        {\n            if (TargetPage.Compare(\"~1\") == 0)\n            {\n                if (Controller->GetSelectedIndex() < cc->GetPageCount())\n                    cc->SetSelectedIndex(Controller->GetSelectedIndex());\n            }\n            else if (TargetPage.Compare(\"~2\") == 0)\n                cc->SetSelectedPage(Controller->GetSelectedPage());\n            else\n                cc->SetSelectedPageID(TargetPage);\n        }\n    }\n}\n\nvoid FChangePageAction::Leave(UGController* Controller)\n{\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/ControllerAction/ControllerAction.cpp",
    "content": "#include \"UI/ControllerAction/ControllerAction.h\"\n#include \"UI/ControllerAction/ChangePageAction.h\"\n#include \"UI/ControllerAction/PlayTransitionAction.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFControllerAction * FControllerAction::CreateAction(int32 ActionType)\n{\n    switch (ActionType)\n    {\n    case 0:\n        return new FPlayTransitionAction();\n\n    case 1:\n        return new FChangePageAction();\n    }\n    return nullptr;\n}\n\nFControllerAction::FControllerAction()\n{\n}\n\nFControllerAction::~FControllerAction()\n{\n}\n\nvoid FControllerAction::Run(UGController* Controller, const FString& PreviousPage, const FString& CurrentPage)\n{\n    if ((FromPage.Num() == 0 || FromPage.Contains(PreviousPage))\n        && (ToPage.Num() == 0 || ToPage.Contains(CurrentPage)))\n        Enter(Controller);\n    else\n        Leave(Controller);\n}\n\nvoid FControllerAction::Setup(FByteBuffer * Buffer)\n{\n    int32 cnt;\n\n    cnt = Buffer->ReadShort();\n    FromPage.SetNum(cnt);\n    for (int32 i = 0; i < cnt; i++)\n        FromPage[i] = Buffer->ReadS();\n\n    cnt = Buffer->ReadShort();\n    ToPage.SetNum(cnt);\n    for (int32 i = 0; i < cnt; i++)\n        ToPage[i] = Buffer->ReadS();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/ControllerAction/PlayTransitionAction.cpp",
    "content": "#include \"UI/ControllerAction/PlayTransitionAction.h\"\n#include \"UI/GController.h\"\n#include \"UI/Transition.h\"\n#include \"UI/GComponent.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFPlayTransitionAction::FPlayTransitionAction() :\n    PlayTimes(1),\n    Delay(0),\n    bStopOnExit(false),\n    CurrentTransition(nullptr)\n{\n}\n\nvoid FPlayTransitionAction::Setup(FByteBuffer* Buffer)\n{\n    FControllerAction::Setup(Buffer);\n\n    TransitionName = Buffer->ReadS();\n    PlayTimes = Buffer->ReadInt();\n    Delay = Buffer->ReadFloat();\n    bStopOnExit = Buffer->ReadBool();\n}\n\nvoid FPlayTransitionAction::Enter(UGController* Controller)\n{\n    UTransition* trans = Cast<UGComponent>(Controller->GetOuter())->GetTransition(TransitionName);\n    if (trans != nullptr)\n    {\n        if (CurrentTransition != nullptr && CurrentTransition->IsPlaying())\n            trans->ChangePlayTimes(PlayTimes);\n        else\n            trans->Play(PlayTimes, Delay);\n        CurrentTransition = trans;\n    }\n}\n\nvoid FPlayTransitionAction::Leave(UGController* Controller)\n{\n    if (bStopOnExit && CurrentTransition != nullptr)\n    {\n        CurrentTransition->Stop();\n        CurrentTransition = nullptr;\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/DragDropManager.cpp",
    "content": "#include \"UI/DragDropManager.h\"\n#include \"UI/UIObjectFactory.h\"\n#include \"UI/GRoot.h\"\n#include \"FairyApplication.h\"\n\nUDragDropManager::UDragDropManager()\n{\n}\n\nUDragDropManager::~UDragDropManager()\n{\n}\n\nvoid UDragDropManager::CreateAgent()\n{\n    Agent = (UGLoader*)FUIObjectFactory::NewObject(EObjectType::Loader, this);\n    Agent->Name = TEXT(\"DragDropAgent\");\n    Agent->SetTouchable(false);\n    Agent->SetDraggable(true);\n    Agent->SetSize(FVector2D(100, 100));\n    Agent->SetPivot(FVector2D(.5f, .5f), true);\n    Agent->SetAlign(EAlignType::Center);\n    Agent->SetVerticalAlign(EVerticalAlignType::Middle);\n    Agent->SetSortingOrder(INT_MAX);\n    Agent->On(FUIEvents::DragEnd).AddUObject(this, &UDragDropManager::OnDragEnd);\n}\n\nvoid UDragDropManager::StartDrag(const FString& InIcon, const FNVariant& InUserData, int32 InUserIndex, int32 InPointerIndex)\n{\n    if (Agent->GetParent() != nullptr)\n        return;\n\n    UserData = InUserData;\n    Agent->SetURL(InIcon);\n    Agent->SetParentToRoot();\n    FVector2D pt = Agent->GetUIRoot()->GlobalToLocal(Agent->GetApp()->GetTouchPosition(InUserIndex, InPointerIndex));\n    Agent->SetPosition(pt);\n    Agent->GetApp()->CallAfterSlateTick(FSimpleDelegate::CreateUObject(this, &UDragDropManager::DelayStartDrag, InUserIndex, InPointerIndex));\n}\n\nvoid UDragDropManager::DelayStartDrag(int32 InUserIndex, int32 InPointerIndex)\n{\n    if (Agent->GetParent() != nullptr)\n        Agent->StartDrag(InUserIndex, InPointerIndex);\n}\n\nvoid UDragDropManager::Cancel()\n{\n    if (Agent->GetParent() != nullptr)\n    {\n        Agent->StopDrag();\n        Agent->RemoveFromParent();\n        UserData.Reset();\n    }\n}\n\nvoid UDragDropManager::OnDragEnd(UEventContext* Context)\n{\n    if (Agent->GetParent() == nullptr) //canceled\n        return;\n\n    Agent->RemoveFromParent();\n\n    UGObject* obj = Agent->GetApp()->GetObjectUnderPoint(Context->GetPointerPosition());\n    while (obj != nullptr)\n    {\n        if (obj->IsA<UGComponent>())\n        {\n            if (obj->HasEventListener(FUIEvents::Drop))\n            {\n                obj->DispatchEvent(FUIEvents::Drop, UserData);\n                return;\n            }\n        }\n\n        obj = obj->GetParent();\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GButton.cpp",
    "content": "#include \"UI/GButton.h\"\n#include \"UI/GTextField.h\"\n#include \"UI/GLabel.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"FairyApplication.h\"\n\nconst FString UGButton::UP = \"up\";\nconst FString UGButton::DOWN = \"down\";\nconst FString UGButton::OVER = \"over\";\nconst FString UGButton::SELECTED_OVER = \"selectedOver\";\nconst FString UGButton::DISABLED = \"disabled\";\nconst FString UGButton::SELECTED_DISABLED = \"selectedDisabled\";\n\nUGButton::UGButton() :\n    bChangeStateOnClick(true),\n    DownEffectValue(0.8f)\n{\n    Sound = FUIConfig::Config.ButtonSound;\n    SoundVolumeScale = FUIConfig::Config.ButtonSoundVolumeScale;\n}\n\nUGButton::~UGButton()\n{\n}\n\nvoid UGButton::SetText(const FString& InText)\n{\n    Title = InText;\n    if (TitleObject != nullptr)\n        TitleObject->SetText(InText);\n    UpdateGear(6);\n}\n\nconst FString& UGButton::GetIcon() const\n{\n    if (IconObject != nullptr)\n        return IconObject->GetIcon();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGButton::SetIcon(const FString & InIcon)\n{\n    if (IconObject != nullptr)\n        IconObject->SetIcon(InIcon);\n    UpdateGear(7);\n}\n\nvoid UGButton::SetSelectedTitle(const FString& InTitle)\n{\n    SelectedTitle = InTitle;\n    if (TitleObject != nullptr)\n        TitleObject->SetText((bSelected && SelectedTitle.Len() > 0) ? SelectedTitle : Title);\n}\n\nvoid UGButton::SetSelectedIcon(const FString& InIcon)\n{\n    SelectedIcon = InIcon;\n    if (IconObject != nullptr)\n        IconObject->SetIcon((bSelected && SelectedIcon.Len() > 0) ? SelectedIcon : Icon);\n}\n\nFColor UGButton::GetTitleColor() const\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n        return TextField->GetTextFormat().Color;\n    else\n        return FColor::Black;\n}\n\nvoid UGButton::SetTitleColor(const FColor & InColor)\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n    {\n        TextField->GetTextFormat().Color = InColor;\n        TextField->ApplyFormat();\n    }\n}\n\nint32 UGButton::GetTitleFontSize() const\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n        return TextField->GetTextFormat().Size;\n    else\n        return 0;\n}\n\nvoid UGButton::SetTitleFontSize(int32 InFontSize)\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n    {\n        TextField->GetTextFormat().Size = InFontSize;\n        TextField->ApplyFormat();\n    }\n}\n\nvoid UGButton::SetSelected(bool bInSelected)\n{\n    if (Mode == EButtonMode::Common)\n        return;\n\n    if (bSelected != bInSelected)\n    {\n        bSelected = bInSelected;\n        SetCurrentState();\n        if (!SelectedTitle.IsEmpty() && TitleObject != nullptr)\n            TitleObject->SetText(bSelected ? SelectedTitle : Title);\n        if (!SelectedIcon.IsEmpty())\n        {\n            const FString& str = bSelected ? SelectedIcon : Icon;\n            if (IconObject != nullptr)\n                IconObject->SetIcon(str);\n        }\n        if (RelatedController != nullptr && GetParent() != nullptr && !GetParent()->bBuildingDisplayList)\n        {\n            if (bSelected)\n            {\n                RelatedController->SetSelectedPageID(RelatedPageID);\n                if (RelatedController->bAutoRadioGroupDepth)\n                    GetParent()->AdjustRadioGroupDepth(this, RelatedController);\n            }\n            else if (Mode == EButtonMode::Check && RelatedController->GetSelectedPageID() == RelatedPageID)\n                RelatedController->SetOppositePageID(RelatedPageID);\n        }\n    }\n}\n\nvoid UGButton::SetRelatedController(UGController* InController)\n{\n    RelatedController = InController;\n}\n\nvoid UGButton::SetState(const FString& InState)\n{\n    if (ButtonController != nullptr)\n        ButtonController->SetSelectedPage(InState);\n\n    if (DownEffect == 1)\n    {\n        int32 cnt = this->NumChildren();\n        if (InState == DOWN || InState == SELECTED_OVER || InState == SELECTED_DISABLED)\n        {\n            int32 c = DownEffectValue * 255;\n            FNVariant Color(FColor(c, c, c, 255));\n            for (int32 i = 0; i < cnt; i++)\n            {\n                UGObject* Obj = this->GetChildAt(i);\n                if (!Obj->IsA<UGTextField>())\n                    Obj->SetProp(EObjectPropID::Color, Color);\n            }\n        }\n        else\n        {\n            FNVariant Color(FColor::White);\n            for (int32 i = 0; i < cnt; i++)\n            {\n                UGObject* Obj = this->GetChildAt(i);\n                if (!Obj->IsA<UGTextField>())\n                    Obj->SetProp(EObjectPropID::Color, Color);\n            }\n        }\n    }\n    else if (DownEffect == 2)\n    {\n        if (InState == DOWN || InState == SELECTED_OVER || InState == SELECTED_DISABLED)\n        {\n            if (!bDownScaled)\n            {\n                bDownScaled = true;\n                SetScale(GetScale() * DownEffectValue);\n            }\n        }\n        else\n        {\n            if (bDownScaled)\n            {\n                bDownScaled = false;\n                SetScale(GetScale() / DownEffectValue);\n            }\n        }\n    }\n}\n\nvoid UGButton::SetCurrentState()\n{\n    if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(DISABLED))\n    {\n        if (bSelected)\n            SetState(SELECTED_DISABLED);\n        else\n            SetState(DISABLED);\n    }\n    else\n    {\n        if (bSelected)\n            SetState(bOver ? SELECTED_OVER : DOWN);\n        else\n            SetState(bOver ? OVER : UP);\n    }\n}\n\nUGTextField * UGButton::GetTextField() const\n{\n    if (TitleObject->IsA<UGTextField>())\n        return Cast<UGTextField>(TitleObject);\n    else if (TitleObject->IsA<UGLabel>())\n        return Cast<UGLabel>(TitleObject)->GetTextField();\n    else if (TitleObject->IsA<UGButton>())\n        return Cast<UGButton>(TitleObject)->GetTextField();\n    else\n        return nullptr;\n}\n\nFNVariant UGButton::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetTitleColor());\n    case EObjectPropID::OutlineColor:\n    {\n        UGTextField* TextField = GetTextField();\n        if (TextField != nullptr)\n            return FNVariant(TextField->GetTextFormat().OutlineColor);\n        else\n            return FNVariant(FColor::Black);\n    }\n    case EObjectPropID::FontSize:\n        return FNVariant(GetTitleFontSize());\n    case EObjectPropID::Selected:\n        return FNVariant(IsSelected());\n    default:\n        return UGComponent::GetProp(PropID);\n    }\n}\n\nvoid UGButton::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetTitleColor(InValue.AsColor());\n        break;\n    case EObjectPropID::OutlineColor:\n    {\n        UGTextField* TextField = GetTextField();\n        if (TextField != nullptr)\n        {\n            TextField->GetTextFormat().OutlineColor = InValue.AsColor();\n            TextField->ApplyFormat();\n        }\n        break;\n    }\n    case EObjectPropID::FontSize:\n        SetTitleFontSize(InValue.AsInt());\n        break;\n    case EObjectPropID::Selected:\n        SetSelected(InValue.AsBool());\n        break;\n    default:\n        UGComponent::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGButton::ConstructExtension(FByteBuffer* Buffer)\n{\n    Buffer->Seek(0, 6);\n\n    Mode = (EButtonMode)Buffer->ReadByte();\n    Buffer->ReadS(Sound);\n    SoundVolumeScale = Buffer->ReadFloat();\n    DownEffect = Buffer->ReadByte();\n    DownEffectValue = Buffer->ReadFloat();\n    if (DownEffect == 2)\n        SetPivot(FVector2D(0.5f, 0.5f), IsPivotAsAnchor());\n\n    ButtonController = GetController(\"button\");\n    TitleObject = GetChild(\"title\");\n    IconObject = GetChild(\"icon\");\n    if (TitleObject != nullptr)\n        Title = TitleObject->GetText();\n    if (IconObject != nullptr)\n        Icon = IconObject->GetIcon();\n\n    if (Mode == EButtonMode::Common)\n        SetState(UP);\n\n    On(FUIEvents::RollOver).AddUObject(this, &UGButton::OnRollOverHandler);\n    On(FUIEvents::RollOut).AddUObject(this, &UGButton::OnRollOutHandler);\n    On(FUIEvents::TouchBegin).AddUObject(this, &UGButton::OnTouchBeginHandler);\n    On(FUIEvents::TouchEnd).AddUObject(this, &UGButton::OnTouchEndHandler);\n    On(FUIEvents::Click).AddUObject(this, &UGButton::OnClickHandler);\n    On(FUIEvents::RemovedFromStage).AddUObject(this, &UGButton::OnRemovedFromStageHandler);\n}\n\nvoid UGButton::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupAfterAdd(Buffer, BeginPos);\n\n    if (!Buffer->Seek(BeginPos, 6))\n        return;\n\n    if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType)\n        return;\n\n    const FString* str;\n\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetTitle(*str);\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetSelectedTitle(*str);\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetIcon(*str);\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetSelectedIcon(*str);\n    if (Buffer->ReadBool())\n        SetTitleColor(Buffer->ReadColor());\n    int32 iv = Buffer->ReadInt();\n    if (iv != 0)\n        SetTitleFontSize(iv);\n    iv = Buffer->ReadShort();\n    if (iv >= 0)\n        RelatedController = GetParent()->GetControllerAt(iv);\n    RelatedPageID = Buffer->ReadS();\n\n    Buffer->ReadS(Sound);\n    if (Buffer->ReadBool())\n        SoundVolumeScale = Buffer->ReadFloat();\n\n    SetSelected(Buffer->ReadBool());\n}\n\nvoid UGButton::HandleControllerChanged(UGController* Controller)\n{\n    UGObject::HandleControllerChanged(Controller);\n\n    if (RelatedController == Controller)\n        SetSelected(RelatedPageID == Controller->GetSelectedPageID());\n}\n\nvoid UGButton::OnRollOverHandler(UEventContext* Context)\n{\n    if (ButtonController == nullptr || !ButtonController->HasPage(OVER))\n        return;\n\n    bOver = true;\n    if (bDown)\n        return;\n\n    if (IsGrayed() && ButtonController->HasPage(DISABLED))\n        return;\n\n    SetState(bSelected ? SELECTED_OVER : OVER);\n}\n\nvoid UGButton::OnRollOutHandler(UEventContext* Context)\n{\n    if (ButtonController == nullptr || !ButtonController->HasPage(OVER))\n        return;\n\n    bOver = false;\n    if (bDown)\n        return;\n\n    if (IsGrayed() && ButtonController->HasPage(DISABLED))\n        return;\n\n    SetState(bSelected ? DOWN : UP);\n}\n\nvoid UGButton::OnTouchBeginHandler(UEventContext* Context)\n{\n    if (Context->GetMouseButton() != EKeys::LeftMouseButton)\n        return;\n\n    bDown = true;\n    Context->CaptureTouch();\n\n    if (Mode == EButtonMode::Common)\n    {\n        if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(DISABLED))\n            SetState(SELECTED_DISABLED);\n        else\n            SetState(DOWN);\n    }\n}\n\nvoid UGButton::OnTouchEndHandler(UEventContext* Context)\n{\n    if (Context->GetMouseButton() != EKeys::LeftMouseButton)\n        return;\n\n    if (bDown)\n    {\n        bDown = false;\n        if (Mode == EButtonMode::Common)\n        {\n            if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(DISABLED))\n                SetState(DISABLED);\n            else if (bOver)\n                SetState(OVER);\n            else\n                SetState(UP);\n        }\n        else\n        {\n            if (!bOver && ButtonController != nullptr && (ButtonController->GetSelectedPage() == OVER || ButtonController->GetSelectedPage() == SELECTED_OVER))\n            {\n                SetCurrentState();\n            }\n        }\n    }\n}\n\nvoid UGButton::OnClickHandler(UEventContext* Context)\n{\n    if (!Sound.IsEmpty())\n        GetApp()->PlaySound(Sound, SoundVolumeScale);\n\n    if (Mode == EButtonMode::Check)\n    {\n        if (bChangeStateOnClick)\n        {\n            SetSelected(!bSelected);\n            DispatchEvent(FUIEvents::Changed);\n        }\n    }\n    else if (Mode == EButtonMode::Radio)\n    {\n        if (bChangeStateOnClick && !bSelected)\n        {\n            SetSelected(true);\n            DispatchEvent(FUIEvents::Changed);\n        }\n    }\n    else\n    {\n        if (RelatedController != nullptr)\n            RelatedController->SetSelectedPageID(RelatedPageID);\n    }\n}\n\nvoid UGButton::OnRemovedFromStageHandler(UEventContext* Context)\n{\n    if (bOver)\n        OnRollOutHandler(Context);\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GComboBox.cpp",
    "content": "#include \"UI/GComboBox.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GTextField.h\"\n#include \"UI/GTextInput.h\"\n#include \"UI/GLabel.h\"\n#include \"UI/GButton.h\"\n#include \"UI/GController.h\"\n#include \"UI/GList.h\"\n#include \"UI/GRoot.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGComboBox::UGComboBox() :\n    bItemsUpdated(true),\n    SelectedIndex(-1)\n{\n    VisibleItemCount = FUIConfig::Config.DefaultComboBoxVisibleItemCount;\n}\n\nUGComboBox::~UGComboBox()\n{\n}\n\nconst FString& UGComboBox::GetText() const\n{\n    if (TitleObject != nullptr)\n        return TitleObject->GetText();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGComboBox::SetText(const FString& InText)\n{\n    if (TitleObject != nullptr)\n        TitleObject->SetText(InText);\n    UpdateGear(6);\n}\n\nconst FString& UGComboBox::GetIcon() const\n{\n    if (IconObject != nullptr)\n        return IconObject->GetIcon();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGComboBox::SetIcon(const FString & InIcon)\n{\n    if (IconObject != nullptr)\n        IconObject->SetIcon(InIcon);\n    UpdateGear(7);\n}\n\nFColor UGComboBox::GetTitleColor() const\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n        return TextField->GetTextFormat().Color;\n    else\n        return FColor::Black;\n}\n\nvoid UGComboBox::SetTitleColor(const FColor & InColor)\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n    {\n        TextField->GetTextFormat().Color = InColor;\n        TextField->ApplyFormat();\n    }\n}\n\nint32 UGComboBox::GetTitleFontSize() const\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n        return TextField->GetTextFormat().Size;\n    else\n        return 0;\n}\n\nvoid UGComboBox::SetTitleFontSize(int32 InFontSize)\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n    {\n        TextField->GetTextFormat().Size = InFontSize;\n        TextField->ApplyFormat();\n    }\n}\n\nconst FString& UGComboBox::GetValue() const\n{\n    if (SelectedIndex >= 0 && SelectedIndex < Values.Num())\n        return Values[SelectedIndex];\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGComboBox::SetValue(const FString& InValue)\n{\n    SetSelectedIndex(Values.Find(InValue));\n}\n\nvoid UGComboBox::SetSelectedIndex(int32 InIndex)\n{\n    if (SelectedIndex == InIndex)\n        return;\n\n    SelectedIndex = InIndex;\n    if (SelectedIndex >= 0 && SelectedIndex < Items.Num())\n    {\n        SetText(Items[SelectedIndex]);\n        if (Icons.Num() > 0 && SelectedIndex != -1 && SelectedIndex < Icons.Num())\n            SetIcon(Icons[SelectedIndex]);\n    }\n    else\n    {\n        SetTitle(G_EMPTY_STRING);\n        if (Icons.Num() > 0)\n            SetIcon(G_EMPTY_STRING);\n    }\n\n    UpdateSelectionController();\n}\n\nvoid UGComboBox::Refresh()\n{\n    if (Items.Num() > 0)\n    {\n        if (SelectedIndex >= Items.Num())\n            SelectedIndex = Items.Num() - 1;\n        else if (SelectedIndex == -1)\n            SelectedIndex = 0;\n        SetTitle(Items[SelectedIndex]);\n    }\n    else\n    {\n        SetTitle(G_EMPTY_STRING);\n        SelectedIndex = -1;\n    }\n\n    if (Icons.Num() > 0)\n    {\n        if (SelectedIndex != -1 && SelectedIndex < Icons.Num())\n            SetIcon(Icons[SelectedIndex]);\n        else\n            SetIcon(G_EMPTY_STRING);\n    }\n\n    bItemsUpdated = true;\n}\n\nvoid UGComboBox::SetState(const FString& InState)\n{\n    if (ButtonController != nullptr)\n        ButtonController->SetSelectedPage(InState);\n}\n\nvoid UGComboBox::SetCurrentState()\n{\n    if (IsGrayed() && ButtonController != nullptr && ButtonController->HasPage(UGButton::DISABLED))\n        SetState(UGButton::DISABLED);\n    else if (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr)\n        SetState(UGButton::DOWN);\n    else\n        SetState(bOver ? UGButton::OVER : UGButton::UP);\n}\n\nvoid UGComboBox::UpdateSelectionController()\n{\n    if (SelectionController != nullptr && !SelectionController->bChanging && SelectedIndex < SelectionController->GetPageCount())\n    {\n        UGController* c = SelectionController;\n        SelectionController = nullptr;\n        c->SetSelectedIndex(SelectedIndex);\n        SelectionController = c;\n    }\n}\n\nvoid UGComboBox::UpdateDropdownList()\n{\n    if (bItemsUpdated)\n    {\n        bItemsUpdated = false;\n        RenderDropdownList();\n        ListObject->ResizeToFit(VisibleItemCount);\n    }\n}\n\nvoid UGComboBox::ShowDropdown()\n{\n    UpdateDropdownList();\n    if (ListObject->GetSelectionMode() == EListSelectionMode::Single)\n        ListObject->SetSelectedIndex(-1);\n    DropdownObject->SetWidth(Size.X);\n    ListObject->EnsureBoundsCorrect();\n\n    GetUIRoot()->TogglePopup(DropdownObject, this, PopupDirection);\n    if (DropdownObject->GetParent() != nullptr)\n        SetState(UGButton::DOWN);\n}\n\nvoid UGComboBox::RenderDropdownList()\n{\n    ListObject->RemoveChildrenToPool();\n    int32 cnt = Items.Num();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        UGObject* Obj = ListObject->AddItemFromPool();\n        Obj->SetText(Items[i]);\n        Obj->SetIcon((Icons.Num() > 0 && i < Icons.Num()) ? Icons[i] : G_EMPTY_STRING);\n        Obj->Name = i < Values.Num() ? Values[i] : G_EMPTY_STRING;\n    }\n}\n\nvoid UGComboBox::HandleControllerChanged(UGController* Controller)\n{\n    UGComponent::HandleControllerChanged(Controller);\n\n    if (SelectionController == Controller)\n        SetSelectedIndex(Controller->GetSelectedIndex());\n}\n\nvoid UGComboBox::HandleGrayedChanged()\n{\n    if (ButtonController != nullptr && ButtonController->HasPage(UGButton::DISABLED))\n    {\n        if (IsGrayed())\n            SetState(UGButton::DISABLED);\n        else\n            SetState(UGButton::UP);\n    }\n    else\n        UGComponent::HandleGrayedChanged();\n}\n\nUGTextField* UGComboBox::GetTextField() const\n{\n    if (TitleObject->IsA<UGTextField>())\n        return Cast<UGTextField>(TitleObject);\n    else if (TitleObject->IsA<UGLabel>())\n        return Cast<UGLabel>(TitleObject)->GetTextField();\n    else if (TitleObject->IsA<UGButton>())\n        return Cast<UGButton>(TitleObject)->GetTextField();\n    else\n        return nullptr;\n}\n\nFNVariant UGComboBox::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetTitleColor());\n    case EObjectPropID::OutlineColor:\n    {\n        UGTextField* TextField = GetTextField();\n        if (TextField != nullptr)\n            return FNVariant(TextField->GetTextFormat().OutlineColor);\n        else\n            return FNVariant(FColor::Black);\n    }\n    case EObjectPropID::FontSize:\n        return FNVariant(GetTitleFontSize());\n    default:\n        return UGComponent::GetProp(PropID);\n    }\n}\n\nvoid UGComboBox::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetTitleColor(InValue.AsColor());\n        break;\n    case EObjectPropID::OutlineColor:\n    {\n        UGTextField* TextField = GetTextField();\n        if (TextField != nullptr)\n        {\n            TextField->GetTextFormat().OutlineColor = InValue.AsColor();\n            TextField->ApplyFormat();\n        }\n        break;\n    }\n    case EObjectPropID::FontSize:\n        SetTitleFontSize(InValue.AsInt());\n        break;\n    default:\n        UGComponent::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGComboBox::ConstructExtension(FByteBuffer* Buffer)\n{\n    Buffer->Seek(0, 6);\n\n    ButtonController = GetController(\"button\");\n    TitleObject = GetChild(\"title\");\n    IconObject = GetChild(\"icon\");\n\n    const FString& dropdownResource = Buffer->ReadS();\n    if (!dropdownResource.IsEmpty())\n    {\n        DropdownObject = Cast<UGComponent>(UUIPackage::CreateObjectFromURL(dropdownResource, this));\n        verifyf(DropdownObject != nullptr, TEXT(\"should be a component.\"));\n\n        ListObject = Cast<UGList>(DropdownObject->GetChild(\"list\"));\n        verifyf(ListObject != nullptr, TEXT(\"should container a list component named list.\"));\n\n        ListObject->On(FUIEvents::ClickItem).AddUObject(this, &UGComboBox::OnClickItem);\n\n        ListObject->AddRelation(DropdownObject, ERelationType::Width);\n        ListObject->RemoveRelation(DropdownObject, ERelationType::Height);\n\n        DropdownObject->AddRelation(ListObject, ERelationType::Height);\n        DropdownObject->RemoveRelation(ListObject, ERelationType::Width);\n\n        DropdownObject->On(FUIEvents::RemovedFromStage).AddUObject(this, &UGComboBox::OnPopupWinClosed);\n    }\n\n    On(FUIEvents::RollOver).AddUObject(this, &UGComboBox::OnRollOverHandler);\n    On(FUIEvents::RollOut).AddUObject(this, &UGComboBox::OnRollOutHandler);\n    On(FUIEvents::TouchBegin).AddUObject(this, &UGComboBox::OnTouchBeginHandler);\n    On(FUIEvents::TouchEnd).AddUObject(this, &UGComboBox::OnTouchEndHandler);\n}\n\nvoid UGComboBox::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupAfterAdd(Buffer, BeginPos);\n\n    if (!Buffer->Seek(BeginPos, 6))\n        return;\n\n    if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType)\n        return;\n\n    const FString* str;\n    bool hasIcon = false;\n    int32 itemCount = Buffer->ReadShort();\n    for (int32 i = 0; i < itemCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        Items.Add(Buffer->ReadS());\n        Values.Add(Buffer->ReadS());\n        if ((str = Buffer->ReadSP()) != nullptr)\n        {\n            if (!hasIcon)\n            {\n                for (int32 j = 0; j < Items.Num() - 1; j++)\n                    Icons.Add(G_EMPTY_STRING);\n            }\n            Icons.Add(*str);\n        }\n\n        Buffer->SetPos(nextPos);\n    }\n\n    if ((str = Buffer->ReadSP()) != nullptr)\n    {\n        SetTitle(*str);\n        SelectedIndex = Items.Find(*str);\n    }\n    else if (Items.Num() > 0)\n    {\n        SelectedIndex = 0;\n        SetTitle(Items[0]);\n    }\n    else\n        SelectedIndex = -1;\n\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetIcon(*str);\n\n    if (Buffer->ReadBool())\n        SetTitleColor(Buffer->ReadColor());\n    int32 iv = Buffer->ReadInt();\n    if (iv > 0)\n        VisibleItemCount = iv;\n    PopupDirection = (EPopupDirection)Buffer->ReadByte();\n\n    iv = Buffer->ReadShort();\n    if (iv >= 0)\n        SelectionController = GetParent()->GetControllerAt(iv);\n}\n\nvoid UGComboBox::OnClickItem(UEventContext* Context)\n{\n    if (DropdownObject->GetParent()->IsA<UGRoot>())\n        ((UGRoot*)DropdownObject->GetParent())->HidePopup(DropdownObject);\n    SelectedIndex = INT_MIN;\n    SetSelectedIndex(ListObject->GetChildIndex(Cast<UGObject>(Context->GetData().AsUObject())));\n\n    DispatchEvent(FUIEvents::Changed);\n}\n\nvoid UGComboBox::OnRollOverHandler(UEventContext* Context)\n{\n    bOver = true;\n    if (bDown || (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr))\n        return;\n\n    SetCurrentState();\n}\n\nvoid UGComboBox::OnRollOutHandler(UEventContext* Context)\n{\n    bOver = false;\n    if (bDown || (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr))\n        return;\n\n    SetCurrentState();\n}\n\nvoid UGComboBox::OnTouchBeginHandler(UEventContext* Context)\n{\n    if (Context->GetMouseButton() != EKeys::LeftMouseButton)\n        return;\n\n    if (Context->GetInitiator()->IsA<UGTextInput>())\n        return;\n\n    bDown = true;\n\n    if (DropdownObject != nullptr)\n        ShowDropdown();\n\n    Context->CaptureTouch();\n}\n\nvoid UGComboBox::OnTouchEndHandler(UEventContext* Context)\n{\n    if (Context->GetMouseButton() != EKeys::LeftMouseButton)\n        return;\n\n    if (bDown)\n    {\n        bDown = false;\n        if (DropdownObject != nullptr && DropdownObject->GetParent() != nullptr)\n            SetCurrentState();\n    }\n}\n\nvoid UGComboBox::OnPopupWinClosed(UEventContext* Context)\n{\n    SetCurrentState();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GComponent.cpp",
    "content": "#include \"UI/GComponent.h\"\n#include \"UI/GButton.h\"\n#include \"UI/GGroup.h\"\n#include \"UI/Relations.h\"\n#include \"UI/TranslationHelper.h\"\n#include \"UI/UIObjectFactory.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n#include \"UI/Transition.h\"\n#include \"UI/GRoot.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Widgets/SContainer.h\"\n#include \"Widgets/HitTest.h\"\n#include \"Tween/GTween.h\"\n#include \"FairyApplication.h\"\n\n\nUGComponent::UGComponent() :\n    AlignOffset(ForceInit)\n{\n    DisplayObject = RootContainer = SNew(SContainer).GObject(this);\n    DisplayObject->SetOpaque(false);\n\n    Container = SNew(SContainer);\n    Container->SetOpaque(false);\n    RootContainer->AddChild(Container.ToSharedRef());\n}\n\nUGComponent::~UGComponent()\n{\n}\n\nUGObject* UGComponent::AddChild(UGObject* Child)\n{\n    AddChildAt(Child, Children.Num());\n    return Child;\n}\n\nUGObject* UGComponent::AddChildAt(UGObject* Child, int32 Index)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n    verifyf(Index >= 0 && Index <= Children.Num(), TEXT(\"Invalid child index\"));\n\n    if (Child->Parent == this)\n    {\n        SetChildIndex(Child, Index);\n    }\n    else\n    {\n        Child->RemoveFromParent();\n        Child->Parent = this;\n\n        int32 cnt = Children.Num();\n        if (Child->SortingOrder != 0)\n        {\n            SortingChildCount++;\n            Index = GetInsertPosForSortingChild(Child);\n        }\n        else if (SortingChildCount > 0)\n        {\n            if (Index > (cnt - SortingChildCount))\n                Index = cnt - SortingChildCount;\n        }\n\n        if (Index == cnt)\n            Children.Add(Child);\n        else\n            Children.Insert(Child, Index);\n\n        ChildStateChanged(Child);\n        SetBoundsChangedFlag();\n    }\n    return Child;\n}\n\nint32 UGComponent::GetInsertPosForSortingChild(UGObject* Child)\n{\n    int32 cnt = Children.Num();\n    int32 i;\n    for (i = 0; i < cnt; i++)\n    {\n        UGObject* Obj = Children[i];\n        if (Obj == Child)\n            continue;\n\n        if (Child->SortingOrder < Obj->SortingOrder)\n            break;\n    }\n    return i;\n}\n\nvoid UGComponent::RemoveChild(UGObject* Child)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    int32 ChildIndex = Children.Find(Child);\n    if (ChildIndex != INDEX_NONE)\n        RemoveChildAt(ChildIndex);\n}\n\nvoid UGComponent::RemoveChildAt(int32 Index)\n{\n    verifyf(Index >= 0 && Index < Children.Num(), TEXT(\"Invalid child index\"));\n\n    UGObject* Child = Children[Index];\n\n    Child->Parent = nullptr;\n\n    if (Child->SortingOrder != 0)\n        SortingChildCount--;\n\n    Child->SetGroup(nullptr);\n    if (Child->DisplayObject->GetParentWidget().IsValid())\n    {\n        Container->RemoveChild(Child->DisplayObject.ToSharedRef());\n        if (ChildrenRenderOrder == EChildrenRenderOrder::Arch)\n            BuildNativeDisplayList();\n    }\n\n    Children.RemoveAt(Index);\n    SetBoundsChangedFlag();\n}\n\nvoid UGComponent::RemoveChildren(int32 BeginIndex, int32 EndIndex)\n{\n    if (EndIndex < 0 || EndIndex >= Children.Num())\n        EndIndex = Children.Num() - 1;\n\n    for (int32 i = BeginIndex; i <= EndIndex; ++i)\n        RemoveChildAt(BeginIndex);\n}\n\nUGObject* UGComponent::GetChildAt(int32 Index, TSubclassOf<UGObject> ClassType) const\n{\n    verifyf(Index >= 0 && Index < Children.Num(), TEXT(\"Invalid child index\"));\n\n    return Children[Index];\n}\n\nUGObject* UGComponent::GetChild(const FString& ChildName, TSubclassOf<UGObject> ClassType) const\n{\n    for (const auto& Child : Children)\n    {\n        if (Child->Name.Compare(ChildName) == 0)\n            return Child;\n    }\n\n    return nullptr;\n}\n\nUGObject* UGComponent::GetChildByPath(const FString& Path, TSubclassOf<UGObject> ClassType) const\n{\n    const UGComponent* Com = this;\n    UGObject* Obj = nullptr;\n\n    int32 Index1 = 0, Index2 = -1;\n    while ((Index2 = Path.Find(TEXT(\".\"), ESearchCase::IgnoreCase, ESearchDir::FromStart, Index1)) != -1\n        || Index1 == 0)\n    {\n        if (Index2 == -1)\n            Index2 = Path.Len();\n\n        if (Com == nullptr)\n        {\n            Com = Cast<UGComponent>(Obj);\n            if (Com == nullptr)\n            {\n                Obj = nullptr;\n                break;\n            }\n        }\n\n        Obj = Com->GetChild(Path.Mid(Index1, Index2 - Index1));\n        if (!Obj)\n            break;\n\n        Com = nullptr;\n        Index1 = Index2 + 1;\n    }\n\n    return Obj;\n}\n\nUGObject* UGComponent::GetChildInGroup(const UGGroup* InGroup, const FString& ChildName, TSubclassOf<UGObject> ClassType) const\n{\n    verifyf(InGroup != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    for (const auto& Obj : Children)\n    {\n        if (Obj->GetGroup() == InGroup && Obj->Name.Compare(ChildName) == 0)\n            return Obj;\n    }\n\n    return nullptr;\n}\n\nUGObject* UGComponent::GetChildByID(const FString& ChildID) const\n{\n    for (const auto& Obj : Children)\n    {\n        if (Obj->ID.Compare(ChildID) == 0)\n            return Obj;\n    }\n\n    return nullptr;\n}\n\nint32 UGComponent::GetChildIndex(const UGObject* Child) const\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    return Children.IndexOfByKey(Child);\n}\n\nvoid UGComponent::SetChildIndex(UGObject* Child, int32 Index)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    int32 OldIndex = Children.Find(Child);\n    verifyf(OldIndex != -1, TEXT(\"Not a child of this container\"));\n\n    if (Child->SortingOrder != 0) //no effect\n        return;\n\n    int32 cnt = Children.Num();\n    if (SortingChildCount > 0)\n    {\n        if (Index > (cnt - SortingChildCount - 1))\n            Index = cnt - SortingChildCount - 1;\n    }\n\n    MoveChild(Child, OldIndex, Index);\n}\n\nint UGComponent::SetChildIndexBefore(UGObject* Child, int32 Index)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    int32 OldIndex = Children.Find(Child);\n    verifyf(OldIndex != -1, TEXT(\"Not a child of this container\"));\n\n    if (Child->SortingOrder != 0) //no effect\n        return OldIndex;\n\n    int32 cnt = Children.Num();\n    if (SortingChildCount > 0)\n    {\n        if (Index > (cnt - SortingChildCount - 1))\n            Index = cnt - SortingChildCount - 1;\n    }\n\n    if (OldIndex < Index)\n        return MoveChild(Child, OldIndex, Index - 1);\n    else\n        return MoveChild(Child, OldIndex, Index);\n}\n\nint32 UGComponent::MoveChild(UGObject* Child, int32 OldIndex, int32 Index)\n{\n    int32 cnt = Children.Num();\n    if (Index > cnt)\n        Index = cnt;\n\n    if (OldIndex == Index)\n        return OldIndex;\n\n    Children.RemoveAt(OldIndex);\n    if (Index >= cnt)\n        Children.Add(Child);\n    else\n        Children.Insert(Child, Index);\n\n    if (Child->DisplayObject->IsParentValid())\n    {\n        int32 DisplayIndex = 0;\n        if (ChildrenRenderOrder == EChildrenRenderOrder::Ascent)\n        {\n            for (int32 i = 0; i < Index; i++)\n            {\n                UGObject* Obj = Children[i];\n                if (Obj->DisplayObject->IsParentValid())\n                    DisplayIndex++;\n            }\n            Container->SetChildIndex(Child->DisplayObject.ToSharedRef(), DisplayIndex);\n        }\n        else if (ChildrenRenderOrder == EChildrenRenderOrder::Descent)\n        {\n            for (int32 i = cnt - 1; i > Index; i--)\n            {\n                UGObject* Obj = Children[i];\n                if (Obj->DisplayObject->IsParentValid())\n                    DisplayIndex++;\n            }\n            Container->SetChildIndex(Child->DisplayObject.ToSharedRef(), DisplayIndex);\n        }\n        else\n            BuildNativeDisplayList();\n\n        SetBoundsChangedFlag();\n    }\n\n    return Index;\n}\n\nvoid UGComponent::SwapChildren(UGObject* Child1, UGObject* Child2)\n{\n    verifyf(Child1 != nullptr, TEXT(\"Argument1 must be non-nil\"));\n    verifyf(Child2 != nullptr, TEXT(\"Argument2 must be non-nil\"));\n\n    int32 Index1 = Children.Find(Child1);\n    int32 Index2 = Children.Find(Child2);\n\n    verifyf(Index1 != -1, TEXT(\"Not a child of this container\"));\n    verifyf(Index2 != -1, TEXT(\"Not a child of this container\"));\n\n    SwapChildrenAt(Index1, Index2);\n}\n\nvoid UGComponent::SwapChildrenAt(int32 Index1, int32 Index2)\n{\n    UGObject* Child1 = Children[Index1];\n    UGObject* Child2 = Children[Index2];\n\n    SetChildIndex(Child1, Index2);\n    SetChildIndex(Child2, Index1);\n}\n\nint32 UGComponent::NumChildren() const\n{\n    return Children.Num();\n}\n\nbool UGComponent::IsAncestorOf(const UGObject* Obj) const\n{\n    if (Obj == nullptr)\n        return false;\n\n    UGComponent* Com = Obj->Parent.Get();\n    while (Com != nullptr)\n    {\n        if (Com == this)\n            return true;\n\n        Com = Com->Parent.Get();\n    }\n    return false;\n}\n\nbool UGComponent::IsChildInView(UGObject* Child) const\n{\n    if (ScrollPane != nullptr)\n    {\n        return ScrollPane->IsChildInView(Child);\n    }\n    else if (DisplayObject->GetClipping() != EWidgetClipping::Inherit)\n    {\n        return Child->GetX() + Child->GetWidth() >= 0 && Child->GetX() <= GetWidth() && Child->GetY() + Child->GetHeight() >= 0 && Child->GetY() <= GetHeight();\n    }\n    else\n        return true;\n}\n\nint32 UGComponent::GetFirstChildInView() const\n{\n    int32 i = 0;\n    for (auto& Obj : Children)\n    {\n\n        if (IsChildInView(Obj))\n            return i;\n        i++;\n    }\n    return -1;\n}\n\nUGController* UGComponent::GetController(const FString& ControllerName) const\n{\n    for (const auto& Controller : Controllers)\n    {\n        if (Controller->Name.Compare(ControllerName) == 0)\n            return Controller;\n    }\n\n    return nullptr;\n}\n\nvoid UGComponent::AddController(UGController* Controller)\n{\n    verifyf(Controller != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    Controllers.Add(Controller);\n}\n\nUGController* UGComponent::GetControllerAt(int32 Index) const\n{\n    verifyf(Index >= 0 && Index < Controllers.Num(), TEXT(\"Invalid controller index\"));\n\n    return Controllers[Index];\n}\n\nvoid UGComponent::RemoveController(UGController* Controller)\n{\n    verifyf(Controller != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    int32 Index = Controllers.Find(Controller);\n    verifyf(Index != -1, TEXT(\"controller not exists\"));\n\n    ApplyController(Controller);\n    Controllers.RemoveAt(Index);\n}\n\nvoid UGComponent::ApplyController(UGController* Controller)\n{\n    ApplyingController = Controller;\n\n    for (int32 i = 0; i < Children.Num(); i++)\n        Children[i]->HandleControllerChanged(Controller);\n\n    ApplyingController = nullptr;\n\n    Controller->RunActions();\n}\n\nvoid UGComponent::ApplyAllControllers()\n{\n    for (const auto& Controller : Controllers)\n        ApplyController(Controller);\n}\n\nUTransition* UGComponent::GetTransition(const FString& TransitionName) const\n{\n    for (const auto& Transition : Transitions)\n    {\n        if (Transition->Name.Compare(TransitionName) == 0)\n            return Transition;\n    }\n\n    return nullptr;\n}\n\nUTransition* UGComponent::GetTransitionAt(int32 Index) const\n{\n    verifyf(Index >= 0 && Index < Transitions.Num(), TEXT(\"Invalid transition index\"));\n\n    return Transitions[Index];\n}\n\nvoid UGComponent::AdjustRadioGroupDepth(UGObject* Obj, UGController* Controller)\n{\n    int32 cnt = Children.Num();\n    int32 i;\n    UGObject* Child;\n    int32 myIndex = -1, maxIndex = -1;\n    for (i = 0; i < cnt; i++)\n    {\n        Child = Children[i];\n        if (Child == Obj)\n        {\n            myIndex = i;\n        }\n        else if (Child->IsA<UGButton>() && ((UGButton*)Child)->GetRelatedController() == Controller)\n        {\n            if (i > maxIndex)\n                maxIndex = i;\n        }\n    }\n    if (myIndex < maxIndex)\n    {\n        if (ApplyingController != nullptr)\n            Children[maxIndex]->HandleControllerChanged(ApplyingController);\n        SwapChildrenAt(myIndex, maxIndex);\n    }\n}\n\nbool UGComponent::IsOpaque() const\n{\n    return DisplayObject->IsOpaque();\n}\n\nvoid UGComponent::SetOpaque(bool bInOpaque)\n{\n    DisplayObject->SetOpaque(bInOpaque);\n}\n\nvoid UGComponent::SetMargin(const FMargin& InMargin)\n{\n    Margin = InMargin;\n}\n\nvoid UGComponent::SetChildrenRenderOrder(EChildrenRenderOrder InRenderOrder)\n{\n    if (ChildrenRenderOrder != InRenderOrder)\n    {\n        ChildrenRenderOrder = InRenderOrder;\n        BuildNativeDisplayList();\n    }\n}\n\nvoid UGComponent::SetApexIndex(int32 InApexIndex)\n{\n    if (ApexIndex != InApexIndex)\n    {\n        ApexIndex = InApexIndex;\n\n        if (ChildrenRenderOrder == EChildrenRenderOrder::Arch)\n            BuildNativeDisplayList();\n    }\n}\n\nfloat UGComponent::GetViewWidth() const\n{\n    if (ScrollPane != nullptr)\n        return ScrollPane->GetViewSize().X;\n    else\n        return Size.X - Margin.Left - Margin.Right;\n}\n\nvoid UGComponent::SetViewWidth(float InViewWidth)\n{\n    if (ScrollPane != nullptr)\n        ScrollPane->SetViewWidth(InViewWidth);\n    else\n        SetWidth(InViewWidth + Margin.Left + Margin.Right);\n}\n\nfloat UGComponent::GetViewHeight() const\n{\n    if (ScrollPane != nullptr)\n        return ScrollPane->GetViewSize().Y;\n    else\n        return Size.Y - Margin.Top - Margin.Bottom;\n}\n\nvoid UGComponent::SetViewHeight(float InViewHeight)\n{\n    if (ScrollPane != nullptr)\n        ScrollPane->SetViewHeight(InViewHeight);\n    else\n        SetHeight(InViewHeight + Margin.Top + Margin.Bottom);\n}\n\nvoid UGComponent::SetHitArea(const TSharedPtr<IHitTest>& InHitArea)\n{\n    HitArea = InHitArea;\n    DisplayObject->UpdateVisibilityFlags();\n}\n\nvoid UGComponent::SetBoundsChangedFlag()\n{\n    if (bBoundsChanged)\n        return;\n\n    if (ScrollPane == nullptr && !bTrackBounds)\n        return;\n\n    bBoundsChanged = true;\n\n    GetApp()->DelayCall(UpdateBoundsTimerHandle, this, &UGComponent::EnsureBoundsCorrect);\n}\n\nvoid UGComponent::EnsureBoundsCorrect()\n{\n    if (bBoundsChanged)\n        UpdateBounds();\n}\n\nvoid UGComponent::UpdateBounds()\n{\n    float ax, ay, aw, ah;\n    if (Children.Num() > 0)\n    {\n        ax = FLT_MAX;\n        ay = FLT_MAX;\n        float ar = -FLT_MAX, ab = -FLT_MAX;\n        float tmp;\n\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; ++i)\n        {\n            UGObject* child = Children[i];\n            tmp = child->GetX();\n            if (tmp < ax)\n                ax = tmp;\n            tmp = child->GetY();\n            if (tmp < ay)\n                ay = tmp;\n            tmp = child->GetX() + child->GetWidth();\n            if (tmp > ar)\n                ar = tmp;\n            tmp = child->GetY() + child->GetHeight();\n            if (tmp > ab)\n                ab = tmp;\n        }\n        aw = ar - ax;\n        ah = ab - ay;\n    }\n    else\n    {\n        ax = 0;\n        ay = 0;\n        aw = 0;\n        ah = 0;\n    }\n    SetBounds(ax, ay, aw, ah);\n}\n\nvoid UGComponent::SetBounds(float ax, float ay, float aw, float ah)\n{\n    bBoundsChanged = false;\n    if (ScrollPane != nullptr)\n        ScrollPane->SetContentSize(FVector2D(FMath::CeilToFloat(ax + aw), FMath::CeilToFloat(ay + ah)));\n}\n\nvoid UGComponent::ChildStateChanged(UGObject* Child)\n{\n    if (bBuildingDisplayList)\n        return;\n\n    int32 cnt = Children.Num();\n    if (Cast<UGGroup>(Child) != nullptr)\n    {\n        for (int32 i = 0; i < cnt; ++i)\n        {\n            UGObject* Obj = Children[i];\n            if (Obj->GetGroup() == Child)\n                ChildStateChanged(Obj);\n        }\n    }\n\n    if (Child->InternalVisible())\n    {\n        if (!Child->DisplayObject->IsParentValid())\n        {\n            if (ChildrenRenderOrder == EChildrenRenderOrder::Ascent)\n            {\n                int32 index = 0;\n                for (int32 i = 0; i < cnt; i++)\n                {\n                    UGObject* Obj = Children[i];\n                    if (Obj == Child)\n                        break;\n\n                    if (Obj->DisplayObject->IsParentValid())\n                        index++;\n                }\n\n                Container->AddChildAt(Child->DisplayObject.ToSharedRef(), index);\n            }\n            else if (ChildrenRenderOrder == EChildrenRenderOrder::Descent)\n            {\n                int32 index = 0;\n                for (int32 i = cnt - 1; i >= 0; i--)\n                {\n                    UGObject* Obj = Children[i];\n                    if (Obj == Child)\n                        break;\n\n                    if (Obj->DisplayObject->IsParentValid())\n                        index++;\n                }\n\n                Container->AddChildAt(Child->DisplayObject.ToSharedRef(), index);\n            }\n            else\n            {\n                BuildNativeDisplayList();\n            }\n        }\n    }\n    else\n    {\n        if (Child->DisplayObject->IsParentValid())\n        {\n            Container->RemoveChild(Child->DisplayObject.ToSharedRef());\n            if (ChildrenRenderOrder == EChildrenRenderOrder::Arch)\n            {\n                BuildNativeDisplayList();\n            }\n        }\n    }\n}\n\nvoid UGComponent::ChildSortingOrderChanged(UGObject* Child, int32 OldValue, int32 NewValue)\n{\n    if (NewValue == 0)\n    {\n        SortingChildCount--;\n        SetChildIndex(Child, Children.Num());\n    }\n    else\n    {\n        if (OldValue == 0)\n            SortingChildCount++;\n\n        int32 OldIndex = Children.Find(Child);\n        int32 Index = GetInsertPosForSortingChild(Child);\n        if (OldIndex < Index)\n            MoveChild(Child, OldIndex, Index - 1);\n        else\n            MoveChild(Child, OldIndex, Index);\n    }\n}\n\nvoid UGComponent::BuildNativeDisplayList(bool bImmediatelly)\n{\n    if (!bImmediatelly)\n    {\n        GetApp()->DelayCall(BuildDisplayListTimerHandle, this, &UGComponent::BuildNativeDisplayList, true);\n        return;\n    }\n\n    int32 cnt = Children.Num();\n    if (cnt == 0)\n        return;\n\n    switch (ChildrenRenderOrder)\n    {\n    case EChildrenRenderOrder::Ascent:\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* Child = Children[i];\n            if (Child->InternalVisible())\n                Container->AddChild(Child->DisplayObject.ToSharedRef());\n        }\n    }\n    break;\n    case EChildrenRenderOrder::Descent:\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* Child = Children[i];\n            if (Child->InternalVisible())\n                Container->AddChild(Child->DisplayObject.ToSharedRef());\n        }\n    }\n    break;\n\n    case EChildrenRenderOrder::Arch:\n    {\n        int32 ai = FMath::Min(ApexIndex, cnt);\n        for (int32 i = 0; i < ai; i++)\n        {\n            UGObject* Child = Children[i];\n            if (Child->InternalVisible())\n                Container->AddChild(Child->DisplayObject.ToSharedRef());\n        }\n        for (int32 i = cnt - 1; i >= ai; i--)\n        {\n            UGObject* Child = Children[i];\n            if (Child->InternalVisible())\n                Container->AddChild(Child->DisplayObject.ToSharedRef());\n        }\n    }\n    break;\n\n    default:\n        break;\n    }\n}\n\nFVector2D UGComponent::GetSnappingPosition(const FVector2D& InPoint)\n{\n    int32 cnt = Children.Num();\n    if (cnt == 0)\n        return InPoint;\n\n    EnsureBoundsCorrect();\n\n    UGObject* Obj = nullptr;\n\n    FVector2D ret = InPoint;\n\n    int32 i = 0;\n    if (ret.Y != 0)\n    {\n        for (; i < cnt; i++)\n        {\n            Obj = Children[i];\n            if (ret.Y < Obj->GetY())\n            {\n                if (i == 0)\n                {\n                    ret.Y = 0;\n                    break;\n                }\n                else\n                {\n                    UGObject* prev = Children[i - 1];\n                    if (ret.Y < prev->GetY() + prev->GetHeight() / 2) //top half part\n                        ret.Y = prev->GetY();\n                    else //bottom half part\n                        ret.Y = Obj->GetY();\n                    break;\n                }\n            }\n        }\n\n        if (i == cnt)\n            ret.Y = Obj->GetY();\n    }\n\n    if (ret.X != 0)\n    {\n        if (i > 0)\n            i--;\n        for (; i < cnt; i++)\n        {\n            Obj = Children[i];\n            if (ret.X < Obj->GetX())\n            {\n                if (i == 0)\n                {\n                    ret.X = 0;\n                    break;\n                }\n                else\n                {\n                    UGObject* prev = Children[i - 1];\n                    if (ret.X < prev->GetX() + prev->GetWidth() / 2) // top half part\n                        ret.X = prev->GetX();\n                    else //bottom half part\n                        ret.X = Obj->GetX();\n                    break;\n                }\n            }\n        }\n        if (i == cnt)\n            ret.X = Obj->GetX();\n    }\n\n    return ret;\n}\n\nvoid UGComponent::SetupOverflow(EOverflowType InOverflow)\n{\n    if (InOverflow == EOverflowType::Hidden)\n    {\n        DisplayObject->SetClipping(EWidgetClipping::ClipToBoundsAlways);\n        DisplayObject->SetCullingBoundsExtension(Margin);\n    }\n\n    Container->SetPosition(Margin.GetTopLeft());\n}\n\nvoid UGComponent::SetupScroll(FByteBuffer* Buffer)\n{\n    ScrollPane = NewObject<UScrollPane>(this);\n    ScrollPane->Setup(Buffer);\n}\n\nvoid UGComponent::HandleSizeChanged()\n{\n    UGObject::HandleSizeChanged();\n\n    if (ScrollPane != nullptr)\n        ScrollPane->OnOwnerSizeChanged();\n    else\n        Container->SetPosition(FVector2D(Margin.Left, Margin.Top));\n\n    if (DisplayObject->GetClipping() != EWidgetClipping::Inherit)\n        DisplayObject->SetCullingBoundsExtension(Margin);\n}\n\nvoid UGComponent::HandleGrayedChanged()\n{\n    UGObject::HandleGrayedChanged();\n\n    UGController* Controller = GetController(\"grayed\");\n    if (Controller != nullptr)\n        Controller->SetSelectedIndex(IsGrayed() ? 1 : 0);\n    else\n    {\n        for (auto& Child : Children)\n            Child->HandleGrayedChanged();\n    }\n}\n\nvoid UGComponent::HandleControllerChanged(UGController* Controller)\n{\n    UGObject::HandleControllerChanged(Controller);\n\n    if (ScrollPane != nullptr)\n        ScrollPane->HandleControllerChanged(Controller);\n}\n\nvoid UGComponent::OnAddedToStageHandler(UEventContext* Context)\n{\n    for (auto& Transition : Transitions)\n        Transition->OnOwnerAddedToStage();\n}\n\nvoid UGComponent::OnRemovedFromStageHandler(UEventContext* Context)\n{\n    for (auto& Transition : Transitions)\n        Transition->OnOwnerRemovedFromStage();\n}\n\nvoid UGComponent::ConstructFromResource()\n{\n    ConstructFromResource(nullptr, 0);\n}\n\nvoid UGComponent::ConstructFromResource(TArray<UGObject*>* ObjectPool, int32 PoolIndex)\n{\n    TSharedPtr<FPackageItem> ContentItem = PackageItem->GetBranch();\n\n    if (!ContentItem->bTranslated)\n    {\n        ContentItem->bTranslated = true;\n        FTranslationHelper::TranslateComponent(ContentItem);\n    }\n\n    FByteBuffer* Buffer = ContentItem->RawData.Get();\n    Buffer->Seek(0, 0);\n\n    bUnderConstruct = true;\n\n    SourceSize.X = Buffer->ReadInt();\n    SourceSize.Y = Buffer->ReadInt();\n    InitSize = SourceSize;\n\n    SetSize(SourceSize);\n\n    if (Buffer->ReadBool())\n    {\n        MinSize.X = Buffer->ReadInt();\n        MaxSize.X = Buffer->ReadInt();\n        MinSize.Y = Buffer->ReadInt();\n        MaxSize.Y = Buffer->ReadInt();\n    }\n\n    if (Buffer->ReadBool())\n    {\n        float f1 = Buffer->ReadFloat();\n        float f2 = Buffer->ReadFloat();\n        SetPivot(FVector2D(f1, f2), Buffer->ReadBool());\n    }\n\n    if (Buffer->ReadBool())\n    {\n        Margin.Top = Buffer->ReadInt();\n        Margin.Bottom = Buffer->ReadInt();\n        Margin.Left = Buffer->ReadInt();\n        Margin.Right = Buffer->ReadInt();\n    }\n\n    EOverflowType overflow = (EOverflowType)Buffer->ReadByte();\n    if (overflow == EOverflowType::Scroll)\n    {\n        int32 savedPos = Buffer->GetPos();\n        Buffer->Seek(0, 7);\n        SetupScroll(Buffer);\n        Buffer->SetPos(savedPos);\n    }\n    else\n        SetupOverflow(overflow);\n\n    if (Buffer->ReadBool()) //clip soft\n        Buffer->Skip(8);\n\n    bBuildingDisplayList = true;\n\n    Buffer->Seek(0, 1);\n\n    int32 controllerCount = Buffer->ReadShort();\n    for (int32 i = 0; i < controllerCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        UGController* Controller = NewObject<UGController>(this);\n        Controllers.Add(Controller);\n        Controller->Setup(Buffer);\n\n        Buffer->SetPos(nextPos);\n    }\n\n    Buffer->Seek(0, 2);\n\n    UGObject* Child;\n    int32 childCount = Buffer->ReadShort();\n    for (int32 i = 0; i < childCount; i++)\n    {\n        int32 dataLen = Buffer->ReadShort();\n        int32 curPos = Buffer->GetPos();\n\n        if (ObjectPool != nullptr)\n            Child = (*ObjectPool)[PoolIndex + i];\n        else\n        {\n            Buffer->Seek(curPos, 0);\n\n            EObjectType type = (EObjectType)Buffer->ReadByte();\n            const FString& src = Buffer->ReadS();\n            const FString& pkgId = Buffer->ReadS();\n\n            TSharedPtr<FPackageItem> pii;\n            if (!src.IsEmpty())\n            {\n                UUIPackage* pkg;\n                if (!pkgId.IsEmpty())\n                    pkg = UUIPackage::GetPackageByID(pkgId);\n                else\n                    pkg = ContentItem->Owner;\n\n                if (pkg != nullptr)\n                    pii = pkg->GetItem(src);\n            }\n\n            if (pii.IsValid())\n            {\n                Child = FUIObjectFactory::NewObject(pii, this);\n                Child->ConstructFromResource();\n            }\n            else\n                Child = FUIObjectFactory::NewObject(type, this);\n        }\n\n        Child->bUnderConstruct = true;\n        Child->SetupBeforeAdd(Buffer, curPos);\n        Child->Parent = this;\n        Children.Add(Child);\n\n        Buffer->SetPos(curPos + dataLen);\n    }\n\n    Buffer->Seek(0, 3);\n    Relations->Setup(Buffer, true);\n\n    Buffer->Seek(0, 2);\n    Buffer->Skip(2);\n\n    for (int32 i = 0; i < childCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        Buffer->Seek(Buffer->GetPos(), 3);\n        Children[i]->GetRelations()->Setup(Buffer, false);\n\n        Buffer->SetPos(nextPos);\n    }\n\n    Buffer->Seek(0, 2);\n    Buffer->Skip(2);\n\n    for (int32 i = 0; i < childCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        Child = Children[i];\n        Child->SetupAfterAdd(Buffer, Buffer->GetPos());\n        Child->bUnderConstruct = false;\n\n        Buffer->SetPos(nextPos);\n    }\n\n    Buffer->Seek(0, 4);\n\n    Buffer->Skip(2); //customData\n    SetOpaque(Buffer->ReadBool());\n    int32 maskId = Buffer->ReadShort();\n    if (maskId != -1)\n    {\n        bool inverted = Buffer->ReadBool();\n        //setMask(getChildAt(maskId)->displayObject(), inverted);\n    }\n\n    const FString& hitTestId = Buffer->ReadS();\n    int32 i1 = Buffer->ReadInt();\n    int32 i2 = Buffer->ReadInt();\n    if (!hitTestId.IsEmpty())\n    {\n        TSharedPtr<FPackageItem> pii = ContentItem->Owner->GetItem(hitTestId);\n        if (pii.IsValid() && pii->PixelHitTestData.IsValid())\n            SetHitArea(MakeShareable(new FPixelHitTest(pii->PixelHitTestData, i1, i2)));\n    }\n    else if (i1 != 0 && i2 != -1)\n    {\n        SetHitArea(MakeShareable(new FChildHitTest(GetChildAt(i2))));\n    }\n\n    if (Buffer->Version >= 5)\n    {\n        const FString& enterSound = Buffer->ReadS();\n        if (!enterSound.IsEmpty()) {\n            On(FUIEvents::AddedToStage).AddLambda([this, enterSound](UEventContext*) {\n                GetApp()->PlaySound(enterSound, 1);\n            });\n        }\n\n\n        const FString& leaveSound = Buffer->ReadS();\n        if (!leaveSound.IsEmpty()) {\n            On(FUIEvents::RemovedFromStage).AddLambda([this, leaveSound](UEventContext*) {\n                GetApp()->PlaySound(leaveSound, 1);\n            });\n        }\n    }\n\n    Buffer->Seek(0, 5);\n\n    int32 transitionCount = Buffer->ReadShort();\n    for (int32 i = 0; i < transitionCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        UTransition* Transition = NewObject<UTransition>(this);\n        Transitions.Add(Transition);\n        Transition->Setup(Buffer);\n\n        Buffer->SetPos(nextPos);\n    }\n\n    if (Transitions.Num() > 0) {\n        On(FUIEvents::AddedToStage).AddUObject(this, &UGComponent::OnAddedToStageHandler);\n        On(FUIEvents::RemovedFromStage).AddUObject(this, &UGComponent::OnRemovedFromStageHandler);\n    }\n\n    ApplyAllControllers();\n\n    bBuildingDisplayList = false;\n    bUnderConstruct = false;\n\n    BuildNativeDisplayList();\n    SetBoundsChangedFlag();\n\n    if (ContentItem->ObjectType != EObjectType::Component)\n        ConstructExtension(Buffer);\n\n    OnConstruct();\n}\n\nvoid UGComponent::ConstructExtension(FByteBuffer* Buffer)\n{\n}\n\nvoid UGComponent::OnConstruct()\n{\n    K2_OnConstruct();\n}\n\nvoid UGComponent::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupAfterAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 4);\n\n    int32 pageController = Buffer->ReadShort();\n    if (pageController != -1 && ScrollPane != nullptr && ScrollPane->bPageMode)\n        ScrollPane->PageController = Parent->GetControllerAt(pageController);\n\n    int32 cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        UGController* Controller = GetController(Buffer->ReadS());\n        const FString& PageID = Buffer->ReadS();\n        if (Controller != nullptr)\n            Controller->SetSelectedPageID(PageID);\n    }\n\n    if (Buffer->Version >= 2)\n    {\n        cnt = Buffer->ReadShort();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FString Target = Buffer->ReadS();\n            EObjectPropID PropID = (EObjectPropID)Buffer->ReadShort();\n            FString Value = Buffer->ReadS();\n            UGObject* Obj = GetChildByPath(Target);\n            if (Obj != nullptr)\n                Obj->SetProp(PropID, FNVariant(Value));\n        }\n    }\n}\n\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GController.cpp",
    "content": "#include \"UI/GController.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/UIPackage.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGController::UGController() :\n    SelectedIndex(-1),\n    PreviousIndex(-1)\n{\n}\n\nUGController::~UGController()\n{\n}\n\nvoid UGController::SetSelectedIndex(int32 Index)\n{\n    SetSelectedIndex(Index, true);\n}\n\nvoid UGController::SetSelectedIndex(int32 Index, bool bTriggerEvent)\n{\n    if (SelectedIndex != Index)\n    {\n        verifyf(Index < PageIDs.Num(), TEXT(\"Invalid selected index\"));\n\n        bChanging = true;\n\n        PreviousIndex = SelectedIndex;\n        SelectedIndex = Index;\n        Cast<UGComponent>(GetOuter())->ApplyController(this);\n\n        if (bTriggerEvent)\n            OnChangedEvent.Broadcast(this);\n\n        bChanging = false;\n    }\n}\n\nconst FString& UGController::GetSelectedPage() const\n{\n    if (SelectedIndex == -1)\n        return G_EMPTY_STRING;\n    else\n        return PageNames[SelectedIndex];\n}\n\nvoid UGController::SetSelectedPage(const FString& PageName)\n{\n    SetSelectedPage(PageName, true);\n}\n\nvoid UGController::SetSelectedPage(const FString& PageName, bool bTriggerEvent)\n{\n    int32 i = PageNames.Find(PageName);\n    if (i == INDEX_NONE)\n        i = 0;\n    SetSelectedIndex(i, bTriggerEvent);\n}\n\nconst FString& UGController::GetSelectedPageID() const\n{\n    if (SelectedIndex == -1)\n        return G_EMPTY_STRING;\n    else\n        return PageIDs[SelectedIndex];\n}\n\nvoid UGController::SetSelectedPageID(const FString& PageID, bool bTriggerEvent)\n{\n    int32 i = PageIDs.Find(PageID);\n    if (i != INDEX_NONE)\n        SetSelectedIndex(i, bTriggerEvent);\n}\n\nconst FString& UGController::GetPreviousPage() const\n{\n    if (PreviousIndex == -1)\n        return G_EMPTY_STRING;\n    else\n        return PageNames[PreviousIndex];\n}\n\nconst FString& UGController::GetPreviousPageID() const\n{\n    if (PreviousIndex == -1)\n        return G_EMPTY_STRING;\n    else\n        return PageIDs[PreviousIndex];\n}\n\nint32 UGController::GetPageCount() const\n{\n    return PageIDs.Num();\n}\n\nbool UGController::HasPage(const FString& PageName) const\n{\n    return PageNames.Find(PageName) != INDEX_NONE;\n}\n\nint32 UGController::GetPageIndexByID(const FString& PageID) const\n{\n    return PageIDs.Find(PageID) != INDEX_NONE;\n}\n\nconst FString& UGController::GetPageNameByID(const FString& PageID) const\n{\n    int32 i = PageIDs.Find(PageID);\n    if (i != INDEX_NONE)\n        return PageNames[i];\n    else\n        return G_EMPTY_STRING;\n}\n\nconst FString& UGController::GetPageID(int32 Index) const\n{\n    return PageIDs[Index];\n}\n\nvoid UGController::SetOppositePageID(const FString& PageID)\n{\n    int32 i = PageIDs.Find(PageID);\n    if (i > 0)\n        SetSelectedIndex(0);\n    else if (PageIDs.Num() > 1)\n        SetSelectedIndex(1);\n}\n\nvoid UGController::RunActions()\n{\n    if (Actions.Num() == 0)\n        return;\n\n    for (auto& it : Actions)\n        it.Run(this, GetPreviousPageID(), GetSelectedPageID());\n}\n\nvoid UGController::Setup(FByteBuffer* Buffer)\n{\n    int32 BeginPos = Buffer->GetPos();\n    Buffer->Seek(BeginPos, 0);\n\n    Name = Buffer->ReadS();\n    bAutoRadioGroupDepth = Buffer->ReadBool();\n\n    Buffer->Seek(BeginPos, 1);\n\n    int32 cnt = Buffer->ReadShort();\n    PageIDs.SetNum(cnt);\n    PageNames.SetNum(cnt);\n    for (int32 i = 0; i < cnt; i++)\n    {\n        PageIDs[i] = Buffer->ReadS();\n        PageNames[i] = Buffer->ReadS();\n    }\n\n    int32 HomePageIndex = 0;\n    if (Buffer->Version >= 2)\n    {\n        int32 HomePageType = Buffer->ReadByte();\n        switch (HomePageType)\n        {\n        case 1:\n            HomePageIndex = Buffer->ReadShort();\n            break;\n\n        case 2:\n            HomePageIndex = PageNames.Find(UUIPackage::GetBranch());\n            if (HomePageIndex == INDEX_NONE)\n                HomePageIndex = 0;\n            break;\n\n        case 3:\n            HomePageIndex = PageNames.Find(UUIPackage::GetVar(Buffer->ReadS()));\n            if (HomePageIndex == INDEX_NONE)\n                HomePageIndex = 0;\n            break;\n        }\n    }\n\n    Buffer->Seek(BeginPos, 2);\n\n    cnt = Buffer->ReadShort();\n    if (cnt > 0)\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            int32 nextPos = Buffer->ReadShort();\n            nextPos += Buffer->GetPos();\n\n            FControllerAction* Action = FControllerAction::CreateAction(Buffer->ReadByte());\n            Action->Setup(Buffer);\n            Actions.Add(Action);\n\n            Buffer->SetPos(nextPos);\n        }\n    }\n\n    if (PageIDs.Num() > 0)\n        SelectedIndex = HomePageIndex;\n    else\n        SelectedIndex = -1;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GGraph.cpp",
    "content": "#include \"UI/GGraph.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/SShape.h\"\n#include \"Widgets/Mesh/RectMesh.h\"\n#include \"Widgets/Mesh/RoundedRectMesh.h\"\n#include \"Widgets/Mesh/PolygonMesh.h\"\n#include \"Widgets/Mesh/RegularPolygonMesh.h\"\n#include \"Widgets/Mesh/EllipseMesh.h\"\n\nUGGraph::UGGraph()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n        DisplayObject = Content = SNew(SShape).GObject(this);\n}\n\nUGGraph::~UGGraph()\n{\n\n}\n\nFColor UGGraph::GetColor() const\n{\n    return Content->Graphics.GetColor();\n}\n\nvoid UGGraph::SetColor(const FColor& InColor)\n{\n    Content->Graphics.SetColor(InColor);\n}\n\nvoid UGGraph::DrawRect(float LineWidth, const FColor& LineColor, const FColor& FillColor)\n{\n    FRectMesh& mesh = Content->Graphics.GetMeshFactory<FRectMesh>();\n    mesh.LineWidth = LineWidth;\n    mesh.LineColor = LineColor;\n    mesh.FillColor.Reset();\n    mesh.Colors.Reset();\n\n    Content->Graphics.SetColor(FillColor);\n    Content->Graphics.SetMeshDirty();\n}\n\nvoid UGGraph::DrawRoundRect(float LineWidth, const FColor& lineColor, const FColor& FillColor,\n    float TopLeftRadius, float TopRightRadius, float BottomLeftRadius, float BottomRightRadius)\n{\n    FRoundedRectMesh& mesh = Content->Graphics.GetMeshFactory<FRoundedRectMesh>();\n    mesh.LineWidth = LineWidth;\n    mesh.LineColor = lineColor;\n    mesh.FillColor.Reset();\n    mesh.TopLeftRadius = TopLeftRadius;\n    mesh.TopRightRadius = TopRightRadius;\n    mesh.BottomLeftRadius = BottomLeftRadius;\n    mesh.BottomRightRadius = BottomRightRadius;\n\n    Content->Graphics.SetColor(FillColor);\n    Content->Graphics.SetMeshDirty();\n}\n\nvoid UGGraph::DrawEllipse(float LineWidth, const FColor& LineColor, const FColor& FillColor, float StartDegree, float EndDegree)\n{\n    FEllipseMesh& mesh = Content->Graphics.GetMeshFactory<FEllipseMesh>();\n    mesh.LineWidth = LineWidth;\n    mesh.LineColor = LineColor;\n    mesh.FillColor.Reset();\n    mesh.CenterColor.Reset();\n    mesh.StartDegree = StartDegree;\n    mesh.EndDegreee = EndDegree;\n\n    Content->Graphics.SetColor(FillColor);\n    Content->Graphics.SetMeshDirty();\n}\n\nvoid UGGraph::DrawPolygon(float LineWidth, const FColor& LineColor, const FColor& FillColor, const TArray<FVector2D>& Points)\n{\n    FPolygonMesh& mesh = Content->Graphics.GetMeshFactory<FPolygonMesh>();\n    mesh.LineWidth = LineWidth;\n    mesh.LineColor = LineColor;\n    mesh.Points.Reset();\n    mesh.Points.Append(Points);\n    mesh.FillColor.Reset();\n    mesh.Colors.Reset();\n\n    Content->Graphics.SetColor(FillColor);\n    Content->Graphics.SetMeshDirty();\n}\n\nvoid UGGraph::DrawRegularPolygon(int32 Sides, float LineWidth, const FColor& LineColor, const FColor& FillColor, float ShapeRotation, const TArray<float>& Distances)\n{\n    FRegularPolygonMesh& mesh = Content->Graphics.GetMeshFactory<FRegularPolygonMesh>();\n    mesh.Sides = Sides;\n    mesh.LineWidth = LineWidth;\n    mesh.CenterColor.Reset();\n    mesh.LineColor = LineColor;\n    mesh.FillColor.Reset();\n    mesh.Rotation = ShapeRotation;\n    mesh.Distances.Reset();\n    mesh.Distances.Append(Distances);\n\n    Content->Graphics.SetColor(FillColor);\n    Content->Graphics.SetMeshDirty();\n}\n\nvoid UGGraph::Clear()\n{\n    Content->Graphics.SetMeshFactory(nullptr);\n}\n\nbool UGGraph::IsEmpty() const\n{\n    return !Content->Graphics.GetMeshFactory().IsValid();\n}\n\nIHitTest* UGGraph::GetHitArea() const\n{\n    const TSharedPtr<IMeshFactory>& Factory = Content->Graphics.GetMeshFactory();\n    if (Factory.IsValid())\n        return Factory->GetMeshHitTest();\n    else\n        return nullptr;\n}\n\nFNVariant UGGraph::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(Content->Graphics.GetColor());\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGGraph::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetColor(InValue.AsColor());\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGGraph::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    int32 type = Buffer->ReadByte();\n    if (type != 0)\n    {\n        int32 lineWidth = Buffer->ReadInt();\n        FColor lineColor = Buffer->ReadColor();\n        FColor fillColor = Buffer->ReadColor();\n        bool roundedRect = Buffer->ReadBool();\n        FVector4 cornerRadius;\n        if (roundedRect)\n        {\n            for (int32 i = 0; i < 4; i++)\n                cornerRadius[i] = Buffer->ReadFloat();\n        }\n\n        if (type == 1)\n        {\n            if (roundedRect)\n                DrawRoundRect(lineWidth, lineColor, fillColor, cornerRadius.X, cornerRadius.Y, cornerRadius.Z, cornerRadius.W);\n            else\n                DrawRect(lineWidth, lineColor, fillColor);\n        }\n        else if (type == 2)\n            DrawEllipse(lineWidth, lineColor, fillColor);\n        else if (type == 3)\n        {\n            int32 cnt = Buffer->ReadShort() / 2;\n            TArray<FVector2D> points;\n            for (int32 i = 0; i < cnt; i++)\n            {\n                float f1 = Buffer->ReadFloat();\n                float f2 = Buffer->ReadFloat();\n                points.Add(FVector2D(f1, f2));\n            }\n\n            DrawPolygon(lineWidth, lineColor, fillColor, points);\n        }\n        else if (type == 4)\n        {\n            int32 sides = Buffer->ReadShort();\n            float startAngle = Buffer->ReadFloat();\n            int32 cnt = Buffer->ReadShort();\n            TArray<float> distances;\n            if (cnt > 0)\n            {\n                for (int32 i = 0; i < cnt; i++)\n                    distances.Add(Buffer->ReadFloat());\n            }\n\n            DrawRegularPolygon(sides, lineWidth, lineColor, fillColor, startAngle, distances);\n        }\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GGroup.cpp",
    "content": "#include \"UI/GGroup.h\"\n#include \"UI/GComponent.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Widgets/SDisplayObject.h\"\n\nUGGroup::UGGroup() :\n    MainGridIndex(-1),\n    MainGridMinSize(10),\n    MainChildIndex(-1)\n{\n    DisplayObject = SNew(SDisplayObject).GObject(this);;\n    DisplayObject->SetInteractable(false);\n}\n\nUGGroup::~UGGroup()\n{\n}\n\nvoid UGGroup::SetLayout(EGroupLayoutType InLayout)\n{\n    if (Layout != InLayout)\n    {\n        Layout = InLayout;\n        SetBoundsChangedFlag(true);\n    }\n}\n\nvoid UGGroup::SetColumnGap(int32 InColumnGap)\n{\n    if (ColumnGap != InColumnGap)\n    {\n        ColumnGap = InColumnGap;\n        SetBoundsChangedFlag();\n    }\n}\n\nvoid UGGroup::SetLineGap(int32 InLineGap)\n{\n    if (LineGap != InLineGap)\n    {\n        LineGap = InLineGap;\n        SetBoundsChangedFlag();\n    }\n}\n\nvoid UGGroup::SetExcludeInvisibles(bool Flag)\n{\n    if (bExcludeInvisibles != Flag)\n    {\n        bExcludeInvisibles = Flag;\n        SetBoundsChangedFlag();\n    }\n}\nvoid UGGroup::SetAutoSizeDisabled(bool Flag)\n{\n    if (bAutoSizeDisabled != Flag)\n    {\n        bAutoSizeDisabled = Flag;\n        SetBoundsChangedFlag();\n    }\n}\n\nvoid UGGroup::SetMainGridIndex(int32 InIndex)\n{\n    if (MainGridIndex != InIndex)\n    {\n        MainGridIndex = InIndex;\n        SetBoundsChangedFlag();\n    }\n}\n\nvoid UGGroup::SetMainGridMinSize(int32 InSize)\n{\n    if (MainGridMinSize != InSize)\n    {\n        MainGridMinSize = InSize;\n        SetBoundsChangedFlag();\n    }\n}\n\nvoid UGGroup::SetBoundsChangedFlag(bool bPositionChangedOnly)\n{\n    if (Updating == 0 && Parent.IsValid())\n    {\n        if (!bPositionChangedOnly)\n            bPercentReady = false;\n\n        if (!bBoundsChanged)\n        {\n            bBoundsChanged = true;\n\n            if (Layout != EGroupLayoutType::None)\n            {\n                GetApp()->DelayCall(UpdateBoundsTimerHandle, this, &UGGroup::EnsureBoundsCorrect);\n            }\n        }\n    }\n}\n\nvoid UGGroup::EnsureBoundsCorrect()\n{\n    if (!Parent.IsValid() || !bBoundsChanged)\n        return;\n\n    bBoundsChanged = false;\n\n    if (bAutoSizeDisabled)\n        ResizeChildren(FVector2D::ZeroVector);\n    else\n    {\n        HandleLayout();\n        UpdateBounds();\n    }\n}\n\nvoid UGGroup::UpdateBounds()\n{\n    int32 cnt = Parent->NumChildren();\n    int32 i;\n    UGObject* child;\n    float ax = FLT_MAX, ay = FLT_MAX;\n    float ar = FLT_MIN, ab = FLT_MIN;\n    float tmp;\n    bool empty = true;\n\n    for (i = 0; i < cnt; i++)\n    {\n        child = Parent->GetChildAt(i);\n        if (child->GetGroup() != this || (bExcludeInvisibles && !child->InternalVisible3()))\n            continue;\n\n        tmp = child->GetX();\n        if (tmp < ax)\n            ax = tmp;\n        tmp = child->GetY();\n        if (tmp < ay)\n            ay = tmp;\n        tmp = child->GetX() + child->GetWidth();\n        if (tmp > ar)\n            ar = tmp;\n        tmp = child->GetY() + child->GetHeight();\n        if (tmp > ab)\n            ab = tmp;\n\n        empty = false;\n    }\n\n    float w;\n    float h;\n    if (!empty)\n    {\n        Updating |= 1;\n        SetPosition(FVector2D(ax, ay));\n        Updating &= 2;\n\n        w = ar - ax;\n        h = ab - ay;\n    }\n    else\n        w = h = 0;\n\n    if ((Updating & 2) == 0)\n    {\n        Updating |= 2;\n        SetSize(FVector2D(w, h));\n        Updating &= 1;\n    }\n    else\n    {\n        Updating &= 1;\n        ResizeChildren(FVector2D(GetWidth() - w, GetHeight() - h));\n    }\n}\n\nvoid UGGroup::HandleLayout()\n{\n    Updating |= 1;\n\n    if (Layout == EGroupLayoutType::Horizontal)\n    {\n        float curX = GetX();\n        int32 cnt = Parent->NumChildren();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* child = Parent->GetChildAt(i);\n            if (child->GetGroup() != this)\n                continue;\n            if (bExcludeInvisibles && !child->InternalVisible3())\n                continue;\n\n            child->SetXMin(curX);\n            if (child->GetWidth() != 0)\n                curX += child->GetWidth() + ColumnGap;\n        }\n    }\n    else if (Layout == EGroupLayoutType::Vertical)\n    {\n        float curY = GetY();\n        int32 cnt = Parent->NumChildren();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* child = Parent->GetChildAt(i);\n            if (child->GetGroup() != this)\n                continue;\n            if (bExcludeInvisibles && !child->InternalVisible3())\n                continue;\n\n            child->SetYMin(curY);\n            if (child->GetHeight() != 0)\n                curY += child->GetHeight() + LineGap;\n        }\n    }\n\n    Updating &= 2;\n}\n\nvoid UGGroup::MoveChildren(const FVector2D& Delta)\n{\n    if ((Updating & 1) != 0 || !Parent.IsValid())\n        return;\n\n    Updating |= 1;\n\n    int32 cnt = Parent->NumChildren();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        UGObject* child = Parent->GetChildAt(i);\n        if (child->GetGroup() == this)\n        {\n            child->SetPosition(child->GetPosition() + Delta);\n        }\n    }\n\n    Updating &= 2;\n}\n\nvoid UGGroup::ResizeChildren(const FVector2D& Delta)\n{\n    if (Layout == EGroupLayoutType::None || (Updating & 2) != 0 || !Parent.IsValid())\n        return;\n\n    Updating |= 2;\n\n    if (bBoundsChanged)\n    {\n        bBoundsChanged = false;\n        if (!bAutoSizeDisabled)\n        {\n            UpdateBounds();\n            return;\n        }\n    }\n\n    int32 cnt = Parent->NumChildren();\n\n    if (!bPercentReady)\n    {\n        bPercentReady = true;\n        NumChildren = 0;\n        TotalSize = 0;\n        MainChildIndex = -1;\n\n        int32 j = 0;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* child = Parent->GetChildAt(i);\n            if (child->GetGroup() != this)\n                continue;\n\n            if (!bExcludeInvisibles || child->InternalVisible3())\n            {\n                if (j == MainGridIndex)\n                    MainChildIndex = i;\n\n                NumChildren++;\n\n                if (Layout == EGroupLayoutType::Horizontal)\n                    TotalSize += child->GetWidth();\n                else\n                    TotalSize += child->GetHeight();\n            }\n\n            j++;\n        }\n\n        if (MainChildIndex != -1)\n        {\n            if (Layout == EGroupLayoutType::Horizontal)\n            {\n                UGObject* child = Parent->GetChildAt(MainChildIndex);\n                TotalSize += MainGridMinSize - child->GetWidth();\n                child->SizePercentInGroup = MainGridMinSize / TotalSize;\n            }\n            else\n            {\n                UGObject* child = Parent->GetChildAt(MainChildIndex);\n                TotalSize += MainGridMinSize - child->GetHeight();\n                child->SizePercentInGroup = MainGridMinSize / TotalSize;\n            }\n        }\n\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* child = Parent->GetChildAt(i);\n            if (child->GetGroup() != this)\n                continue;\n\n            if (i == MainChildIndex)\n                continue;\n\n            if (TotalSize > 0)\n                child->SizePercentInGroup = (Layout == EGroupLayoutType::Horizontal ? child->GetWidth() : child->GetHeight()) / TotalSize;\n            else\n                child->SizePercentInGroup = 0;\n        }\n    }\n\n    float remainSize = 0;\n    float remainPercent = 1;\n    bool priorHandled = false;\n\n    if (Layout == EGroupLayoutType::Horizontal)\n    {\n        remainSize = GetWidth() - (NumChildren - 1) * ColumnGap;\n        if (MainChildIndex != -1 && remainSize >= TotalSize)\n        {\n            UGObject* child = Parent->GetChildAt(MainChildIndex);\n            child->SetSize(FVector2D(remainSize - (TotalSize - MainGridMinSize), child->RawSize.Y + Delta.Y), true);\n            remainSize -= child->GetWidth();\n            remainPercent -= child->SizePercentInGroup;\n            priorHandled = true;\n        }\n\n        float curX = GetX();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* child = Parent->GetChildAt(i);\n            if (child->GetGroup() != this)\n                continue;\n\n            if (bExcludeInvisibles && !child->InternalVisible3())\n            {\n                child->SetSize(FVector2D(child->RawSize.X, child->RawSize.Y + Delta.Y), true);\n                continue;\n            }\n\n            if (!priorHandled || i != MainChildIndex)\n            {\n                child->SetSize(FVector2D(FMath::RoundToInt(child->SizePercentInGroup / remainPercent * remainSize), child->RawSize.Y + Delta.Y), true);\n                remainPercent -= child->SizePercentInGroup;\n                remainSize -= child->GetWidth();\n            }\n\n            child->SetXMin(curX);\n            if (child->GetWidth() != 0)\n                curX += child->GetWidth() + ColumnGap;\n        }\n    }\n    else\n    {\n        remainSize = GetHeight() - (NumChildren - 1) * LineGap;\n        if (MainChildIndex != -1 && remainSize >= TotalSize)\n        {\n            UGObject* child = Parent->GetChildAt(MainChildIndex);\n            child->SetSize(FVector2D(child->RawSize.X + Delta.X, remainSize - (TotalSize - MainGridMinSize)), true);\n            remainSize -= child->GetHeight();\n            remainPercent -= child->SizePercentInGroup;\n            priorHandled = true;\n        }\n\n        float curY = GetY();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* child = Parent->GetChildAt(i);\n            if (child->GetGroup() != this)\n                continue;\n\n            if (bExcludeInvisibles && !child->InternalVisible3())\n            {\n                child->SetSize(FVector2D(child->RawSize.X + Delta.X, child->RawSize.Y), true);\n                continue;\n            }\n\n            if (!priorHandled || i != MainChildIndex)\n            {\n                child->SetSize(FVector2D(child->RawSize.X + Delta.X, FMath::RoundToInt(child->SizePercentInGroup / remainPercent * remainSize)), true);\n                remainPercent -= child->SizePercentInGroup;\n                remainSize -= child->GetHeight();\n            }\n\n            child->SetYMin(curY);\n            if (child->GetHeight() != 0)\n                curY += child->GetHeight() + LineGap;\n        }\n    }\n\n    Updating &= 1;\n}\n\nvoid UGGroup::HandleAlphaChanged()\n{\n    UGObject::HandleAlphaChanged();\n\n    if (bUnderConstruct)\n        return;\n\n    int32 cnt = Parent->NumChildren();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        UGObject* child = Parent->GetChildAt(i);\n        if (child->GetGroup() == this)\n            child->SetAlpha(Alpha);\n    }\n}\n\nvoid UGGroup::HandleVisibleChanged()\n{\n    if (!Parent.IsValid())\n        return;\n\n    int32 cnt = Parent->NumChildren();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        UGObject* child = Parent->GetChildAt(i);\n        if (child->GetGroup() == this)\n            child->HandleVisibleChanged();\n    }\n}\n\nvoid UGGroup::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    Layout = (EGroupLayoutType)Buffer->ReadByte();\n    LineGap = Buffer->ReadInt();\n    ColumnGap = Buffer->ReadInt();\n    if (Buffer->Version >= 2)\n    {\n        bExcludeInvisibles = Buffer->ReadBool();\n        bAutoSizeDisabled = Buffer->ReadBool();\n        MainGridIndex = Buffer->ReadShort();\n    }\n}\n\nvoid UGGroup::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupAfterAdd(Buffer, BeginPos);\n\n    if (!bVisible)\n        HandleVisibleChanged();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GImage.cpp",
    "content": "#include \"UI/GImage.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/SFImage.h\"\n\nUGImage::UGImage()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        DisplayObject = Content = SNew(SFImage).GObject(this);\n        DisplayObject->SetInteractable(false);\n    }\n}\n\nUGImage::~UGImage()\n{\n\n}\n\nEFlipType UGImage::GetFlip() const\n{\n    return Content->Graphics.GetFlip();\n}\n\nvoid UGImage::SetFlip(EFlipType InFlip)\n{\n    Content->Graphics.SetFlip(InFlip);\n}\n\nFColor UGImage::GetColor() const\n{\n    return Content->Graphics.GetColor();\n}\n\nvoid UGImage::SetColor(const FColor& InColor)\n{\n    Content->Graphics.SetColor(InColor);\n}\n\nEFillMethod UGImage::GetFillMethod() const\n{\n    return Content->GetFillMethod();\n}\n\nvoid UGImage::SetFillMethod(EFillMethod Method)\n{\n    Content->SetFillMethod(Method);\n}\n\nint32 UGImage::GetFillOrigin() const\n{\n    return Content->GetFillOrigin();\n}\n\nvoid UGImage::SetFillOrigin(int32 Origin)\n{\n    Content->SetFillOrigin(Origin);\n}\n\nbool UGImage::IsFillClockwise() const\n{\n    return Content->IsFillClockwise();\n}\n\nvoid UGImage::SetFillClockwise(bool bClockwise)\n{\n    Content->SetFillClockwise(bClockwise);\n}\n\nfloat UGImage::GetFillAmount() const\n{\n    return Content->GetFillAmount();\n}\n\nvoid UGImage::SetFillAmount(float Amount)\n{\n    Content->SetFillAmount(Amount);\n}\n\nFNVariant UGImage::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetColor());\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGImage::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetColor(InValue.AsColor());\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGImage::ConstructFromResource()\n{\n    TSharedPtr<FPackageItem> ContentItem = PackageItem->GetBranch();\n    InitSize = SourceSize = ContentItem->Size;\n\n    ContentItem = ContentItem->GetHighResolution();\n    ContentItem->Load();\n\n    Content->SetTexture(ContentItem->Texture);\n    if (ContentItem->Scale9Grid.IsSet())\n        Content->SetScale9Grid(ContentItem->Scale9Grid);\n    else if (ContentItem->bScaleByTile)\n        Content->SetScaleByTile(true);\n\n    SetSize(SourceSize);\n}\n\nvoid UGImage::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    if (Buffer->ReadBool())\n        SetColor(Buffer->ReadColor());\n    SetFlip((EFlipType)Buffer->ReadByte());\n    int32 method = Buffer->ReadByte();\n    if (method != 0)\n    {\n        Content->SetFillMethod((EFillMethod)method);\n        Content->SetFillOrigin(Buffer->ReadByte());\n        Content->SetFillClockwise(Buffer->ReadBool());\n        Content->SetFillAmount(Buffer->ReadFloat());\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GLabel.cpp",
    "content": "#include \"UI/GLabel.h\"\n#include \"UI/GTextInput.h\"\n#include \"UI/GButton.h\"\n#include \"UI/GTextField.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGLabel::UGLabel()\n{\n}\n\nUGLabel::~UGLabel()\n{\n}\n\nconst FString& UGLabel::GetText() const\n{\n    if (TitleObject != nullptr)\n        return TitleObject->GetText();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGLabel::SetText(const FString& InText)\n{\n    if (TitleObject != nullptr)\n        TitleObject->SetText(InText);\n    UpdateGear(6);\n}\n\nconst FString& UGLabel::GetIcon() const\n{\n    if (IconObject != nullptr)\n        return IconObject->GetIcon();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGLabel::SetIcon(const FString & InIcon)\n{\n    if (IconObject != nullptr)\n        IconObject->SetIcon(InIcon);\n    UpdateGear(7);\n}\n\nFColor UGLabel::GetTitleColor() const\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n        return TextField->GetTextFormat().Color;\n    else\n        return FColor::Black;\n}\n\nvoid UGLabel::SetTitleColor(const FColor& InColor)\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n    {\n        TextField->GetTextFormat().Color = InColor;\n        TextField->ApplyFormat();\n    }\n}\n\nint32 UGLabel::GetTitleFontSize() const\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n        return TextField->GetTextFormat().Size;\n    else\n        return 0;\n}\n\nvoid UGLabel::SetTitleFontSize(int32 InFontSize)\n{\n    UGTextField* TextField = GetTextField();\n    if (TextField)\n    {\n        TextField->GetTextFormat().Size = InFontSize;\n        TextField->ApplyFormat();\n    }\n}\n\nUGTextField * UGLabel::GetTextField() const\n{\n    if (TitleObject->IsA<UGTextField>())\n        return Cast<UGTextField>(TitleObject);\n    else if (TitleObject->IsA<UGLabel>())\n        return Cast<UGLabel>(TitleObject)->GetTextField();\n    else if (TitleObject->IsA<UGButton>())\n        return Cast<UGButton>(TitleObject)->GetTextField();\n    else\n        return nullptr;\n}\n\nFNVariant UGLabel::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetTitleColor());\n    case EObjectPropID::OutlineColor:\n    {\n        UGTextField* TextField = GetTextField();\n        if (TextField != nullptr)\n            return FNVariant(TextField->GetTextFormat().OutlineColor);\n        else\n            return FNVariant(FColor::Black);\n    }\n    case EObjectPropID::FontSize:\n        return FNVariant(GetTitleFontSize());\n    default:\n        return UGComponent::GetProp(PropID);\n    }\n}\n\nvoid UGLabel::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetTitleColor(InValue.AsColor());\n        break;\n    case EObjectPropID::OutlineColor:\n    {\n        UGTextField* TextField = GetTextField();\n        if (TextField != nullptr)\n        {\n            TextField->GetTextFormat().OutlineColor = InValue.AsColor();\n            TextField->ApplyFormat();\n        }\n        break;\n    }\n    case EObjectPropID::FontSize:\n        SetTitleFontSize(InValue.AsInt());\n        break;\n    default:\n        UGComponent::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGLabel::ConstructExtension(FByteBuffer* Buffer)\n{\n    TitleObject = GetChild(\"title\");\n    IconObject = GetChild(\"icon\");\n}\n\nvoid UGLabel::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupAfterAdd(Buffer, BeginPos);\n\n    if (!Buffer->Seek(BeginPos, 6))\n        return;\n\n    if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType)\n        return;\n\n    const FString* str;\n\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetText(*str);\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetIcon(*str);\n    if (Buffer->ReadBool())\n        SetTitleColor(Buffer->ReadColor());\n    int32 iv = Buffer->ReadInt();\n    if (iv != 0)\n        SetTitleFontSize(iv);\n\n    if (Buffer->ReadBool())\n    {\n        UGTextInput* input = Cast<UGTextInput>(GetTextField());\n        if (input)\n        {\n            if ((str = Buffer->ReadSP()) != nullptr)\n                input->SetPrompt(*str);\n            if ((str = Buffer->ReadSP()) != nullptr)\n                input->SetRestrict(*str);\n            iv = Buffer->ReadInt();\n            if (iv != 0)\n                input->SetMaxLength(iv);\n            iv = Buffer->ReadInt();\n            if (iv != 0)\n                input->SetKeyboardType(iv);\n            if (Buffer->ReadBool())\n                input->SetPassword(true);\n        }\n        else\n            Buffer->Skip(13);\n    }\n}\n\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GList.cpp",
    "content": "﻿#include \"UI/GList.h\"\n#include \"UI/GButton.h\"\n#include \"UI/GObjectPool.h\"\n#include \"UI/GController.h\"\n#include \"UI/GScrollBar.h\"\n#include \"UI/UIPackage.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Widgets/SContainer.h\"\n#include \"FairyApplication.h\"\n\nUGList::FItemInfo::FItemInfo() :\n    Obj(nullptr),\n    UpdateFlag(0),\n    bSelected(false)\n{\n}\n\nUGList::UGList() :\n    bScrollItemToViewOnClick(true),\n    bAutoResizeItem(true),\n    LastSelectedIndex(-1),\n    FirstIndex(-1)\n{\n    bTrackBounds = true;\n    SetOpaque(true);\n    Pool = new FGObjectPool();\n}\n\nUGList::~UGList()\n{\n    delete Pool;\n\n    SelectionController = nullptr;\n    bScrollItemToViewOnClick = false;\n}\n\nvoid UGList::SetDefaultItem(const FString& InDefaultItem)\n{\n    DefaultItem = UUIPackage::NormalizeURL(InDefaultItem);\n}\n\nvoid UGList::SetLayout(EListLayoutType InLayout)\n{\n    if (Layout != InLayout)\n    {\n        Layout = InLayout;\n        SetBoundsChangedFlag();\n        if (bVirtual)\n            SetVirtualListChangedFlag(true);\n    }\n}\n\nvoid UGList::SetLineCount(int32 InLineCount)\n{\n    if (LineCount != InLineCount)\n    {\n        LineCount = InLineCount;\n        if (Layout == EListLayoutType::FlowVertical || Layout == EListLayoutType::Pagination)\n        {\n            SetBoundsChangedFlag();\n            if (bVirtual)\n                SetVirtualListChangedFlag(true);\n        }\n    }\n}\n\nvoid UGList::SetColumnCount(int32 InColumnCount)\n{\n    if (ColumnCount != InColumnCount)\n    {\n        ColumnCount = InColumnCount;\n        if (Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination)\n        {\n            SetBoundsChangedFlag();\n            if (bVirtual)\n                SetVirtualListChangedFlag(true);\n        }\n    }\n}\n\nvoid UGList::SetLineGap(int32 InLineGap)\n{\n    if (LineGap != InLineGap)\n    {\n        LineGap = InLineGap;\n        SetBoundsChangedFlag();\n        if (bVirtual)\n            SetVirtualListChangedFlag(true);\n    }\n}\n\nvoid UGList::SetColumnGap(int32 InColumnGap)\n{\n    if (ColumnGap != InColumnGap)\n    {\n        ColumnGap = InColumnGap;\n        SetBoundsChangedFlag();\n        if (bVirtual)\n            SetVirtualListChangedFlag(true);\n    }\n}\n\nvoid UGList::SetAlign(EAlignType InAlign)\n{\n    if (Align != InAlign)\n    {\n        Align = InAlign;\n        SetBoundsChangedFlag();\n        if (bVirtual)\n            SetVirtualListChangedFlag(true);\n    }\n}\n\nvoid UGList::SetVerticalAlign(EVerticalAlignType InVerticalAlign)\n{\n    if (VerticalAlign != InVerticalAlign)\n    {\n        VerticalAlign = InVerticalAlign;\n        SetBoundsChangedFlag();\n        if (bVirtual)\n            SetVirtualListChangedFlag(true);\n    }\n}\n\nvoid UGList::SetAutoResizeItem(bool bFlag)\n{\n    if (bAutoResizeItem != bFlag)\n    {\n        bAutoResizeItem = bFlag;\n        SetBoundsChangedFlag();\n        if (bVirtual)\n            SetVirtualListChangedFlag(true);\n    }\n}\n\nUGObject* UGList::GetFromPool()\n{\n    return GetFromPool(G_EMPTY_STRING);\n}\n\nUGObject* UGList::GetFromPool(const FString& URL)\n{\n    UGObject* ret;\n    if (URL.Len() == 0)\n        ret = Pool->GetObject(DefaultItem, this);\n    else\n        ret = Pool->GetObject(URL, this);\n    if (ret != nullptr)\n        ret->SetVisible(true);\n    return ret;\n}\n\nvoid UGList::ReturnToPool(UGObject* Obj)\n{\n    Pool->ReturnObject(Obj);\n}\n\nUGObject* UGList::AddItemFromPool(const FString& URL)\n{\n    UGObject* Obj = GetFromPool(URL);\n\n    return AddChild(Obj);\n}\n\nUGObject* UGList::AddChildAt(UGObject* Child, int32 Index)\n{\n    UGComponent::AddChildAt(Child, Index);\n    if (Child->IsA<UGButton>())\n    {\n        UGButton* Button = (UGButton*)Child;\n        Button->SetSelected(false);\n        Button->bChangeStateOnClick = false;\n    }\n\n    Child->OnClick.AddUniqueDynamic(this, &UGList::OnClickItemHandler);\n\n    return Child;\n}\n\nvoid UGList::RemoveChildAt(int32 Index)\n{\n    UGObject* Child = Children[Index];\n    Child->OnClick.RemoveDynamic(this, &UGList::OnClickItemHandler);\n\n    UGComponent::RemoveChildAt(Index);\n}\n\nvoid UGList::RemoveChildToPoolAt(int32 Index)\n{\n    ReturnToPool(GetChildAt(Index));\n    RemoveChildAt(Index);\n}\n\nvoid UGList::RemoveChildToPool(UGObject* Child)\n{\n    ReturnToPool(Child);\n    RemoveChild(Child);\n}\n\nvoid UGList::RemoveChildrenToPool(int32 BeginIndex, int32 EndIndex)\n{\n    if (EndIndex < 0 || EndIndex >= Children.Num())\n        EndIndex = Children.Num() - 1;\n\n    for (int32 i = BeginIndex; i <= EndIndex; ++i)\n        RemoveChildToPoolAt(BeginIndex);\n}\n\nint32 UGList::GetSelectedIndex() const\n{\n    if (bVirtual)\n    {\n        int32 cnt = RealNumItems;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            const FItemInfo& ii = VirtualItems[i];\n            if ((Cast<UGButton>(ii.Obj) && ((UGButton*)ii.Obj)->IsSelected()) || (ii.Obj == nullptr && ii.bSelected))\n            {\n                if (bLoop)\n                    return i % NumItems;\n                else\n                    return i;\n            }\n        }\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGButton* Obj = Cast<UGButton>(Children[i]);\n            if (Obj != nullptr && Obj->IsSelected())\n                return i;\n        }\n    }\n    return -1;\n}\n\nvoid UGList::SetSelectedIndex(int32 Index)\n{\n    if (Index >= 0 && Index < GetNumItems())\n    {\n        if (SelectionMode != EListSelectionMode::Single)\n            ClearSelection();\n        AddSelection(Index, false);\n    }\n    else\n        ClearSelection();\n}\n\nvoid UGList::SetSelectionController(UGController* InController)\n{\n    SelectionController = InController;\n}\n\nvoid UGList::GetSelection(TArray<int32>& OutIndice) const\n{\n    OutIndice.Reset();\n    if (bVirtual)\n    {\n        int32 cnt = RealNumItems;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            const FItemInfo& ii = VirtualItems[i];\n            if ((Cast<UGButton>(ii.Obj) && ((UGButton*)ii.Obj)->IsSelected()) || (ii.Obj == nullptr && ii.bSelected))\n            {\n                int32 j = i;\n                if (bLoop)\n                {\n                    j = i % NumItems;\n                    if (OutIndice.Contains(j))\n                        continue;\n                }\n                OutIndice.Add(j);\n            }\n        }\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGButton* Obj = Cast<UGButton>(Children[i]);\n            if (Obj != nullptr && Obj->IsSelected())\n                OutIndice.Add(i);\n        }\n    }\n}\n\nvoid UGList::AddSelection(int32 Index, bool bScrollItToView)\n{\n    if (SelectionMode == EListSelectionMode::None)\n        return;\n\n    CheckVirtualList();\n\n    if (SelectionMode == EListSelectionMode::Single)\n        ClearSelection();\n\n    if (bScrollItToView)\n        ScrollToView(Index);\n\n    LastSelectedIndex = Index;\n    UGButton* Obj = nullptr;\n    if (bVirtual)\n    {\n        FItemInfo& ii = VirtualItems[Index];\n        if (ii.Obj != nullptr)\n            Obj = ii.Obj->As<UGButton>();\n        ii.bSelected = true;\n    }\n    else\n        Obj = GetChildAt(Index)->As<UGButton>();\n\n    if (Obj != nullptr && !Obj->IsSelected())\n    {\n        Obj->SetSelected(true);\n        UpdateSelectionController(Index);\n    }\n}\n\nvoid UGList::RemoveSelection(int32 Index)\n{\n    if (SelectionMode == EListSelectionMode::None)\n        return;\n\n    UGButton* Obj = nullptr;\n    if (bVirtual)\n    {\n        FItemInfo& ii = VirtualItems[Index];\n        if (ii.Obj != nullptr)\n            Obj = ii.Obj->As<UGButton>();\n        ii.bSelected = false;\n    }\n    else\n        Obj = GetChildAt(Index)->As<UGButton>();\n\n    if (Obj != nullptr)\n        Obj->SetSelected(false);\n}\n\nvoid UGList::ClearSelection()\n{\n    if (bVirtual)\n    {\n        int32 cnt = RealNumItems;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FItemInfo& ii = VirtualItems[i];\n            if (Cast<UGButton>(ii.Obj))\n                ((UGButton*)ii.Obj)->SetSelected(false);\n            ii.bSelected = false;\n        }\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGButton* Obj = Children[i]->As<UGButton>();\n            if (Obj != nullptr)\n                Obj->SetSelected(false);\n        }\n    }\n}\n\nvoid UGList::ClearSelectionExcept(UGObject* Obj)\n{\n    if (bVirtual)\n    {\n        int32 cnt = RealNumItems;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FItemInfo& ii = VirtualItems[i];\n            if (ii.Obj != Obj)\n            {\n                if (Cast<UGButton>(ii.Obj))\n                    ((UGButton*)ii.Obj)->SetSelected(false);\n                ii.bSelected = false;\n            }\n        }\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGButton* Child = Children[i]->As<UGButton>();\n            if (Child != nullptr && Child != Obj)\n                Child->SetSelected(false);\n        }\n    }\n}\n\nvoid UGList::SelectAll()\n{\n    CheckVirtualList();\n\n    int32 last = -1;\n    if (bVirtual)\n    {\n        int32 cnt = RealNumItems;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FItemInfo& ii = VirtualItems[i];\n            if (Cast<UGButton>(ii.Obj) && !((UGButton*)ii.Obj)->IsSelected())\n            {\n                ((UGButton*)ii.Obj)->SetSelected(true);\n                last = i;\n            }\n            ii.bSelected = true;\n        }\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGButton* Obj = Children[i]->As<UGButton>();\n            if (Obj != nullptr && !Obj->IsSelected())\n            {\n                Obj->SetSelected(true);\n                last = i;\n            }\n        }\n    }\n\n    if (last != -1)\n        UpdateSelectionController(last);\n}\n\nvoid UGList::SelectReverse()\n{\n    CheckVirtualList();\n\n    int32 last = -1;\n    if (bVirtual)\n    {\n        int32 cnt = RealNumItems;\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FItemInfo& ii = VirtualItems[i];\n            if (Cast<UGButton>(ii.Obj))\n            {\n                ((UGButton*)ii.Obj)->SetSelected(!((UGButton*)ii.Obj)->IsSelected());\n                if (((UGButton*)ii.Obj)->IsSelected())\n                    last = i;\n            }\n            ii.bSelected = !ii.bSelected;\n        }\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGButton* Obj = Children[i]->As<UGButton>();\n            if (Obj != nullptr)\n            {\n                Obj->SetSelected(!Obj->IsSelected());\n                if (Obj->IsSelected())\n                    last = i;\n            }\n        }\n    }\n\n    if (last != -1)\n        UpdateSelectionController(last);\n}\n\nvoid UGList::HandleArrowKey(int32 Direction)\n{\n    int32 index = GetSelectedIndex();\n    if (index == -1)\n        return;\n\n    switch (Direction)\n    {\n    case 1: //up\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowVertical)\n        {\n            index--;\n            if (index >= 0)\n            {\n                ClearSelection();\n                AddSelection(index, true);\n            }\n        }\n        else if (Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination)\n        {\n            UGObject* current = Children[index];\n            int32 k = 0;\n            int32 i;\n            for (i = index - 1; i >= 0; i--)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetY() != current->GetY())\n                {\n                    current = obj;\n                    break;\n                }\n                k++;\n            }\n            for (; i >= 0; i--)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetY() != current->GetY())\n                {\n                    ClearSelection();\n                    AddSelection(i + k + 1, true);\n                    break;\n                }\n            }\n        }\n        break;\n\n    case 3: //right\n        if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination)\n        {\n            index++;\n            if (index < Children.Num())\n            {\n                ClearSelection();\n                AddSelection(index, true);\n            }\n        }\n        else if (Layout == EListLayoutType::FlowVertical)\n        {\n            UGObject* current = Children[index];\n            int32 k = 0;\n            int32 cnt = Children.Num();\n            int32 i;\n            for (i = index + 1; i < cnt; i++)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetX() != current->GetX())\n                {\n                    current = obj;\n                    break;\n                }\n                k++;\n            }\n            for (; i < cnt; i++)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetX() != current->GetX())\n                {\n                    ClearSelection();\n                    AddSelection(i - k - 1, true);\n                    break;\n                }\n            }\n        }\n        break;\n\n    case 5: //down\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowVertical)\n        {\n            index++;\n            if (index < Children.Num())\n            {\n                ClearSelection();\n                AddSelection(index, true);\n            }\n        }\n        else if (Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination)\n        {\n            UGObject* current = Children[index];\n            int32 k = 0;\n            int32 cnt = Children.Num();\n            int32 i;\n            for (i = index + 1; i < cnt; i++)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetY() != current->GetY())\n                {\n                    current = obj;\n                    break;\n                }\n                k++;\n            }\n            for (; i < cnt; i++)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetY() != current->GetY())\n                {\n                    ClearSelection();\n                    AddSelection(i - k - 1, true);\n                    break;\n                }\n            }\n        }\n        break;\n\n    case 7: //left\n        if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowHorizontal || Layout == EListLayoutType::Pagination)\n        {\n            index--;\n            if (index >= 0)\n            {\n                ClearSelection();\n                AddSelection(index, true);\n            }\n        }\n        else if (Layout == EListLayoutType::FlowVertical)\n        {\n            UGObject* current = Children[index];\n            int32 k = 0;\n            int32 i;\n            for (i = index - 1; i >= 0; i--)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetX() != current->GetX())\n                {\n                    current = obj;\n                    break;\n                }\n                k++;\n            }\n            for (; i >= 0; i--)\n            {\n                UGObject* obj = Children[i];\n                if (obj->GetX() != current->GetX())\n                {\n                    ClearSelection();\n                    AddSelection(i + k + 1, true);\n                    break;\n                }\n            }\n        }\n        break;\n    }\n}\n\nvoid UGList::OnClickItemHandler(UEventContext* Context)\n{\n    UGObject* Obj = Context->GetSender();\n    if (Obj->IsA<UGButton>() && SelectionMode != EListSelectionMode::None)\n        SetSelectionOnEvent(Obj, Context);\n\n    if (ScrollPane != nullptr && bScrollItemToViewOnClick)\n        ScrollPane->ScrollToView(Obj, true);\n\n    DispatchItemEvent(Obj, Context);\n}\n\nvoid UGList::DispatchItemEvent(UGObject* Obj, UEventContext* Context)\n{\n    DispatchEvent(FUIEvents::ClickItem, FNVariant(Obj));\n}\n\nvoid UGList::SetSelectionOnEvent(UGObject* Obj, UEventContext* Context)\n{\n    bool bDontChangeLastIndex = false;\n    UGButton* Button = Cast<UGButton>(Obj);\n    int32 Index = ChildIndexToItemIndex(GetChildIndex(Obj));\n\n    if (SelectionMode == EListSelectionMode::Single)\n    {\n        if (!Button->IsSelected())\n        {\n            ClearSelectionExcept(Button);\n            Button->SetSelected(true);\n        }\n    }\n    else\n    {\n        if (Context->GetPointerEvent().IsShiftDown())\n        {\n            if (!Button->IsSelected())\n            {\n                if (LastSelectedIndex != -1)\n                {\n                    int32 min = FMath::Min(LastSelectedIndex, Index);\n                    int32 max = FMath::Max(LastSelectedIndex, Index);\n                    max = FMath::Min(max, GetNumItems() - 1);\n                    if (bVirtual)\n                    {\n                        for (int32 i = min; i <= max; i++)\n                        {\n                            FItemInfo& ii = VirtualItems[i];\n                            if (ii.Obj != nullptr && ii.Obj->IsA<UGButton>())\n                                Cast<UGButton>(ii.Obj)->SetSelected(true);\n                            ii.bSelected = true;\n                        }\n                    }\n                    else\n                    {\n                        for (int32 i = min; i <= max; i++)\n                        {\n                            UGButton* Child = GetChildAt(i)->As<UGButton>();\n                            if (Child != nullptr && !Child->IsSelected())\n                                Child->SetSelected(true);\n                        }\n                    }\n\n                    bDontChangeLastIndex = true;\n                }\n                else\n                {\n                    Button->SetSelected(true);\n                }\n            }\n        }\n        else if (Context->GetPointerEvent().IsControlDown() || SelectionMode == EListSelectionMode::MultipleSingleclick)\n        {\n            Button->SetSelected(!Button->IsSelected());\n        }\n        else\n        {\n            if (!Button->IsSelected())\n            {\n                ClearSelectionExcept(Button);\n                Button->SetSelected(true);\n            }\n            else if (Context->GetMouseButton() == EKeys::LeftMouseButton)\n                ClearSelectionExcept(Button);\n        }\n    }\n\n    if (!bDontChangeLastIndex)\n        LastSelectedIndex = Index;\n\n    if (Button->IsSelected())\n        UpdateSelectionController(Index);\n}\n\nvoid UGList::ResizeToFit(int32 ItemCount, int32 InMinSize)\n{\n    EnsureBoundsCorrect();\n\n    int32 curCount = GetNumItems();\n    if (ItemCount > curCount)\n        ItemCount = curCount;\n\n    if (bVirtual)\n    {\n        int32 lineCount = FMath::CeilToInt((float)ItemCount / CurLineItemCount);\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n            SetViewHeight(lineCount * ItemSize.Y + FMath::Max(0, lineCount - 1) * LineGap);\n        else\n            SetViewWidth(lineCount * ItemSize.X + FMath::Max(0, lineCount - 1) * ColumnGap);\n    }\n    else if (ItemCount == 0)\n    {\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n            SetViewHeight(InMinSize);\n        else\n            SetViewWidth(InMinSize);\n    }\n    else\n    {\n        int32 i = ItemCount - 1;\n        UGObject* obj = nullptr;\n        while (i >= 0)\n        {\n            obj = GetChildAt(i);\n            if (!bFoldInvisibleItems || obj->IsVisible())\n                break;\n            i--;\n        }\n        if (i < 0)\n        {\n            if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n                SetViewHeight(InMinSize);\n            else\n                SetViewWidth(InMinSize);\n        }\n        else\n        {\n            float size;\n            if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n            {\n                size = obj->GetY() + obj->GetHeight();\n                if (size < InMinSize)\n                    size = InMinSize;\n                SetViewHeight(size);\n            }\n            else\n            {\n                size = obj->GetX() + obj->GetWidth();\n                if (size < InMinSize)\n                    size = InMinSize;\n                SetViewWidth(size);\n            }\n        }\n    }\n}\n\nint32 UGList::GetFirstChildInView() const\n{\n    return ChildIndexToItemIndex(UGComponent::GetFirstChildInView());\n}\n\nvoid UGList::HandleSizeChanged()\n{\n    UGComponent::HandleSizeChanged();\n\n    SetBoundsChangedFlag();\n    if (bVirtual)\n        SetVirtualListChangedFlag(true);\n}\n\nvoid UGList::HandleControllerChanged(UGController* Controller)\n{\n    UGComponent::HandleControllerChanged(Controller);\n\n    if (SelectionController == Controller)\n        SetSelectedIndex(Controller->GetSelectedIndex());\n}\n\nvoid UGList::UpdateSelectionController(int32 Index)\n{\n    if (SelectionController != nullptr && !SelectionController->bChanging && Index < SelectionController->GetPageCount())\n    {\n        UGController* Controller = SelectionController;\n        SelectionController = nullptr;\n        Controller->SetSelectedIndex(Index);\n        SelectionController = Controller;\n    }\n}\n\nvoid UGList::ScrollToView(int32 Index, bool bAnimation, bool bSetFirst)\n{\n    if (bVirtual)\n    {\n        if (NumItems == 0)\n            return;\n\n        CheckVirtualList();\n\n        verifyf(Index >= 0 && Index < VirtualItems.Num(), TEXT(\"Invalid child index\"));\n\n        if (bLoop)\n            Index = FMath::FloorToFloat(FirstIndex / NumItems) * NumItems + Index;\n\n        FBox2D rect;\n        FItemInfo& ii = VirtualItems[Index];\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n        {\n            float pos = 0;\n            for (int32 i = CurLineItemCount - 1; i < Index; i += CurLineItemCount)\n                pos += VirtualItems[i].Size.Y + LineGap;\n            rect.Min.Set(0, pos);\n            rect.Max = rect.Min + FVector2D(ItemSize.X, ii.Size.Y);\n        }\n        else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical)\n        {\n            float pos = 0;\n            for (int32 i = CurLineItemCount - 1; i < Index; i += CurLineItemCount)\n                pos += VirtualItems[i].Size.X + ColumnGap;\n            rect.Min.Set(pos, 0);\n            rect.Max = rect.Min + FVector2D(ii.Size.X, ItemSize.Y);\n        }\n        else\n        {\n            int32 page = Index / (CurLineItemCount * CurLineItemCount2);\n            rect.Min.Set(page * GetViewWidth() + (Index % CurLineItemCount) * (ii.Size.X + ColumnGap),\n                (Index / CurLineItemCount) % CurLineItemCount2 * (ii.Size.Y + LineGap));\n            rect.Max = rect.Min + ii.Size;\n        }\n\n        if (ScrollPane != nullptr)\n            ScrollPane->ScrollToView(rect, bAnimation, bSetFirst);\n        else if (Parent.IsValid() && Parent->GetScrollPane() != nullptr)\n        {\n            FBox2D rect2 = LocalToGlobalRect(rect);\n            rect2 = Parent->GlobalToLocalRect(rect2);\n            Parent->GetScrollPane()->ScrollToView(rect2, bAnimation, bSetFirst);\n        }\n    }\n    else\n    {\n        UGObject* obj = GetChildAt(Index);\n        if (ScrollPane != nullptr)\n            ScrollPane->ScrollToView(obj, bAnimation, bSetFirst);\n        else if (Parent.IsValid() && Parent->GetScrollPane() != nullptr)\n            Parent->GetScrollPane()->ScrollToView(obj, bAnimation, bSetFirst);\n    }\n}\n\nint32 UGList::ChildIndexToItemIndex(int32 Index) const\n{\n    if (!bVirtual)\n        return Index;\n\n    if (Layout == EListLayoutType::Pagination)\n    {\n        for (int32 i = FirstIndex; i < RealNumItems; i++)\n        {\n            if (VirtualItems[i].Obj != nullptr)\n            {\n                Index--;\n                if (Index < 0)\n                    return i;\n            }\n        }\n\n        return Index;\n    }\n    else\n    {\n        Index += FirstIndex;\n        if (bLoop && NumItems > 0)\n            Index = Index % NumItems;\n\n        return Index;\n    }\n}\n\nint32 UGList::ItemIndexToChildIndex(int32 Index) const\n{\n    if (!bVirtual)\n        return Index;\n\n    if (Layout == EListLayoutType::Pagination)\n    {\n        return GetChildIndex(VirtualItems[Index].Obj);\n    }\n    else\n    {\n        if (bLoop && NumItems > 0)\n        {\n            int32 j = FirstIndex % NumItems;\n            if (Index >= j)\n                Index = Index - j;\n            else\n                Index = NumItems - j + Index;\n        }\n        else\n            Index -= FirstIndex;\n\n        return Index;\n    }\n}\n\nvoid UGList::SetVirtual()\n{\n    SetVirtual(false);\n}\n\nvoid UGList::SetVirtualAndLoop()\n{\n    SetVirtual(true);\n}\n\nvoid UGList::SetVirtual(bool bInLoop)\n{\n    if (!bVirtual)\n    {\n        verifyf(ScrollPane != nullptr, TEXT(\"FairyGUI: Virtual list must be scrollable!\"));\n\n        if (bInLoop)\n        {\n            verifyf(Layout != EListLayoutType::FlowHorizontal && Layout != EListLayoutType::FlowVertical,\n                TEXT(\"Loop list is not supported for FlowHorizontal or FlowVertical layout!\"));\n\n            ScrollPane->bBouncebackEffect = false;\n        }\n\n        bVirtual = true;\n        bLoop = bInLoop;\n        RemoveChildrenToPool();\n\n        if (ItemSize.X == 0 || ItemSize.Y == 0)\n        {\n            UGObject* obj = GetFromPool();\n            verifyf(obj != nullptr, TEXT(\"Virtual List must have a default list item resource.\"));\n            ItemSize = obj->GetSize();\n            ItemSize.X = FMath::CeilToFloat(ItemSize.X);\n            ItemSize.Y = FMath::CeilToFloat(ItemSize.Y);\n            ReturnToPool(obj);\n        }\n\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n        {\n            ScrollPane->ScrollStep = ItemSize.Y;\n            if (bLoop)\n                ScrollPane->LoopMode = 2;\n        }\n        else\n        {\n            ScrollPane->ScrollStep = ItemSize.X;\n            if (bLoop)\n                ScrollPane->LoopMode = 1;\n        }\n\n        On(FUIEvents::Scroll).AddUObject(this, &UGList::OnScrollHandler);\n        SetVirtualListChangedFlag(true);\n    }\n}\n\nint32 UGList::GetNumItems() const\n{\n    if (bVirtual)\n        return NumItems;\n    else\n        return Children.Num();\n}\n\nvoid UGList::SetNumItems(int32 InNumItems)\n{\n    if (bVirtual)\n    {\n        verifyf(ItemRenderer.IsBound(), TEXT(\"Set itemRenderer first!\"));\n\n        NumItems = InNumItems;\n        if (bLoop)\n            RealNumItems = NumItems * 6;\n        else\n            RealNumItems = NumItems;\n\n        int32 oldCount = VirtualItems.Num();\n        if (RealNumItems > oldCount)\n        {\n            for (int32 i = oldCount; i < RealNumItems; i++)\n            {\n                FItemInfo ii;\n                ii.Size = ItemSize;\n\n                VirtualItems.Add(MoveTemp(ii));\n            }\n        }\n        else\n        {\n            for (int32 i = RealNumItems; i < oldCount; i++)\n                VirtualItems[i].bSelected = false;\n        }\n\n        if (VirtualListChanged != 0)\n            GetApp()->CancelDelayCall(RefreshTimerHandle);\n\n        DoRefreshVirtualList();\n    }\n    else\n    {\n        int32 cnt = Children.Num();\n        if (InNumItems > cnt)\n        {\n            for (int32 i = cnt; i < InNumItems; i++)\n            {\n                if (!ItemProvider.IsBound())\n                    AddItemFromPool();\n                else\n                    AddItemFromPool(ItemProvider.Execute(i));\n            }\n        }\n        else\n        {\n            RemoveChildrenToPool(InNumItems, cnt);\n        }\n\n        if (ItemRenderer.IsBound())\n        {\n            for (int32 i = 0; i < InNumItems; i++)\n                ItemRenderer.Execute(i, GetChildAt(i));\n        }\n    }\n}\n\nvoid UGList::RefreshVirtualList()\n{\n    verifyf(bVirtual, TEXT(\"not virtual list\"));\n\n    SetVirtualListChangedFlag(false);\n}\n\nFVector2D UGList::GetSnappingPosition(const FVector2D& InPoint)\n{\n    if (bVirtual)\n    {\n        FVector2D ret = InPoint;\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n        {\n            int32 index = GetIndexOnPos1(ret.Y, false);\n            if (index < VirtualItems.Num() && InPoint.Y - ret.Y > VirtualItems[index].Size.Y / 2 && index < RealNumItems)\n                ret.Y += VirtualItems[index].Size.Y + LineGap;\n        }\n        else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical)\n        {\n            int32 index = GetIndexOnPos2(ret.X, false);\n            if (index < VirtualItems.Num() && InPoint.X - ret.X > VirtualItems[index].Size.X / 2 && index < RealNumItems)\n                ret.X += VirtualItems[index].Size.X + ColumnGap;\n        }\n        else\n        {\n            int32 index = GetIndexOnPos3(ret.X, false);\n            if (index < VirtualItems.Num() && InPoint.X - ret.X > VirtualItems[index].Size.X / 2 && index < RealNumItems)\n                ret.X += VirtualItems[index].Size.X + ColumnGap;\n        }\n\n        return ret;\n    }\n    else\n        return UGComponent::GetSnappingPosition(InPoint);\n}\n\nvoid UGList::CheckVirtualList()\n{\n    if (VirtualListChanged != 0)\n    {\n        DoRefreshVirtualList();\n        GetApp()->CancelDelayCall(RefreshTimerHandle);\n    }\n}\n\nvoid UGList::SetVirtualListChangedFlag(bool bLayoutChanged)\n{\n    if (bLayoutChanged)\n        VirtualListChanged = 2;\n    else if (VirtualListChanged == 0)\n        VirtualListChanged = 1;\n\n    GetApp()->DelayCall(RefreshTimerHandle, this, &UGList::DoRefreshVirtualList);\n}\n\nvoid UGList::DoRefreshVirtualList()\n{\n    bool bLayoutChanged = VirtualListChanged == 2;\n    VirtualListChanged = 0;\n    bEventLocked = true;\n\n    if (bLayoutChanged)\n    {\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::SingleRow)\n            CurLineItemCount = 1;\n        else if (Layout == EListLayoutType::FlowHorizontal)\n        {\n            if (ColumnCount > 0)\n                CurLineItemCount = ColumnCount;\n            else\n            {\n                CurLineItemCount = FMath::FloorToInt((ScrollPane->GetViewSize().X + ColumnGap) / (ItemSize.X + ColumnGap));\n                if (CurLineItemCount <= 0)\n                    CurLineItemCount = 1;\n            }\n        }\n        else if (Layout == EListLayoutType::FlowVertical)\n        {\n            if (LineCount > 0)\n                CurLineItemCount = LineCount;\n            else\n            {\n                CurLineItemCount = FMath::FloorToInt((ScrollPane->GetViewSize().Y + LineGap) / (ItemSize.Y + LineGap));\n                if (CurLineItemCount <= 0)\n                    CurLineItemCount = 1;\n            }\n        }\n        else //Pagination\n        {\n            if (ColumnCount > 0)\n                CurLineItemCount = ColumnCount;\n            else\n            {\n                CurLineItemCount = FMath::FloorToInt((ScrollPane->GetViewSize().X + ColumnGap) / (ItemSize.X + ColumnGap));\n                if (CurLineItemCount <= 0)\n                    CurLineItemCount = 1;\n            }\n\n            if (LineCount > 0)\n                CurLineItemCount2 = LineCount;\n            else\n            {\n                CurLineItemCount2 = FMath::FloorToInt((ScrollPane->GetViewSize().Y + LineGap) / (ItemSize.Y + LineGap));\n                if (CurLineItemCount2 <= 0)\n                    CurLineItemCount2 = 1;\n            }\n        }\n    }\n    float ch = 0, cw = 0;\n    if (RealNumItems > 0)\n    {\n        int32 len = FMath::FloorToInt((float)RealNumItems / CurLineItemCount) * CurLineItemCount;\n        int32 len2 = FMath::Min(CurLineItemCount, RealNumItems);\n        if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n        {\n            for (int32 i = 0; i < len; i += CurLineItemCount)\n                ch += VirtualItems[i].Size.Y + LineGap;\n            if (ch > 0)\n                ch -= LineGap;\n\n            if (bAutoResizeItem)\n                cw = ScrollPane->GetViewSize().X;\n            else\n            {\n                for (int32 i = 0; i < len2; i++)\n                    cw += VirtualItems[i].Size.X + ColumnGap;\n                if (cw > 0)\n                    cw -= ColumnGap;\n            }\n        }\n        else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical)\n        {\n            for (int32 i = 0; i < len; i += CurLineItemCount)\n                cw += VirtualItems[i].Size.X + ColumnGap;\n            if (cw > 0)\n                cw -= ColumnGap;\n\n            if (bAutoResizeItem)\n                ch = ScrollPane->GetViewSize().Y;\n            else\n            {\n                for (int32 i = 0; i < len2; i++)\n                    ch += VirtualItems[i].Size.Y + LineGap;\n                if (ch > 0)\n                    ch -= LineGap;\n            }\n        }\n        else\n        {\n            int32 pageCount = FMath::CeilToInt((float)len / (CurLineItemCount * CurLineItemCount2));\n            cw = pageCount * GetViewWidth();\n            ch = GetViewHeight();\n        }\n    }\n\n    HandleAlign(cw, ch);\n    ScrollPane->SetContentSize(FVector2D(cw, ch));\n\n    bEventLocked = false;\n\n    HandleScroll(true);\n}\n\nvoid UGList::OnScrollHandler(UEventContext* Context)\n{\n    HandleScroll(false);\n}\n\nint32 UGList::GetIndexOnPos1(float& pos, bool forceUpdate)\n{\n    if (RealNumItems < CurLineItemCount)\n    {\n        pos = 0;\n        return 0;\n    }\n\n    if (NumChildren() > 0 && !forceUpdate)\n    {\n        float pos2 = GetChildAt(0)->GetY();\n        if (pos2 + (LineGap > 0 ? 0 : -LineGap) > pos)\n        {\n            for (int32 i = FirstIndex - CurLineItemCount; i >= 0; i -= CurLineItemCount)\n            {\n                pos2 -= (VirtualItems[i].Size.Y + LineGap);\n                if (pos2 <= pos)\n                {\n                    pos = pos2;\n                    return i;\n                }\n            }\n\n            pos = 0;\n            return 0;\n        }\n        else\n        {\n            float testGap = LineGap > 0 ? LineGap : 0;\n            for (int32 i = FirstIndex; i < RealNumItems; i += CurLineItemCount)\n            {\n                float pos3 = pos2 + VirtualItems[i].Size.Y;\n                if (pos3 + testGap > pos)\n                {\n                    pos = pos2;\n                    return i;\n                }\n                pos2 = pos3 + LineGap;\n            }\n\n            pos = pos2;\n            return RealNumItems - CurLineItemCount;\n        }\n    }\n    else\n    {\n        float pos2 = 0;\n        float testGap = LineGap > 0 ? LineGap : 0;\n        for (int32 i = 0; i < RealNumItems; i += CurLineItemCount)\n        {\n            float pos3 = pos2 + VirtualItems[i].Size.Y;\n            if (pos3 + testGap > pos)\n            {\n                pos = pos2;\n                return i;\n            }\n            pos2 = pos3 + LineGap;\n        }\n\n        pos = pos2;\n        return RealNumItems - CurLineItemCount;\n    }\n}\n\nint32 UGList::GetIndexOnPos2(float& pos, bool forceUpdate)\n{\n    if (RealNumItems < CurLineItemCount)\n    {\n        pos = 0;\n        return 0;\n    }\n\n    if (NumChildren() > 0 && !forceUpdate)\n    {\n        float pos2 = GetChildAt(0)->GetX();\n        if (pos2 + (ColumnGap > 0 ? 0 : -ColumnGap) > pos)\n        {\n            for (int32 i = FirstIndex - CurLineItemCount; i >= 0; i -= CurLineItemCount)\n            {\n                pos2 -= (VirtualItems[i].Size.X + ColumnGap);\n                if (pos2 <= pos)\n                {\n                    pos = pos2;\n                    return i;\n                }\n            }\n\n            pos = 0;\n            return 0;\n        }\n        else\n        {\n            float testGap = ColumnGap > 0 ? ColumnGap : 0;\n            for (int32 i = FirstIndex; i < RealNumItems; i += CurLineItemCount)\n            {\n                float pos3 = pos2 + VirtualItems[i].Size.X;\n                if (pos3 + testGap > pos)\n                {\n                    pos = pos2;\n                    return i;\n                }\n                pos2 = pos3 + ColumnGap;\n            }\n\n            pos = pos2;\n            return RealNumItems - CurLineItemCount;\n        }\n    }\n    else\n    {\n        float pos2 = 0;\n        float testGap = ColumnGap > 0 ? ColumnGap : 0;\n        for (int32 i = 0; i < RealNumItems; i += CurLineItemCount)\n        {\n            float pos3 = pos2 + VirtualItems[i].Size.X;\n            if (pos3 + testGap > pos)\n            {\n                pos = pos2;\n                return i;\n            }\n            pos2 = pos3 + ColumnGap;\n        }\n\n        pos = pos2;\n        return RealNumItems - CurLineItemCount;\n    }\n}\n\nint32 UGList::GetIndexOnPos3(float& pos, bool forceUpdate)\n{\n    if (RealNumItems < CurLineItemCount)\n    {\n        pos = 0;\n        return 0;\n    }\n\n    float viewWidth = GetViewWidth();\n    int32 page = FMath::FloorToInt(pos / viewWidth);\n    int32 startIndex = page * (CurLineItemCount * CurLineItemCount2);\n    float pos2 = page * viewWidth;\n    float testGap = ColumnGap > 0 ? ColumnGap : 0;\n    for (int32 i = 0; i < CurLineItemCount; i++)\n    {\n        float pos3 = pos2 + VirtualItems[startIndex + i].Size.X;\n        if (pos3 + testGap > pos)\n        {\n            pos = pos2;\n            return startIndex + i;\n        }\n        pos2 = pos3 + ColumnGap;\n    }\n\n    pos = pos2;\n    return startIndex + CurLineItemCount - 1;\n}\n\nvoid UGList::HandleScroll(bool forceUpdate)\n{\n    if (bEventLocked)\n        return;\n\n    if (Layout == EListLayoutType::SingleColumn || Layout == EListLayoutType::FlowHorizontal)\n    {\n        int32 enterCounter = 0;\n        while (HandleScroll1(forceUpdate))\n        {\n            enterCounter++;\n            forceUpdate = false;\n            if (enterCounter > 20)\n            {\n                UE_LOG(LogFairyGUI, Warning, TEXT(\"list will never be filled as the item renderer function always returns a different size.\"));\n                break;\n            }\n        }\n        HandleArchOrder1();\n    }\n    else if (Layout == EListLayoutType::SingleRow || Layout == EListLayoutType::FlowVertical)\n    {\n        int32 enterCounter = 0;\n        while (HandleScroll2(forceUpdate))\n        {\n            enterCounter++;\n            forceUpdate = false;\n            if (enterCounter > 20)\n            {\n                UE_LOG(LogFairyGUI, Warning, TEXT(\"list will never be filled as the item renderer function always returns a different size.\"));\n                break;\n            }\n        }\n        HandleArchOrder2();\n    }\n    else\n    {\n        HandleScroll3(forceUpdate);\n    }\n\n    bBoundsChanged = false;\n}\n\nbool UGList::HandleScroll1(bool forceUpdate)\n{\n    float pos = ScrollPane->GetScrollingPosY();\n    float max = pos + ScrollPane->GetViewSize().Y;\n    bool end = max == ScrollPane->GetContentSize().Y;\n\n    int32 newFirstIndex = GetIndexOnPos1(pos, forceUpdate);\n    if (newFirstIndex == FirstIndex && !forceUpdate)\n        return false;\n\n    int32 oldFirstIndex = FirstIndex;\n    FirstIndex = newFirstIndex;\n    int32 curIndex = newFirstIndex;\n    bool forward = oldFirstIndex > newFirstIndex;\n    int32 childCount = NumChildren();\n    int32 lastIndex = oldFirstIndex + childCount - 1;\n    int32 reuseIndex = forward ? lastIndex : oldFirstIndex;\n    float curX = 0, curY = pos;\n    bool needRender;\n    float deltaSize = 0;\n    float firstItemDeltaSize = 0;\n    FString url = DefaultItem;\n    int32 partSize = (int32)((ScrollPane->GetViewSize().X - ColumnGap * (CurLineItemCount - 1)) / CurLineItemCount);\n\n    ItemInfoVer++;\n    while (curIndex < RealNumItems && (end || curY < max))\n    {\n        FItemInfo& ii = VirtualItems[curIndex];\n\n        if (ii.Obj == nullptr || forceUpdate)\n        {\n            if (ItemProvider.IsBound())\n            {\n                url = ItemProvider.Execute(curIndex % NumItems);\n                if (url.Len() == 0)\n                    url = DefaultItem;\n                url = UUIPackage::NormalizeURL(url);\n            }\n\n            if (ii.Obj != nullptr && ii.Obj->GetResourceURL().Compare(url) != 0)\n            {\n                if (Cast<UGButton>(ii.Obj))\n                    ii.bSelected = ((UGButton*)ii.Obj)->IsSelected();\n                RemoveChildToPool(ii.Obj);\n                ii.Obj = nullptr;\n            }\n        }\n\n        if (ii.Obj == nullptr)\n        {\n            if (forward)\n            {\n                for (int32 j = reuseIndex; j >= oldFirstIndex; j--)\n                {\n                    FItemInfo& ii2 = VirtualItems[j];\n                    if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0)\n                    {\n                        if (Cast<UGButton>(ii2.Obj))\n                            ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected();\n                        ii.Obj = ii2.Obj;\n                        ii2.Obj = nullptr;\n                        if (j == reuseIndex)\n                            reuseIndex--;\n                        break;\n                    }\n                }\n            }\n            else\n            {\n                for (int32 j = reuseIndex; j <= lastIndex; j++)\n                {\n                    FItemInfo& ii2 = VirtualItems[j];\n                    if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0)\n                    {\n                        if (Cast<UGButton>(ii2.Obj))\n                            ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected();\n                        ii.Obj = ii2.Obj;\n                        ii2.Obj = nullptr;\n                        if (j == reuseIndex)\n                            reuseIndex++;\n                        break;\n                    }\n                }\n            }\n\n            if (ii.Obj != nullptr)\n            {\n                SetChildIndex(ii.Obj, forward ? curIndex - newFirstIndex : NumChildren());\n            }\n            else\n            {\n                ii.Obj = Pool->GetObject(url, this);\n                if (forward)\n                    AddChildAt(ii.Obj, curIndex - newFirstIndex);\n                else\n                    AddChild(ii.Obj);\n            }\n            if (Cast<UGButton>(ii.Obj))\n                ((UGButton*)ii.Obj)->SetSelected(ii.bSelected);\n\n            needRender = true;\n        }\n        else\n            needRender = forceUpdate;\n\n        if (needRender)\n        {\n            if (bAutoResizeItem && (Layout == EListLayoutType::SingleColumn || ColumnCount > 0))\n                ii.Obj->SetSize(FVector2D(partSize, ii.Obj->GetHeight()), true);\n\n            ItemRenderer.ExecuteIfBound(curIndex % NumItems, ii.Obj);\n            if (curIndex % CurLineItemCount == 0)\n            {\n                deltaSize += FMath::CeilToFloat(ii.Obj->GetHeight()) - ii.Size.Y;\n                if (curIndex == newFirstIndex && oldFirstIndex > newFirstIndex)\n                {\n                    firstItemDeltaSize = FMath::CeilToFloat(ii.Obj->GetHeight()) - ii.Size.Y;\n                }\n            }\n            ii.Size.X = FMath::CeilToFloat(ii.Obj->GetWidth());\n            ii.Size.Y = FMath::CeilToFloat(ii.Obj->GetHeight());\n        }\n\n        ii.UpdateFlag = ItemInfoVer;\n        ii.Obj->SetPosition(FVector2D(curX, curY));\n        if (curIndex == newFirstIndex)\n            max += ii.Size.Y;\n\n        curX += ii.Size.X + ColumnGap;\n\n        if (curIndex % CurLineItemCount == CurLineItemCount - 1)\n        {\n            curX = 0;\n            curY += ii.Size.Y + LineGap;\n        }\n        curIndex++;\n    }\n\n    for (int32 i = 0; i < childCount; i++)\n    {\n        FItemInfo& ii = VirtualItems[oldFirstIndex + i];\n        if (ii.UpdateFlag != ItemInfoVer && ii.Obj != nullptr)\n        {\n            if (Cast<UGButton>(ii.Obj))\n                ii.bSelected = ((UGButton*)ii.Obj)->IsSelected();\n            RemoveChildToPool(ii.Obj);\n            ii.Obj = nullptr;\n        }\n    }\n\n    childCount = Children.Num();\n    for (int32 i = 0; i < childCount; i++)\n    {\n        UGObject* obj = VirtualItems[newFirstIndex + i].Obj;\n        if (Children[i] != obj)\n            SetChildIndex(obj, i);\n    }\n\n    if (deltaSize != 0 || firstItemDeltaSize != 0)\n        ScrollPane->ChangeContentSizeOnScrolling(0, deltaSize, 0, firstItemDeltaSize);\n\n    if (curIndex > 0 && NumChildren() > 0 && Container->GetPosition().Y <= 0 && GetChildAt(0)->GetY() > -Container->GetPosition().Y)\n        return true;\n    else\n        return false;\n}\n\nbool UGList::HandleScroll2(bool forceUpdate)\n{\n    float pos = ScrollPane->GetScrollingPosX();\n    float max = pos + ScrollPane->GetViewSize().X;\n    bool end = pos == ScrollPane->GetContentSize().X;\n\n    int32 newFirstIndex = GetIndexOnPos2(pos, forceUpdate);\n    if (newFirstIndex == FirstIndex && !forceUpdate)\n        return false;\n\n    int32 oldFirstIndex = FirstIndex;\n    FirstIndex = newFirstIndex;\n    int32 curIndex = newFirstIndex;\n    bool forward = oldFirstIndex > newFirstIndex;\n    int32 childCount = NumChildren();\n    int32 lastIndex = oldFirstIndex + childCount - 1;\n    int32 reuseIndex = forward ? lastIndex : oldFirstIndex;\n    float curX = pos, curY = 0;\n    bool needRender;\n    float deltaSize = 0;\n    float firstItemDeltaSize = 0;\n    FString url = DefaultItem;\n    int32 partSize = (int32)((ScrollPane->GetViewSize().Y - LineGap * (CurLineItemCount - 1)) / CurLineItemCount);\n\n    ItemInfoVer++;\n    while (curIndex < RealNumItems && (end || curX < max))\n    {\n        FItemInfo& ii = VirtualItems[curIndex];\n\n        if (ii.Obj == nullptr || forceUpdate)\n        {\n            if (ItemProvider.IsBound())\n            {\n                url = ItemProvider.Execute(curIndex % NumItems);\n                if (url.Len() == 0)\n                    url = DefaultItem;\n                url = UUIPackage::NormalizeURL(url);\n            }\n\n            if (ii.Obj != nullptr && ii.Obj->GetResourceURL().Compare(url) != 0)\n            {\n                if (Cast<UGButton>(ii.Obj))\n                    ii.bSelected = ((UGButton*)ii.Obj)->IsSelected();\n                RemoveChildToPool(ii.Obj);\n                ii.Obj = nullptr;\n            }\n        }\n\n        if (ii.Obj == nullptr)\n        {\n            if (forward)\n            {\n                for (int32 j = reuseIndex; j >= oldFirstIndex; j--)\n                {\n                    FItemInfo& ii2 = VirtualItems[j];\n                    if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0)\n                    {\n                        if (Cast<UGButton>(ii2.Obj))\n                            ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected();\n                        ii.Obj = ii2.Obj;\n                        ii2.Obj = nullptr;\n                        if (j == reuseIndex)\n                            reuseIndex--;\n                        break;\n                    }\n                }\n            }\n            else\n            {\n                for (int32 j = reuseIndex; j <= lastIndex; j++)\n                {\n                    FItemInfo& ii2 = VirtualItems[j];\n                    if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer && ii2.Obj->GetResourceURL().Compare(url) == 0)\n                    {\n                        if (Cast<UGButton>(ii2.Obj))\n                            ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected();\n                        ii.Obj = ii2.Obj;\n                        ii2.Obj = nullptr;\n                        if (j == reuseIndex)\n                            reuseIndex++;\n                        break;\n                    }\n                }\n            }\n\n            if (ii.Obj != nullptr)\n            {\n                SetChildIndex(ii.Obj, forward ? curIndex - newFirstIndex : NumChildren());\n            }\n            else\n            {\n                ii.Obj = Pool->GetObject(url, this);\n                if (forward)\n                    AddChildAt(ii.Obj, curIndex - newFirstIndex);\n                else\n                    AddChild(ii.Obj);\n            }\n            if (Cast<UGButton>(ii.Obj))\n                ((UGButton*)ii.Obj)->SetSelected(ii.bSelected);\n\n            needRender = true;\n        }\n        else\n            needRender = forceUpdate;\n\n        if (needRender)\n        {\n            if (bAutoResizeItem && (Layout == EListLayoutType::SingleRow || LineCount > 0))\n                ii.Obj->SetSize(FVector2D(ii.Obj->GetWidth(), partSize), true);\n\n            ItemRenderer.ExecuteIfBound(curIndex % NumItems, ii.Obj);\n            if (curIndex % CurLineItemCount == 0)\n            {\n                deltaSize += FMath::CeilToFloat(ii.Obj->GetWidth()) - ii.Size.X;\n                if (curIndex == newFirstIndex && oldFirstIndex > newFirstIndex)\n                {\n                    firstItemDeltaSize = FMath::CeilToFloat(ii.Obj->GetWidth()) - ii.Size.X;\n                }\n            }\n            ii.Size.X = FMath::CeilToFloat(ii.Obj->GetWidth());\n            ii.Size.Y = FMath::CeilToFloat(ii.Obj->GetHeight());\n        }\n\n        ii.UpdateFlag = ItemInfoVer;\n        ii.Obj->SetPosition(FVector2D(curX, curY));\n        if (curIndex == newFirstIndex)\n            max += ii.Size.X;\n\n        curY += ii.Size.Y + LineGap;\n\n        if (curIndex % CurLineItemCount == CurLineItemCount - 1)\n        {\n            curY = 0;\n            curX += ii.Size.X + ColumnGap;\n        }\n        curIndex++;\n    }\n\n    for (int32 i = 0; i < childCount; i++)\n    {\n        FItemInfo& ii = VirtualItems[oldFirstIndex + i];\n        if (ii.UpdateFlag != ItemInfoVer && ii.Obj != nullptr)\n        {\n            if (Cast<UGButton>(ii.Obj))\n                ii.bSelected = ((UGButton*)ii.Obj)->IsSelected();\n            RemoveChildToPool(ii.Obj);\n            ii.Obj = nullptr;\n        }\n    }\n\n    childCount = Children.Num();\n    for (int32 i = 0; i < childCount; i++)\n    {\n        UGObject* obj = VirtualItems[newFirstIndex + i].Obj;\n        if (Children[i] != obj)\n            SetChildIndex(obj, i);\n    }\n\n    if (deltaSize != 0 || firstItemDeltaSize != 0)\n        ScrollPane->ChangeContentSizeOnScrolling(deltaSize, 0, firstItemDeltaSize, 0);\n\n    if (curIndex > 0 && NumChildren() > 0 && Container->GetPosition().X <= 0 && GetChildAt(0)->GetX() > -Container->GetPosition().X)\n        return true;\n    else\n        return false;\n}\n\nvoid UGList::HandleScroll3(bool forceUpdate)\n{\n    float pos = ScrollPane->GetScrollingPosX();\n\n    int32 newFirstIndex = GetIndexOnPos3(pos, forceUpdate);\n    if (newFirstIndex == FirstIndex && !forceUpdate)\n        return;\n\n    int32 oldFirstIndex = FirstIndex;\n    FirstIndex = newFirstIndex;\n\n    int32 reuseIndex = oldFirstIndex;\n    int32 virtualItemCount = VirtualItems.Num();\n    int32 pageSize = CurLineItemCount * CurLineItemCount2;\n    int32 startCol = newFirstIndex % CurLineItemCount;\n    float viewWidth = GetViewWidth();\n    int32 page = (int32)(newFirstIndex / pageSize);\n    int32 startIndex = page * pageSize;\n    int32 lastIndex = startIndex + pageSize * 2;\n    bool needRender;\n    FString url = DefaultItem;\n    int32 partWidth = (int32)((ScrollPane->GetViewSize().X - ColumnGap * (CurLineItemCount - 1)) / CurLineItemCount);\n    int32 partHeight = (int32)((ScrollPane->GetViewSize().Y - LineGap * (CurLineItemCount2 - 1)) / CurLineItemCount2);\n    ItemInfoVer++;\n\n    for (int32 i = startIndex; i < lastIndex; i++)\n    {\n        if (i >= RealNumItems)\n            continue;\n\n        int32 col = i % CurLineItemCount;\n        if (i - startIndex < pageSize)\n        {\n            if (col < startCol)\n                continue;\n        }\n        else\n        {\n            if (col > startCol)\n                continue;\n        }\n\n        FItemInfo& ii = VirtualItems[i];\n        ii.UpdateFlag = ItemInfoVer;\n    }\n\n    UGObject* lastObj = nullptr;\n    int32 insertIndex = 0;\n    for (int32 i = startIndex; i < lastIndex; i++)\n    {\n        if (i >= RealNumItems)\n            continue;\n\n        FItemInfo& ii = VirtualItems[i];\n        if (ii.UpdateFlag != ItemInfoVer)\n            continue;\n\n        if (ii.Obj == nullptr)\n        {\n            reuseIndex = reuseIndex < 0 ? 0 : reuseIndex;\n            while (reuseIndex < virtualItemCount)\n            {\n                FItemInfo& ii2 = VirtualItems[reuseIndex];\n                if (ii2.Obj != nullptr && ii2.UpdateFlag != ItemInfoVer)\n                {\n                    if (Cast<UGButton>(ii2.Obj))\n                        ii2.bSelected = ((UGButton*)ii2.Obj)->IsSelected();\n                    ii.Obj = ii2.Obj;\n                    ii2.Obj = nullptr;\n                    break;\n                }\n                reuseIndex++;\n            }\n\n            if (insertIndex == -1)\n                insertIndex = GetChildIndex(lastObj) + 1;\n\n            if (ii.Obj == nullptr)\n            {\n                if (ItemProvider.IsBound())\n                {\n                    url = ItemProvider.Execute(i % NumItems);\n                    if (url.Len() == 0)\n                        url = DefaultItem;\n                    url = UUIPackage::NormalizeURL(url);\n                }\n\n                ii.Obj = Pool->GetObject(url, this);\n                AddChildAt(ii.Obj, insertIndex);\n            }\n            else\n            {\n                insertIndex = SetChildIndexBefore(ii.Obj, insertIndex);\n            }\n            insertIndex++;\n\n            if (Cast<UGButton>(ii.Obj))\n                ((UGButton*)ii.Obj)->SetSelected(ii.bSelected);\n\n            needRender = true;\n        }\n        else\n        {\n            needRender = forceUpdate;\n            insertIndex = -1;\n            lastObj = ii.Obj;\n        }\n\n        if (needRender)\n        {\n            if (bAutoResizeItem)\n            {\n                if (CurLineItemCount == ColumnCount && CurLineItemCount2 == LineCount)\n                    ii.Obj->SetSize(FVector2D(partWidth, partHeight), true);\n                else if (CurLineItemCount == ColumnCount)\n                    ii.Obj->SetSize(FVector2D(partWidth, ii.Obj->GetHeight()), true);\n                else if (CurLineItemCount2 == LineCount)\n                    ii.Obj->SetSize(FVector2D(ii.Obj->GetWidth(), partHeight), true);\n            }\n\n            ItemRenderer.ExecuteIfBound(i % NumItems, ii.Obj);\n            ii.Size.X = FMath::CeilToFloat(ii.Obj->GetWidth());\n            ii.Size.Y = FMath::CeilToFloat(ii.Obj->GetHeight());\n        }\n    }\n\n    float borderX = (startIndex / pageSize) * viewWidth;\n    float xx = borderX;\n    float yy = 0;\n    float lineHeight = 0;\n    for (int32 i = startIndex; i < lastIndex; i++)\n    {\n        if (i >= RealNumItems)\n            continue;\n\n        FItemInfo& ii = VirtualItems[i];\n        if (ii.UpdateFlag == ItemInfoVer)\n            ii.Obj->SetPosition(FVector2D(xx, yy));\n\n        if (ii.Size.Y > lineHeight)\n            lineHeight = ii.Size.Y;\n        if (i % CurLineItemCount == CurLineItemCount - 1)\n        {\n            xx = borderX;\n            yy += lineHeight + LineGap;\n            lineHeight = 0;\n\n            if (i == startIndex + pageSize - 1)\n            {\n                borderX += viewWidth;\n                xx = borderX;\n                yy = 0;\n            }\n        }\n        else\n            xx += ii.Size.X + ColumnGap;\n    }\n\n    for (int32 i = reuseIndex; i < virtualItemCount; i++)\n    {\n        FItemInfo& ii = VirtualItems[i];\n        if (ii.UpdateFlag != ItemInfoVer && ii.Obj != nullptr)\n        {\n            if (Cast<UGButton>(ii.Obj))\n                ii.bSelected = ((UGButton*)ii.Obj)->IsSelected();\n            RemoveChildToPool(ii.Obj);\n            ii.Obj = nullptr;\n        }\n    }\n}\n\nvoid UGList::HandleArchOrder1()\n{\n    if (ChildrenRenderOrder == EChildrenRenderOrder::Arch)\n    {\n        float mid = ScrollPane->GetPosY() + GetViewHeight() / 2;\n        float minDist = FLT_MAX, dist;\n        int32 apexIndex = 0;\n        int32 cnt = NumChildren();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* obj = GetChildAt(i);\n            if (!bFoldInvisibleItems || obj->IsVisible())\n            {\n                dist = FMath::Abs(mid - obj->GetY() - obj->GetHeight() / 2);\n                if (dist < minDist)\n                {\n                    minDist = dist;\n                    apexIndex = i;\n                }\n            }\n        }\n        SetApexIndex(apexIndex);\n    }\n}\n\nvoid UGList::HandleArchOrder2()\n{\n    if (ChildrenRenderOrder == EChildrenRenderOrder::Arch)\n    {\n        float mid = ScrollPane->GetPosX() + GetViewWidth() / 2;\n        float minDist = FLT_MAX, dist;\n        int32 apexIndex = 0;\n        int32 cnt = NumChildren();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* obj = GetChildAt(i);\n            if (!bFoldInvisibleItems || obj->IsVisible())\n            {\n                dist = FMath::Abs(mid - obj->GetX() - obj->GetWidth() / 2);\n                if (dist < minDist)\n                {\n                    minDist = dist;\n                    apexIndex = i;\n                }\n            }\n        }\n        SetApexIndex(apexIndex);\n    }\n}\n\nvoid UGList::HandleAlign(float contentWidth, float contentHeight)\n{\n    FVector2D newOffset(0, 0);\n\n    float viewHeight = GetViewHeight();\n    float viewWidth = GetViewWidth();\n    if (contentHeight < viewHeight)\n    {\n        if (VerticalAlign == EVerticalAlignType::Middle)\n            newOffset.Y = (int32)((viewHeight - contentHeight) / 2);\n        else if (VerticalAlign == EVerticalAlignType::Bottom)\n            newOffset.Y = viewHeight - contentHeight;\n    }\n\n    if (contentWidth < viewWidth)\n    {\n        if (Align == EAlignType::Center)\n            newOffset.X = (int32)((viewWidth - contentWidth) / 2);\n        else if (Align == EAlignType::Right)\n            newOffset.X = viewWidth - contentWidth;\n    }\n\n    if (newOffset != AlignOffset)\n    {\n        AlignOffset = newOffset;\n        if (ScrollPane != nullptr)\n            ScrollPane->AdjustMaskContainer();\n        else\n            Container->SetPosition(FVector2D(Margin.Left + AlignOffset.X, Margin.Top + AlignOffset.Y));\n    }\n}\n\nvoid UGList::UpdateBounds()\n{\n    if (bVirtual)\n        return;\n\n    int32 cnt = Children.Num();\n    int32 i;\n    int32 j = 0;\n    UGObject* child;\n    float curX = 0;\n    float curY = 0;\n    float cw, ch;\n    float maxWidth = 0;\n    float maxHeight = 0;\n    float viewWidth = GetViewWidth();\n    float viewHeight = GetViewHeight();\n\n    if (Layout == EListLayoutType::SingleColumn)\n    {\n        for (i = 0; i < cnt; i++)\n        {\n            child = GetChildAt(i);\n            if (bFoldInvisibleItems && !child->IsVisible())\n                continue;\n\n            if (curY != 0)\n                curY += LineGap;\n            child->SetY(curY);\n            if (bAutoResizeItem)\n                child->SetSize(FVector2D(viewWidth, child->GetHeight()), true);\n            curY += FMath::CeilToFloat(child->GetHeight());\n            if (child->GetWidth() > maxWidth)\n                maxWidth = child->GetWidth();\n        }\n        ch = curY;\n        if (ch <= viewHeight && bAutoResizeItem && ScrollPane != nullptr && ScrollPane->bDisplayInDemand && ScrollPane->VtScrollBar != nullptr)\n        {\n            viewWidth += ScrollPane->VtScrollBar->GetWidth();\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                child->SetSize(FVector2D(viewWidth, child->GetHeight()), true);\n                if (child->GetWidth() > maxWidth)\n                    maxWidth = child->GetWidth();\n            }\n        }\n        cw = FMath::CeilToFloat(maxWidth);\n    }\n    else if (Layout == EListLayoutType::SingleRow)\n    {\n        for (i = 0; i < cnt; i++)\n        {\n            child = GetChildAt(i);\n            if (bFoldInvisibleItems && !child->IsVisible())\n                continue;\n\n            if (curX != 0)\n                curX += ColumnGap;\n            child->SetX(curX);\n            if (bAutoResizeItem)\n                child->SetSize(FVector2D(child->GetWidth(), viewHeight), true);\n            curX += FMath::CeilToFloat(child->GetWidth());\n            if (child->GetHeight() > maxHeight)\n                maxHeight = child->GetHeight();\n        }\n        cw = curX;\n        if (cw <= viewWidth && bAutoResizeItem && ScrollPane != nullptr && ScrollPane->bDisplayInDemand && ScrollPane->HzScrollBar != nullptr)\n        {\n            viewHeight += ScrollPane->HzScrollBar->GetHeight();\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                child->SetSize(FVector2D(child->GetWidth(), viewHeight), true);\n                if (child->GetHeight() > maxHeight)\n                    maxHeight = child->GetHeight();\n            }\n        }\n        ch = FMath::CeilToFloat(maxHeight);\n    }\n    else if (Layout == EListLayoutType::FlowHorizontal)\n    {\n        if (bAutoResizeItem && ColumnCount > 0)\n        {\n            float lineSize = 0;\n            int32 lineStart = 0;\n            float ratio;\n\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                lineSize += child->SourceSize.X;\n                j++;\n                if (j == ColumnCount || i == cnt - 1)\n                {\n                    ratio = (viewWidth - lineSize - (j - 1) * ColumnGap) / lineSize;\n                    curX = 0;\n                    for (j = lineStart; j <= i; j++)\n                    {\n                        child = GetChildAt(j);\n                        if (bFoldInvisibleItems && !child->IsVisible())\n                            continue;\n\n                        child->SetPosition(FVector2D(curX, curY));\n\n                        if (j < i)\n                        {\n                            child->SetSize(FVector2D(child->SourceSize.X + round(child->SourceSize.X * ratio), child->GetHeight()), true);\n                            curX += FMath::CeilToFloat(child->GetWidth()) + ColumnGap;\n                        }\n                        else\n                        {\n                            child->SetSize(FVector2D(viewWidth - curX, child->GetHeight()), true);\n                        }\n                        if (child->GetHeight() > maxHeight)\n                            maxHeight = child->GetHeight();\n                    }\n                    curY += FMath::CeilToFloat(maxHeight) + LineGap;\n                    maxHeight = 0;\n                    j = 0;\n                    lineStart = i + 1;\n                    lineSize = 0;\n                }\n            }\n            ch = curY + FMath::CeilToFloat(maxHeight);\n            cw = viewWidth;\n        }\n        else\n        {\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                if (curX != 0)\n                    curX += ColumnGap;\n\n                if ((ColumnCount != 0 && j >= ColumnCount) || (ColumnCount == 0 && curX + child->GetWidth() > viewWidth && maxHeight != 0))\n                {\n                    curX = 0;\n                    curY += FMath::CeilToFloat(maxHeight) + LineGap;\n                    maxHeight = 0;\n                    j = 0;\n                }\n                child->SetPosition(FVector2D(curX, curY));\n                curX += FMath::CeilToFloat(child->GetWidth());\n                if (curX > maxWidth)\n                    maxWidth = curX;\n                if (child->GetHeight() > maxHeight)\n                    maxHeight = child->GetHeight();\n                j++;\n            }\n            ch = curY + FMath::CeilToFloat(maxHeight);\n            cw = FMath::CeilToFloat(maxWidth);\n        }\n    }\n    else if (Layout == EListLayoutType::FlowVertical)\n    {\n        if (bAutoResizeItem && LineCount > 0)\n        {\n            float lineSize = 0;\n            int32 lineStart = 0;\n            float ratio;\n\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                lineSize += child->SourceSize.Y;\n                j++;\n                if (j == LineCount || i == cnt - 1)\n                {\n                    ratio = (viewHeight - lineSize - (j - 1) * LineGap) / lineSize;\n                    curY = 0;\n                    for (j = lineStart; j <= i; j++)\n                    {\n                        child = GetChildAt(j);\n                        if (bFoldInvisibleItems && !child->IsVisible())\n                            continue;\n\n                        child->SetPosition(FVector2D(curX, curY));\n\n                        if (j < i)\n                        {\n                            child->SetSize(FVector2D(child->GetWidth(), child->SourceSize.Y + FMath::RoundToFloat(child->SourceSize.Y * ratio)), true);\n                            curY += FMath::CeilToFloat(child->GetHeight()) + LineGap;\n                        }\n                        else\n                        {\n                            child->SetSize(FVector2D(child->GetWidth(), viewHeight - curY), true);\n                        }\n                        if (child->GetWidth() > maxWidth)\n                            maxWidth = child->GetWidth();\n                    }\n                    curX += FMath::CeilToFloat(maxWidth) + ColumnGap;\n                    maxWidth = 0;\n                    j = 0;\n                    lineStart = i + 1;\n                    lineSize = 0;\n                }\n            }\n            cw = curX + FMath::CeilToFloat(maxWidth);\n            ch = viewHeight;\n        }\n        else\n        {\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                if (curY != 0)\n                    curY += LineGap;\n\n                if ((LineCount != 0 && j >= LineCount) || (LineCount == 0 && curY + child->GetHeight() > viewHeight && maxWidth != 0))\n                {\n                    curY = 0;\n                    curX += FMath::CeilToFloat(maxWidth) + ColumnGap;\n                    maxWidth = 0;\n                    j = 0;\n                }\n                child->SetPosition(FVector2D(curX, curY));\n                curY += child->GetHeight();\n                if (curY > maxHeight)\n                    maxHeight = curY;\n                if (child->GetWidth() > maxWidth)\n                    maxWidth = child->GetWidth();\n                j++;\n            }\n            cw = curX + FMath::CeilToFloat(maxWidth);\n            ch = FMath::CeilToFloat(maxHeight);\n        }\n    }\n    else //Pagination\n    {\n        int32 page = 0;\n        int32 k = 0;\n        float eachHeight = 0;\n        if (bAutoResizeItem && LineCount > 0)\n            eachHeight = FMath::FloorToFloat((viewHeight - (LineCount - 1) * LineGap) / LineCount);\n\n        if (bAutoResizeItem && ColumnCount > 0)\n        {\n            float lineSize = 0;\n            int32 lineStart = 0;\n            float ratio;\n\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                if (j == 0 && ((LineCount != 0 && k >= LineCount) || (LineCount == 0 && curY + (LineCount > 0 ? eachHeight : child->GetHeight()) > viewHeight)))\n                {\n                    page++;\n                    curY = 0;\n                    k = 0;\n                }\n\n                lineSize += child->SourceSize.X;\n                j++;\n                if (j == ColumnCount || i == cnt - 1)\n                {\n                    ratio = (viewWidth - lineSize - (j - 1) * ColumnGap) / lineSize;\n                    curX = 0;\n                    for (j = lineStart; j <= i; j++)\n                    {\n                        child = GetChildAt(j);\n                        if (bFoldInvisibleItems && !child->IsVisible())\n                            continue;\n\n                        child->SetPosition(FVector2D(page * viewWidth + curX, curY));\n\n                        if (j < i)\n                        {\n                            child->SetSize(FVector2D(child->SourceSize.X + FMath::RoundToFloat(child->SourceSize.X * ratio),\n                                LineCount > 0 ? eachHeight : child->GetHeight()), true);\n                            curX += FMath::CeilToFloat(child->GetWidth()) + ColumnGap;\n                        }\n                        else\n                        {\n                            child->SetSize(FVector2D(viewWidth - curX, LineCount > 0 ? eachHeight : child->GetHeight()), true);\n                        }\n                        if (child->GetHeight() > maxHeight)\n                            maxHeight = child->GetHeight();\n                    }\n                    curY += FMath::CeilToFloat(maxHeight) + LineGap;\n                    maxHeight = 0;\n                    j = 0;\n                    lineStart = i + 1;\n                    lineSize = 0;\n\n                    k++;\n                }\n            }\n        }\n        else\n        {\n            for (i = 0; i < cnt; i++)\n            {\n                child = GetChildAt(i);\n                if (bFoldInvisibleItems && !child->IsVisible())\n                    continue;\n\n                if (curX != 0)\n                    curX += ColumnGap;\n\n                if (bAutoResizeItem && LineCount > 0)\n                    child->SetSize(FVector2D(child->GetWidth(), eachHeight), true);\n\n                if ((ColumnCount != 0 && j >= ColumnCount) || (ColumnCount == 0 && curX + child->GetWidth() > viewWidth && maxHeight != 0))\n                {\n                    curX = 0;\n                    curY += maxHeight + LineGap;\n                    maxHeight = 0;\n                    j = 0;\n                    k++;\n\n                    if ((LineCount != 0 && k >= LineCount) || (LineCount == 0 && curY + child->GetHeight() > viewHeight && maxWidth != 0)) //new page\n                    {\n                        page++;\n                        curY = 0;\n                        k = 0;\n                    }\n                }\n                child->SetPosition(FVector2D(page * viewWidth + curX, curY));\n                curX += FMath::CeilToFloat(child->GetWidth());\n                if (curX > maxWidth)\n                    maxWidth = curX;\n                if (child->GetHeight() > maxHeight)\n                    maxHeight = child->GetHeight();\n                j++;\n            }\n        }\n        ch = page > 0 ? viewHeight : (curY + FMath::CeilToFloat(maxHeight));\n        cw = (page + 1) * viewWidth;\n    }\n\n    HandleAlign(cw, ch);\n    SetBounds(0, 0, cw, ch);\n}\n\nvoid UGList::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    Layout = (EListLayoutType)Buffer->ReadByte();\n    SelectionMode = (EListSelectionMode)Buffer->ReadByte();\n    Align = (EAlignType)Buffer->ReadByte();\n    VerticalAlign = (EVerticalAlignType)Buffer->ReadByte();\n    LineGap = Buffer->ReadShort();\n    ColumnGap = Buffer->ReadShort();\n    LineCount = Buffer->ReadShort();\n    ColumnCount = Buffer->ReadShort();\n    bAutoResizeItem = Buffer->ReadBool();\n    ChildrenRenderOrder = (EChildrenRenderOrder)Buffer->ReadByte();\n    ApexIndex = Buffer->ReadShort();\n\n    if (Buffer->ReadBool())\n    {\n        Margin.Top = Buffer->ReadInt();\n        Margin.Bottom = Buffer->ReadInt();\n        Margin.Left = Buffer->ReadInt();\n        Margin.Right = Buffer->ReadInt();\n    }\n\n    EOverflowType overflow = (EOverflowType)Buffer->ReadByte();\n    if (overflow == EOverflowType::Scroll)\n    {\n        int32 savedPos = Buffer->GetPos();\n        Buffer->Seek(BeginPos, 7);\n        SetupScroll(Buffer);\n        Buffer->SetPos(savedPos);\n    }\n    else\n        SetupOverflow(overflow);\n\n    if (Buffer->ReadBool()) //clipSoftness\n        Buffer->Skip(8);\n\n    if (Buffer->Version >= 2)\n    {\n        bScrollItemToViewOnClick = Buffer->ReadBool();\n        bFoldInvisibleItems = Buffer->ReadBool();\n    }\n\n    Buffer->Seek(BeginPos, 8);\n\n    DefaultItem = Buffer->ReadS();\n    ReadItems(Buffer);\n}\n\nvoid UGList::ReadItems(FByteBuffer* Buffer)\n{\n    const FString* str;\n\n    int32 itemCount = Buffer->ReadShort();\n    for (int32 i = 0; i < itemCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        str = Buffer->ReadSP();\n        if (!str || (*str).IsEmpty())\n        {\n            str = &DefaultItem;\n            if ((*str).IsEmpty())\n            {\n                Buffer->SetPos(nextPos);\n                continue;\n            }\n        }\n\n        UGObject* obj = GetFromPool(*str);\n        if (obj != nullptr)\n        {\n            AddChild(obj);\n            SetupItem(Buffer, obj);\n        }\n\n        Buffer->SetPos(nextPos);\n    }\n}\n\nvoid UGList::SetupItem(FByteBuffer* Buffer, UGObject* Obj)\n{\n    const FString* str;\n    UGButton* btn = Cast<UGButton>(Obj);\n\n    if ((str = Buffer->ReadSP()) != nullptr)\n        Obj->SetText(*str);\n    if ((str = Buffer->ReadSP()) != nullptr && btn)\n        btn->SetSelectedTitle(*str);\n    if ((str = Buffer->ReadSP()) != nullptr)\n        Obj->SetIcon(*str);\n    if ((str = Buffer->ReadSP()) != nullptr && btn)\n        btn->SetSelectedIcon(*str);\n    if ((str = Buffer->ReadSP()) != nullptr)\n        Obj->Name = *str;\n\n    UGComponent* gcom = Cast<UGComponent>(Obj);\n    if (gcom != nullptr)\n    {\n        int32 cnt = Buffer->ReadShort();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGController* cc = gcom->GetController(Buffer->ReadS());\n            const FString& PageID = Buffer->ReadS();\n            cc->SetSelectedPageID(PageID);\n        }\n\n        if (Buffer->Version >= 2)\n        {\n            cnt = Buffer->ReadShort();\n            for (int32 i = 0; i < cnt; i++)\n            {\n                const FString& target = Buffer->ReadS();\n                EObjectPropID PropID = (EObjectPropID)Buffer->ReadShort();\n                FString value = Buffer->ReadS();\n                UGObject* obj2 = gcom->GetChildByPath(target);\n                if (obj2 != nullptr)\n                    obj2->SetProp(PropID, FNVariant(value));\n            }\n        }\n    }\n}\n\nvoid UGList::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupAfterAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 6);\n\n    int32 i = Buffer->ReadShort();\n    if (i != -1)\n        SelectionController = Parent->GetControllerAt(i);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GLoader.cpp",
    "content": "#include \"UI/GLoader.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GComponent.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/SMovieClip.h\"\n#include \"Widgets/SContainer.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Engine/AssetManager.h\"\n\nUGLoader::UGLoader()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        DisplayObject = Container = SNew(SContainer).GObject(this);\n        Content = SNew(SMovieClip);\n        Content->SetInteractable(false);\n        Container->AddChild(Content.ToSharedRef());\n    }\n}\n\nUGLoader::~UGLoader()\n{\n\n}\n\nvoid UGLoader::SetURL(const FString& InURL)\n{\n    if (URL.Compare(InURL, ESearchCase::CaseSensitive) == 0)\n        return;\n\n    ClearContent();\n    URL = InURL;\n    LoadContent();\n    UpdateGear(7);\n}\n\nvoid UGLoader::SetAlign(EAlignType InAlign)\n{\n    if (Align != InAlign)\n    {\n        Align = InAlign;\n        UpdateLayout();\n    }\n}\n\nvoid UGLoader::SetVerticalAlign(EVerticalAlignType InVerticalAlign)\n{\n    if (VerticalAlign != InVerticalAlign)\n    {\n        VerticalAlign = InVerticalAlign;\n        UpdateLayout();\n    }\n}\n\nvoid UGLoader::SetAutoSize(bool bInAutoSize)\n{\n    if (bAutoSize != bInAutoSize)\n    {\n        bAutoSize = bInAutoSize;\n        UpdateLayout();\n    }\n}\n\nvoid UGLoader::SetFill(ELoaderFillType InFillType)\n{\n    if (Fill != InFillType)\n    {\n        Fill = InFillType;\n        UpdateLayout();\n    }\n}\n\nvoid UGLoader::SetShrinkOnly(bool bInShrinkOnly)\n{\n    if (bShrinkOnly != bInShrinkOnly)\n    {\n        bShrinkOnly = bInShrinkOnly;\n        UpdateLayout();\n    }\n}\n\nEFlipType UGLoader::GetFlip() const\n{\n    return Content->Graphics.GetFlip();\n}\n\nvoid UGLoader::SetFlip(EFlipType InFlip)\n{\n    Content->Graphics.SetFlip(InFlip);\n}\n\nFColor UGLoader::GetColor() const\n{\n    return Content->Graphics.GetColor();\n}\n\nvoid UGLoader::SetColor(const FColor& InColor)\n{\n    Content->Graphics.SetColor(InColor);\n}\n\nEFillMethod UGLoader::GetFillMethod() const\n{\n    return Content->GetFillMethod();\n}\n\nvoid UGLoader::SetFillMethod(EFillMethod Method)\n{\n    Content->SetFillMethod(Method);\n}\n\nint32 UGLoader::GetFillOrigin() const\n{\n    return Content->GetFillOrigin();\n}\n\nvoid UGLoader::SetFillOrigin(int32 Origin)\n{\n    Content->SetFillOrigin(Origin);\n}\n\nbool UGLoader::IsFillClockwise() const\n{\n    return Content->IsFillClockwise();\n}\n\nvoid UGLoader::SetFillClockwise(bool bClockwise)\n{\n    Content->SetFillClockwise(bClockwise);\n}\n\nfloat UGLoader::GetFillAmount() const\n{\n    return Content->GetFillAmount();\n}\n\nvoid UGLoader::SetFillAmount(float Amount)\n{\n    Content->SetFillAmount(Amount);\n}\n\nbool UGLoader::IsPlaying() const\n{\n    return Content->IsPlaying();\n}\n\nvoid UGLoader::SetPlaying(bool bInPlaying)\n{\n    if (Content->IsPlaying() != bInPlaying)\n    {\n        Content->SetPlaying(bInPlaying);\n        UpdateGear(5);\n    }\n}\n\nint UGLoader::GetFrame() const\n{\n    return Content->GetFrame();\n}\n\nvoid UGLoader::SetFrame(int32 InFrame)\n{\n    if (Content->GetFrame() != InFrame)\n    {\n        Content->SetFrame(InFrame);\n        UpdateGear(5);\n    }\n}\n\nvoid UGLoader::LoadContent()\n{\n    ClearContent();\n\n    if (URL.IsEmpty())\n        return;\n\n    if (URL.StartsWith(\"ui://\"))\n        LoadFromPackage(URL);\n    else\n        LoadExternal();\n}\n\nvoid UGLoader::ClearContent()\n{\n    ContentItem.Reset();\n    Content->SetTexture(nullptr);\n    Content->SetClipData(nullptr);\n    if (Content2 != nullptr)\n    {\n        Container->RemoveChild(Content2->GetDisplayObject());\n        Content2 = nullptr;\n    }\n}\n\nvoid UGLoader::LoadFromPackage(const FString& ItemURL)\n{\n    ContentItem = UUIPackage::GetItemByURL(ItemURL);\n    if (ContentItem.IsValid())\n    {\n        ContentItem = ContentItem->GetBranch();\n        SourceSize = ContentItem->Size;\n        ContentItem = ContentItem->GetHighResolution();\n        ContentItem->Load();\n\n        if (ContentItem->Type == EPackageItemType::Image)\n        {\n            Content->SetTexture(ContentItem->Texture);\n            if (ContentItem->Scale9Grid.IsSet())\n                Content->SetScale9Grid(ContentItem->Scale9Grid);\n            else if (ContentItem->bScaleByTile)\n                Content->SetScaleByTile(true);\n\n            UpdateLayout();\n        }\n        else if (ContentItem->Type == EPackageItemType::MovieClip)\n        {\n            Content->SetClipData(ContentItem->MovieClipData);\n            UpdateLayout();\n        }\n        else if (ContentItem->Type == EPackageItemType::Component)\n        {\n            UGObject* obj = UUIPackage::CreateObjectFromURL(ItemURL, this);\n            if (obj == nullptr || !obj->IsA<UGComponent>())\n                SetErrorState();\n            else\n            {\n                Content2 = Cast<UGComponent>(obj);\n                Container->AddChild(Content2->GetDisplayObject());\n                UpdateLayout();\n            }\n        }\n        else\n        {\n            if (bAutoSize)\n                SetSize(ContentItem->Size);\n\n            SetErrorState();\n\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"Unsupported type of GLoader: %d\"), ContentItem->Type);\n        }\n    }\n    else\n        SetErrorState();\n}\n\nvoid UGLoader::LoadExternal()\n{\n    SoftObjectPath = MakeShareable(new FSoftObjectPath(URL));\n\n    UAssetManager::GetStreamableManager().RequestAsyncLoad(*SoftObjectPath, FStreamableDelegate::CreateUObject(this, &UGLoader::OnExternalLoaded, URL));\n}\n\nvoid UGLoader::OnExternalLoaded(FString LoadingURL)\n{\n    if (!SoftObjectPath.IsValid() || LoadingURL != URL)\n        return;\n\n    TSoftObjectPtr<UTexture2D> NativeTexture(*SoftObjectPath);\n    UNTexture* NTexture = NewObject<UNTexture>(this);\n    NTexture->Init(NativeTexture.Get());\n    Content->SetTexture(NTexture);\n    Content->SetNativeSize();\n    SourceSize = NTexture->GetSize();\n    UpdateLayout();\n\n    SoftObjectPath.Reset();\n}\n\nvoid UGLoader::UpdateLayout()\n{\n    if (Content2 == nullptr && Content->GetTexture() == nullptr && !Content->GetClipData().IsValid())\n    {\n        if (bAutoSize)\n        {\n            bUpdatingLayout = true;\n            SetSize(FVector2D(50, 30));\n            bUpdatingLayout = false;\n        }\n        return;\n    }\n\n    FVector2D contentSize = SourceSize;\n\n    if (bAutoSize)\n    {\n        bUpdatingLayout = true;\n        if (contentSize.X == 0)\n            contentSize.X = 50;\n        if (contentSize.Y == 0)\n            contentSize.Y = 30;\n        SetSize(contentSize);\n\n        bUpdatingLayout = false;\n\n        if (Size == contentSize)\n        {\n            if (Content2 != nullptr)\n            {\n                Content2->SetPosition(FVector2D(0, 0));\n                Content2->SetScale(FVector2D(1, 1));\n            }\n            else\n            {\n                Content->SetPosition(FVector2D(0, 0));\n                Content->SetSize(contentSize);\n            }\n\n            return;\n        }\n    }\n\n    FVector2D ContentScale(1, 1);\n    if (Fill != ELoaderFillType::None)\n    {\n        ContentScale = Size / SourceSize;\n\n        if (ContentScale != FVector2D(1, 1))\n        {\n            if (Fill == ELoaderFillType::ScaleMatchHeight)\n                ContentScale.X = ContentScale.Y;\n            else if (Fill == ELoaderFillType::ScaleMatchWidth)\n                ContentScale.Y = ContentScale.X;\n            else if (Fill == ELoaderFillType::Scale)\n            {\n                if (ContentScale.X > ContentScale.Y)\n                    ContentScale.X = ContentScale.Y;\n                else\n                    ContentScale.Y = ContentScale.X;\n            }\n            else if (Fill == ELoaderFillType::ScaleNoBorder)\n            {\n                if (ContentScale.X > ContentScale.Y)\n                    ContentScale.Y = ContentScale.X;\n                else\n                    ContentScale.X = ContentScale.Y;\n            }\n\n            if (bShrinkOnly)\n            {\n                if (ContentScale.X > 1)\n                    ContentScale.X = 1;\n                if (ContentScale.Y > 1)\n                    ContentScale.Y = 1;\n            }\n\n            contentSize = SourceSize * ContentScale;\n        }\n    }\n\n    if (Content2 != nullptr)\n        Content2->SetScale(ContentScale);\n    else\n        Content->SetSize(contentSize);\n\n    FVector2D ContentPosition;\n    if (Align == EAlignType::Center)\n        ContentPosition.X = (Size.X - contentSize.X) / 2;\n    else if (Align == EAlignType::Right)\n        ContentPosition.X = Size.X - contentSize.X;\n    else\n        ContentPosition.X = 0;\n\n    if (VerticalAlign == EVerticalAlignType::Middle)\n        ContentPosition.Y = (Size.Y - contentSize.Y) / 2;\n    else if (VerticalAlign == EVerticalAlignType::Bottom)\n        ContentPosition.Y = Size.Y - contentSize.Y;\n    else\n        ContentPosition.Y = 0;\n\n    if (Content2 != nullptr)\n        Content2->SetPosition(ContentPosition);\n    else\n        Content->SetPosition(ContentPosition);\n}\n\nvoid UGLoader::SetErrorState()\n{\n\n}\n\nFNVariant UGLoader::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetColor());\n    case EObjectPropID::Playing:\n        return FNVariant(Content->IsPlaying());\n    case EObjectPropID::Frame:\n        return FNVariant(Content->GetFrame());\n    case EObjectPropID::TimeScale:\n        return FNVariant(Content->GetTimeScale());\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGLoader::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetColor(InValue.AsColor());\n        break;\n    case EObjectPropID::Playing:\n        Content->SetPlaying(InValue.AsBool());\n        break;\n    case EObjectPropID::Frame:\n        Content->SetFrame(InValue.AsInt());\n        break;\n    case EObjectPropID::TimeScale:\n        Content->SetTimeScale(InValue.AsFloat());\n        break;\n    case EObjectPropID::DeltaTime:\n        Content->Advance(InValue.AsFloat());\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGLoader::HandleSizeChanged()\n{\n    UGObject::HandleSizeChanged();\n\n    if (!bUpdatingLayout)\n        UpdateLayout();\n}\n\nvoid UGLoader::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    URL = Buffer->ReadS();\n    Align = (EAlignType)Buffer->ReadByte();\n    VerticalAlign = (EVerticalAlignType)Buffer->ReadByte();\n    Fill = (ELoaderFillType)Buffer->ReadByte();\n    bShrinkOnly = Buffer->ReadBool();\n    bAutoSize = Buffer->ReadBool();\n    bShowErrorSign = Buffer->ReadBool();\n    Content->SetPlaying(Buffer->ReadBool());\n    Content->SetFrame(Buffer->ReadInt());\n\n    if (Buffer->ReadBool())\n        SetColor(Buffer->ReadColor());\n    int32 method = Buffer->ReadByte();\n    if (method != 0)\n    {\n        Content->SetFillMethod((EFillMethod)method);\n        Content->SetFillOrigin(Buffer->ReadByte());\n        Content->SetFillClockwise(Buffer->ReadBool());\n        Content->SetFillAmount(Buffer->ReadFloat());\n    }\n\n    if (!URL.IsEmpty())\n        LoadContent();\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GLoader3D.cpp",
    "content": "#include \"UI/GLoader3D.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GComponent.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/SMovieClip.h\"\n#include \"Widgets/SContainer.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGLoader3D::UGLoader3D()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        DisplayObject = Content = SNew(SFImage).GObject(this);\n    }\n}\n\nUGLoader3D::~UGLoader3D()\n{\n\n}\n\nvoid UGLoader3D::SetURL(const FString& InURL)\n{\n    if (URL.Compare(InURL, ESearchCase::CaseSensitive) == 0)\n        return;\n\n    ClearContent();\n    URL = InURL;\n    LoadContent();\n    UpdateGear(7);\n}\n\nFColor UGLoader3D::GetColor() const\n{\n    return FColor();// Content->getColor();\n}\n\nvoid UGLoader3D::SetColor(const FColor& InColor)\n{\n    //Content->setColor(value);\n}\n\nvoid UGLoader3D::LoadContent()\n{\n    ClearContent();\n\n    if (URL.IsEmpty())\n        return;\n\n    if (URL.StartsWith(\"ui://\"))\n        LoadFromPackage(URL);\n    else\n        LoadExternal();\n}\n\nvoid UGLoader3D::ClearContent()\n{\n\n}\n\nvoid UGLoader3D::LoadFromPackage(const FString& ItemURL)\n{\n    ContentItem = UUIPackage::GetItemByURL(ItemURL);\n\n    if (ContentItem.IsValid())\n    {\n        ContentItem = ContentItem->GetBranch();\n        SourceSize = ContentItem->Size;\n        ContentItem = ContentItem->GetHighResolution();\n        ContentItem->Load();\n\n        if (ContentItem->Type == EPackageItemType::Spine)\n        {\n            UpdateLayout();\n        }\n        else if (ContentItem->Type == EPackageItemType::DragonBones)\n        {\n            UpdateLayout();\n        }\n        else\n        {\n            if (bAutoSize)\n                SetSize(ContentItem->Size);\n\n            SetErrorState();\n\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"Unsupported type of GLoader: %d\"), ContentItem->Type);\n        }\n    }\n    else\n        SetErrorState();\n}\n\nvoid UGLoader3D::LoadExternal()\n{\n\n}\n\nvoid UGLoader3D::UpdateLayout()\n{\n    FVector2D contentSize = SourceSize;\n\n    if (bAutoSize)\n    {\n        bUpdatingLayout = true;\n        if (contentSize.X == 0)\n            contentSize.X = 50;\n        if (contentSize.Y == 0)\n            contentSize.Y = 30;\n        SetSize(contentSize);\n\n        bUpdatingLayout = false;\n\n        if (Size == contentSize)\n        {\n            Content->SetPosition(FVector2D(0, 0));\n            Content->SetSize(contentSize);\n            return;\n        }\n    }\n\n    FVector2D ContentScale(1, 1);\n    if (Fill != ELoaderFillType::None)\n    {\n        ContentScale = Size / SourceSize;\n\n        if (ContentScale != FVector2D(1, 1))\n        {\n            if (Fill == ELoaderFillType::ScaleMatchHeight)\n                ContentScale.X = ContentScale.Y;\n            else if (Fill == ELoaderFillType::ScaleMatchWidth)\n                ContentScale.Y = ContentScale.X;\n            else if (Fill == ELoaderFillType::Scale)\n            {\n                if (ContentScale.X > ContentScale.Y)\n                    ContentScale.X = ContentScale.Y;\n                else\n                    ContentScale.Y = ContentScale.X;\n            }\n            else if (Fill == ELoaderFillType::ScaleNoBorder)\n            {\n                if (ContentScale.X > ContentScale.Y)\n                    ContentScale.Y = ContentScale.X;\n                else\n                    ContentScale.X = ContentScale.Y;\n            }\n\n            if (bShrinkOnly)\n            {\n                if (ContentScale.X > 1)\n                    ContentScale.X = 1;\n                if (ContentScale.Y > 1)\n                    ContentScale.Y = 1;\n            }\n\n            contentSize = SourceSize * ContentScale;\n        }\n    }\n\n    Content->SetSize(contentSize);\n\n    FVector2D ContentPosition;\n    if (Align == EAlignType::Center)\n        ContentPosition.X = (Size.X - contentSize.X) / 2;\n    else if (Align == EAlignType::Right)\n        ContentPosition.X = Size.X - contentSize.X;\n    else\n        ContentPosition.X = 0;\n\n    if (VerticalAlign == EVerticalAlignType::Middle)\n        ContentPosition.Y = (Size.Y - contentSize.Y) / 2;\n    else if (VerticalAlign == EVerticalAlignType::Bottom)\n        ContentPosition.Y = Size.Y - contentSize.Y;\n    else\n        ContentPosition.Y = 0;\n\n    Content->SetPosition(ContentPosition);\n}\n\nvoid UGLoader3D::SetErrorState()\n{\n\n}\n\n\nFNVariant UGLoader3D::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetColor());\n        break;\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGLoader3D::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetColor(InValue.AsColor());\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGLoader3D::HandleSizeChanged()\n{\n    UGObject::HandleSizeChanged();\n\n    if (!bUpdatingLayout)\n        UpdateLayout();\n}\n\nvoid UGLoader3D::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GMovieClip.cpp",
    "content": "#include \"UI/GMovieClip.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/SMovieClip.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGMovieClip::UGMovieClip()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        DisplayObject = Content = SNew(SMovieClip).GObject(this);\n        DisplayObject->SetInteractable(false);\n    }\n}\n\nUGMovieClip::~UGMovieClip()\n{\n\n}\n\nvoid UGMovieClip::SetPlaySettings(int32 InStart, int32 InEnd, int32 InTimes, int32 InEndAt, const FSimpleDelegate& InCompleteCallback)\n{\n    Content->SetPlaySettings(InStart, InEnd, InTimes, InEndAt, InCompleteCallback);\n}\n\nbool UGMovieClip::IsPlaying() const\n{\n    return Content->IsPlaying();\n}\n\nvoid UGMovieClip::SetPlaying(bool bInPlaying)\n{\n    Content->SetPlaying(bInPlaying);\n}\n\nint32 UGMovieClip::GetFrame() const\n{\n    return Content->GetFrame();\n}\n\nvoid UGMovieClip::SetFrame(int32 InFrame)\n{\n    Content->SetFrame(InFrame);\n}\n\nfloat UGMovieClip::GetTimeScale() const\n{\n    return Content->GetTimeScale();\n}\n\nvoid UGMovieClip::SetTimeScale(float InTimeScale)\n{\n    Content->SetTimeScale(InTimeScale);\n}\n\nvoid UGMovieClip::Advance(float Time)\n{\n    Content->Advance(Time);\n}\n\nEFlipType UGMovieClip::GetFlip() const\n{\n    return Content->Graphics.GetFlip();\n}\n\nvoid UGMovieClip::SetFlip(EFlipType InFlip)\n{\n    Content->Graphics.SetFlip(InFlip);\n}\n\nFColor UGMovieClip::GetColor() const\n{\n    return Content->Graphics.GetColor();\n}\n\nvoid UGMovieClip::SetColor(const FColor& InColor)\n{\n    Content->Graphics.SetColor(InColor);\n}\n\nFNVariant UGMovieClip::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(GetColor());\n    case EObjectPropID::Playing:\n        return FNVariant(Content->IsPlaying());\n    case EObjectPropID::Frame:\n        return FNVariant(Content->GetFrame());\n    case EObjectPropID::TimeScale:\n        return FNVariant(Content->GetTimeScale());\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGMovieClip::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        SetColor(InValue.AsColor());\n        break;\n    case EObjectPropID::Playing:\n        Content->SetPlaying(InValue.AsBool());\n        break;\n    case EObjectPropID::Frame:\n        Content->SetFrame(InValue.AsInt());\n        break;\n    case EObjectPropID::TimeScale:\n        Content->SetTimeScale(InValue.AsFloat());\n        break;\n    case EObjectPropID::DeltaTime:\n        Content->Advance(InValue.AsFloat());\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGMovieClip::ConstructFromResource()\n{\n    TSharedPtr<FPackageItem> contentItem = PackageItem->GetBranch();\n    SourceSize = contentItem->Size;\n    InitSize = SourceSize;\n\n    contentItem = contentItem->GetHighResolution();\n    contentItem->Load();\n\n    Content->SetClipData(contentItem->MovieClipData);\n\n    SetSize(SourceSize);\n}\n\nvoid UGMovieClip::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    if (Buffer->ReadBool())\n        SetColor(Buffer->ReadColor());\n    SetFlip((EFlipType)Buffer->ReadByte());\n    SetFrame(Buffer->ReadInt());\n    SetPlaying(Buffer->ReadBool());\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GObject.cpp",
    "content": "#include \"UI/GObject.h\"\n#include \"UI/GList.h\"\n#include \"UI/GGroup.h\"\n#include \"UI/GController.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GRoot.h\"\n#include \"UI/Gears/GearBase.h\"\n#include \"UI/Gears/GearDisplay.h\"\n#include \"UI/Gears/GearDisplay2.h\"\n#include \"Widgets/SDisplayObject.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"FairyApplication.h\"\n\nTWeakObjectPtr<UGObject> UGObject::DraggingObject;\nFVector2D UGObject::GlobalDragStart;\nFBox2D UGObject::GlobalRect;\nbool UGObject::bUpdateInDragging = false;\n\nUGObject::UGObject() :\n    SourceSize(ForceInit),\n    InitSize(ForceInit),\n    MinSize(ForceInit),\n    MaxSize(ForceInit),\n    Position(ForceInit),\n    Size(ForceInit),\n    RawSize(ForceInit),\n    Pivot(ForceInit),\n    Scale{ 1, 1 },\n    Skew(ForceInit),\n    Alpha(1.0f),\n    bVisible(true),\n    bInternalVisible(true)\n{\n    static int32 _gInstanceCounter = 1;\n    ID.AppendInt(_gInstanceCounter);\n\n    Relations = MakeShareable(new FRelations(this));\n}\n\nUGObject::~UGObject()\n{\n}\n\nvoid UGObject::SetX(float InX)\n{\n    SetPosition(FVector2D(InX, Position.Y));\n}\n\nvoid UGObject::SetY(float InY)\n{\n    SetPosition(FVector2D(Position.X, InY));\n}\n\nvoid UGObject::SetPosition(const FVector2D& InPosition)\n{\n    if (Position != InPosition)\n    {\n        FVector2D delta = InPosition - Position;\n        Position = InPosition;\n\n        HandlePositionChanged();\n\n        UGGroup* g = Cast<UGGroup>(this);\n        if (g != nullptr)\n            g->MoveChildren(delta);\n\n        UpdateGear(1);\n\n        if (Parent.IsValid() && !Parent->IsA<UGList>())\n        {\n            Parent->SetBoundsChangedFlag();\n            if (Group.IsValid())\n                Group->SetBoundsChangedFlag(true);\n\n            OnPositionChangedEvent.Broadcast();\n        }\n\n        if (DraggingObject.Get() == this && !bUpdateInDragging)\n            GlobalRect = LocalToGlobalRect(FBox2D(FVector2D(), Size));\n    }\n}\n\nfloat UGObject::GetXMin() const\n{\n    return bPivotAsAnchor ? (Position.X - Size.X * Pivot.X) : Position.X;\n}\n\nvoid UGObject::SetXMin(float InXMin)\n{\n    if (bPivotAsAnchor)\n        SetPosition(FVector2D(InXMin + Size.X * Pivot.X, Position.Y));\n    else\n        SetPosition(FVector2D(InXMin, Position.Y));\n}\n\nfloat UGObject::GetYMin() const\n{\n    return bPivotAsAnchor ? (Position.Y - Size.Y * Pivot.Y) : Position.Y;\n}\n\nvoid UGObject::SetYMin(float InYMin)\n{\n    if (bPivotAsAnchor)\n        SetPosition(FVector2D(Position.X, InYMin + Size.Y * Pivot.Y));\n    else\n        SetPosition(FVector2D(Position.X, InYMin));\n}\n\nvoid UGObject::SetSize(const FVector2D& InSize, bool bIgnorePivot)\n{\n    if (RawSize != InSize)\n    {\n        RawSize = InSize;\n        FVector2D ClampSize = InSize;\n        if (ClampSize.X < MinSize.X)\n            ClampSize.X = MinSize.X;\n        else if (MaxSize.X > 0 && ClampSize.X > MaxSize.X)\n            ClampSize.X = MaxSize.X;\n        if (ClampSize.Y < MinSize.Y)\n            ClampSize.Y = MinSize.Y;\n        else if (MaxSize.Y > 0 && ClampSize.Y > MaxSize.Y)\n            ClampSize.Y = MaxSize.Y;\n        FVector2D Delta = ClampSize - Size;\n        Size = ClampSize;\n\n        HandleSizeChanged();\n\n        if (Pivot.X != 0 || Pivot.Y != 0)\n        {\n            if (!bPivotAsAnchor)\n            {\n                if (!bIgnorePivot)\n                    SetPosition(Position - Pivot * Delta);\n                else\n                    HandlePositionChanged();\n            }\n            else\n                HandlePositionChanged();\n        }\n\n        UGGroup* g = Cast<UGGroup>(this);\n        if (g != nullptr)\n            g->ResizeChildren(Delta);\n\n        UpdateGear(2);\n\n        if (Parent.IsValid())\n        {\n            Relations->OnOwnerSizeChanged(Delta, bPivotAsAnchor || !bIgnorePivot);\n            Parent->SetBoundsChangedFlag();\n            if (Group.IsValid())\n                Group->SetBoundsChangedFlag();\n        }\n\n        OnSizeChangedEvent.Broadcast();\n    }\n}\n\nvoid UGObject::SetSizeDirectly(const FVector2D& InSize)\n{\n    RawSize = InSize;\n    Size = InSize;\n    if (Size.X < 0)\n        Size.X = 0;\n    if (Size.Y < 0)\n        Size.Y = 0;\n}\n\nvoid UGObject::Center(bool bRestraint)\n{\n    UGComponent* r = nullptr;\n    if (Parent.IsValid())\n        r = Parent.Get();\n    else\n        r = GetUIRoot();\n\n    SetPosition(((r->Size - Size) / 2).RoundToVector());\n    if (bRestraint)\n    {\n        AddRelation(r, ERelationType::Center_Center);\n        AddRelation(r, ERelationType::Middle_Middle);\n    }\n}\n\nvoid UGObject::MakeFullScreen(bool bRestraint)\n{\n    SetSize(GetUIRoot()->GetSize());\n    if (bRestraint)\n        AddRelation(GetUIRoot(), ERelationType::Size);\n}\n\nvoid UGObject::SetPivot(const FVector2D& InPivot, bool bAsAnchor)\n{\n    if (Pivot != InPivot || bPivotAsAnchor != bAsAnchor)\n    {\n        Pivot = InPivot;\n        bPivotAsAnchor = bAsAnchor;\n        DisplayObject->SetRenderTransformPivot(FVector2D(Pivot.X, Pivot.Y));\n        HandlePositionChanged();\n    }\n}\n\nvoid UGObject::SetScale(const FVector2D& InScale)\n{\n    if (Scale != InScale)\n    {\n        Scale = InScale;\n        UpdateTransform();\n        UpdateGear(2);\n    }\n}\n\nvoid UGObject::SetSkew(const FVector2D& InSkew)\n{\n    Skew = InSkew;\n}\n\nvoid UGObject::SetRotation(float InRotation)\n{\n    if (Rotation != InRotation)\n    {\n        Rotation = InRotation;\n        UpdateTransform();\n        UpdateGear(3);\n    }\n}\n\nvoid UGObject::UpdateTransform()\n{\n    FScale2D Scale2D = FScale2D(Scale);\n    FQuat2D Quat2D = FQuat2D(FMath::DegreesToRadians(Rotation));\n    FMatrix2x2 Matrix = Concatenate(Quat2D, Scale2D);\n    DisplayObject->SetRenderTransform(FSlateRenderTransform(Matrix, Position));\n}\n\nvoid UGObject::SetAlpha(float InAlpha)\n{\n    if (Alpha != InAlpha)\n    {\n        Alpha = InAlpha;\n        HandleAlphaChanged();\n        UpdateGear(3);\n    }\n}\n\nvoid UGObject::SetGrayed(bool InBGrayed)\n{\n    if (bGrayed != InBGrayed)\n    {\n        bGrayed = InBGrayed;\n        HandleGrayedChanged();\n        UpdateGear(3);\n    }\n}\n\nvoid UGObject::SetVisible(bool bInVisible)\n{\n    if (bVisible != bInVisible)\n    {\n        bVisible = bInVisible;\n        HandleVisibleChanged();\n        if (Parent.IsValid())\n            Parent->SetBoundsChangedFlag();\n        if (Group.IsValid() && Group->IsExcludeInvisibles())\n            Group->SetBoundsChangedFlag();\n    }\n}\n\nbool UGObject::InternalVisible() const\n{\n    return bInternalVisible && (!Group.IsValid() || Group->InternalVisible());\n}\n\nbool UGObject::InternalVisible2() const\n{\n    return bVisible && (!Group.IsValid() || Group->InternalVisible2());\n}\n\nbool UGObject::InternalVisible3() const\n{\n    return bVisible && bInternalVisible;\n}\n\nbool UGObject::IsTouchable() const\n{\n    return DisplayObject->IsTouchable();\n}\n\nvoid UGObject::SetTouchable(bool bInTouchable)\n{\n    DisplayObject->SetTouchable(bInTouchable);\n}\n\nvoid UGObject::SetSortingOrder(int32 InSortingOrder)\n{\n    if (InSortingOrder < 0)\n        InSortingOrder = 0;\n    if (SortingOrder != InSortingOrder)\n    {\n        int32 old = SortingOrder;\n        SortingOrder = InSortingOrder;\n        if (Parent.IsValid())\n            Parent->ChildSortingOrderChanged(this, old, SortingOrder);\n    }\n}\n\nvoid UGObject::SetGroup(UGGroup* InGroup)\n{\n    if (Group.Get() != InGroup)\n    {\n        if (Group.IsValid())\n            Group->SetBoundsChangedFlag();\n        Group = InGroup;\n        if (Group.IsValid())\n            Group->SetBoundsChangedFlag();\n        HandleVisibleChanged();\n        if (Parent.IsValid())\n            Parent->ChildStateChanged(this);\n    }\n}\n\nconst FString& UGObject::GetText() const\n{\n    return G_EMPTY_STRING;\n}\n\nvoid UGObject::SetText(const FString& InText)\n{\n}\n\nconst FString& UGObject::GetIcon() const\n{\n    return G_EMPTY_STRING;\n}\n\nvoid UGObject::SetIcon(const FString& InIcon)\n{\n}\n\nvoid UGObject::SetTooltips(const FString& InTooltips)\n{\n    Tooltips = InTooltips;\n    if (!Tooltips.IsEmpty())\n    {\n        On(FUIEvents::RollOver).AddUObject(this, &UGObject::OnRollOverHandler);\n        On(FUIEvents::RollOut).AddUObject(this, &UGObject::OnRollOutHandler);\n    }\n}\n\nvoid UGObject::OnRollOverHandler(UEventContext* Context)\n{\n    GetUIRoot()->ShowTooltips(Tooltips);\n}\n\nvoid UGObject::OnRollOutHandler(UEventContext* Context)\n{\n    GetUIRoot()->HideTooltips();\n}\n\nvoid UGObject::SetDraggable(bool bInDraggable)\n{\n    if (bDraggable != bInDraggable)\n    {\n        bDraggable = bInDraggable;\n        InitDrag();\n    }\n}\n\nFBox2D UGObject::GetDragBounds() const\n{\n    if (DragBounds.IsSet())\n        return DragBounds.GetValue();\n    else\n        return FBox2D(FVector2D::ZeroVector, FVector2D::ZeroVector);\n}\n\nvoid UGObject::SetDragBounds(const FBox2D& InBounds)\n{\n    if (InBounds.Min == InBounds.Max && InBounds.Min == FVector2D::ZeroVector)\n        DragBounds.Reset();\n    else\n        DragBounds = InBounds;\n}\n\nvoid UGObject::StartDrag(int32 UserIndex, int32 PointerIndex)\n{\n    DragBegin(UserIndex, PointerIndex);\n}\n\nvoid UGObject::StopDrag()\n{\n    DragEnd();\n}\n\nFString UGObject::GetResourceURL() const\n{\n    if (PackageItem.IsValid())\n        return \"ui://\" + PackageItem->Owner->GetID() + PackageItem->ID;\n    else\n        return G_EMPTY_STRING;\n}\n\nFString UGObject::GetResourceName() const\n{\n    if (PackageItem.IsValid())\n        return PackageItem->Name;\n    else\n        return G_EMPTY_STRING;\n}\n\nFString UGObject::GetPackageName() const\n{\n    if (PackageItem.IsValid())\n        return PackageItem->Owner->GetName();\n    else\n        return G_EMPTY_STRING;\n}\n\nFVector2D UGObject::LocalToGlobal(const FVector2D& InPoint)\n{\n    FVector2D Point = InPoint;\n    if (bPivotAsAnchor)\n        Point += Size * Pivot;\n\n    return DisplayObject->GetCachedGeometry().LocalToAbsolute(Point);\n}\n\nFBox2D UGObject::LocalToGlobalRect(const FBox2D& InRect)\n{\n    FVector2D v0 = LocalToGlobal(InRect.Min);\n    FVector2D v1 = LocalToGlobal(InRect.Max);\n    return FBox2D(v0, v1);\n}\n\nFVector2D UGObject::LocalToRoot(const FVector2D& InPoint)\n{\n    return GetUIRoot()->GlobalToLocal(LocalToGlobal(InPoint));\n}\n\nFBox2D UGObject::LocalToRootRect(const FBox2D& InRect)\n{\n    return GetUIRoot()->GlobalToLocalRect(LocalToGlobalRect(InRect));\n}\n\nFVector2D UGObject::GlobalToLocal(const FVector2D& InPoint)\n{\n    FVector2D Point = DisplayObject->GetCachedGeometry().AbsoluteToLocal(InPoint);\n    if (bPivotAsAnchor)\n        Point -= Size * Pivot;\n    return Point;\n}\n\nFBox2D UGObject::GlobalToLocalRect(const FBox2D& InRect)\n{\n    FVector2D v0 = GlobalToLocal(InRect.Min);\n    FVector2D v1 = GlobalToLocal(InRect.Max);\n    return FBox2D(v0, v1);\n}\n\nFVector2D UGObject::RootToLocal(const FVector2D& InPoint)\n{\n    return GlobalToLocal(GetUIRoot()->LocalToGlobal(InPoint));\n}\n\nFBox2D UGObject::RootToLocalRect(const FBox2D& InRect)\n{\n    return GlobalToLocalRect(GetUIRoot()->LocalToGlobalRect(InRect));\n}\n\nvoid UGObject::AddRelation(UGObject* Obj, ERelationType RelationType, bool bUsePercent)\n{\n    verifyf(Obj != this, TEXT(\"Cannot add relation to self\"));\n\n    Relations->Add(Obj, RelationType, bUsePercent);\n}\n\nvoid UGObject::RemoveRelation(UGObject* Obj, ERelationType RelationType)\n{\n    Relations->Remove(Obj, RelationType);\n}\n\nconst TSharedPtr<FGearBase>& UGObject::GetGear(int32 Index)\n{\n    TSharedPtr<FGearBase>& Gear = Gears[Index];\n    if (!Gear.IsValid())\n        Gear = FGearBase::Create(this, static_cast<FGearBase::EType>(Index));\n\n    return Gear;\n}\n\nvoid UGObject::UpdateGear(int32 Index)\n{\n    if (bUnderConstruct || bGearLocked)\n        return;\n\n    const TSharedPtr<FGearBase>& Gear = Gears[Index];\n    if (Gear.IsValid() && Gear->GetController() != nullptr)\n        Gear->UpdateState();\n}\n\nbool UGObject::CheckGearController(int32 Index, UGController* Controller)\n{\n    return Gears[Index].IsValid() && Gears[Index]->GetController() == Controller;\n}\n\nvoid UGObject::UpdateGearFromRelations(int32 Index, const FVector2D& Delta)\n{\n    if (Gears[Index].IsValid())\n        Gears[Index]->UpdateFromRelations(Delta);\n}\n\nuint32 UGObject::AddDisplayLock()\n{\n    const TSharedPtr<FGearDisplay>& GearDisplay = StaticCastSharedPtr<FGearDisplay>(Gears[0]);\n    if (GearDisplay.IsValid() && GearDisplay->GetController() != nullptr)\n    {\n        uint32 ret = GearDisplay->AddLock();\n        CheckGearDisplay();\n\n        return ret;\n    }\n    else\n        return 0;\n}\n\nvoid UGObject::ReleaseDisplayLock(uint32 Token)\n{\n    const TSharedPtr<FGearDisplay>& GearDisplay = StaticCastSharedPtr<FGearDisplay>(Gears[0]);\n    if (GearDisplay.IsValid() && GearDisplay->GetController() != nullptr)\n    {\n        GearDisplay->ReleaseLock(Token);\n        CheckGearDisplay();\n    }\n}\n\nvoid UGObject::CheckGearDisplay()\n{\n    if (bHandlingController)\n        return;\n\n    bool bConnected = !Gears[0].IsValid() || StaticCastSharedPtr<FGearDisplay>(Gears[0])->IsConnected();\n    if (Gears[8].IsValid() && Gears[8]->GetType() == FGearBase::EType::Display2)\n        bConnected = StaticCastSharedPtr<FGearDisplay2>(Gears[8])->Evaluate(bConnected);\n\n    if (bConnected != bInternalVisible)\n    {\n        bInternalVisible = bConnected;\n        if (Parent.IsValid())\n            Parent->ChildStateChanged(this);\n        if (Group.IsValid() && Group->IsExcludeInvisibles())\n            Group->SetBoundsChangedFlag();\n    }\n}\n\nvoid UGObject::SetParent(UGObject* InParent)\n{\n    verifyf(InParent == nullptr || InParent->IsA<UGComponent>(), TEXT(\"Parent must be GComponent\"));\n    verifyf(InParent != this, TEXT(\"Parent must not be self\"));\n\n    if (InParent != nullptr)\n        Cast<UGComponent>(InParent)->AddChild(this);\n    else if (Parent.IsValid())\n        Parent->RemoveChild(this);\n}\n\nvoid UGObject::SetParentToRoot()\n{\n    SetParent(GetUIRoot());\n}\n\nvoid UGObject::RemoveFromParent()\n{\n    if (Parent.IsValid())\n        Parent->RemoveChild(this);\n}\n\nbool UGObject::OnStage() const\n{\n    return SDisplayObject::IsWidgetOnStage(DisplayObject);\n}\n\nUGRoot* UGObject::GetUIRoot() const\n{\n    return GetApp()->GetUIRoot();\n}\n\nUFairyApplication* UGObject::GetApp() const\n{\n    if (CachedApp == nullptr)\n        const_cast<UGObject*>(this)->CachedApp = UFairyApplication::Get(const_cast<UGObject*>(this));\n\n    return CachedApp;\n}\n\nUWorld* UGObject::GetWorld() const\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n        return GetOuter()->GetWorld();\n    else\n        return nullptr;\n}\n\nUGObject* UGObject::CastTo(TSubclassOf<UGObject> ClassType) const\n{\n    return const_cast<UGObject*>(this);\n}\n\nFNVariant UGObject::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Text:\n        return FNVariant(GetText());\n    case EObjectPropID::Icon:\n        return FNVariant(GetIcon());\n    default:\n        return FNVariant(0);\n    }\n}\n\nvoid UGObject::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Text:\n        return SetText(InValue.AsString());\n    case EObjectPropID::Icon:\n        return SetIcon(InValue.AsString());\n    default:\n        break;\n    }\n}\n\nbool UGObject::DispatchEvent(const FName& EventType, const FNVariant& Data)\n{\n    return GetApp()->DispatchEvent(EventType, DisplayObject.ToSharedRef(), Data);\n}\n\nbool UGObject::HasEventListener(const FName& EventType) const\n{\n    const FUnifiedEventDelegate& Delegate = const_cast<UGObject*>(this)->GetEventDelegate(EventType);\n    return Delegate.Func.IsBound() || (Delegate.DynFunc != nullptr && Delegate.DynFunc->IsBound());\n}\n\nvoid UGObject::InvokeEventDelegate(UEventContext* Context)\n{\n    FUnifiedEventDelegate& Delegate = GetEventDelegate(Context->GetType());\n    Delegate.Func.Broadcast(Context);\n    if (Delegate.DynFunc != nullptr)\n        Delegate.DynFunc->Broadcast(Context);\n}\n\nUGObject::FUnifiedEventDelegate& UGObject::GetEventDelegate(const FName& EventType)\n{\n    FUnifiedEventDelegate* Delegate = EventDelegates.Find(EventType);\n    if (Delegate == nullptr)\n    {\n        Delegate = &EventDelegates.Add(EventType);\n\n#if (ENGINE_MAJOR_VERSION <= 4) && (ENGINE_MINOR_VERSION < 25)\n        UProperty\n#else\n        FProperty\n#endif\n            * Property = GetClass()->FindPropertyByName(FName(*FString(\"On\").Append(EventType.ToString())));\n\n        if (Property != nullptr)\n            Delegate->DynFunc = Property->ContainerPtrToValuePtr<FGUIEventDynMDelegate>(this);\n        else\n            Delegate->DynFunc = nullptr;\n    }\n\n    return *Delegate;\n}\n\nFGUIEventMDelegate& UGObject::On(const FName& EventType)\n{\n    return GetEventDelegate(EventType).Func;\n}\n\nvoid UGObject::ConstructFromResource()\n{\n}\n\nvoid UGObject::HandlePositionChanged()\n{\n    DisplayObject->SetPosition(bPivotAsAnchor ? (Position - Size * Pivot) : Position);\n}\n\nvoid UGObject::HandleSizeChanged()\n{\n    DisplayObject->SetSize(Size);\n}\n\nvoid UGObject::HandleAlphaChanged()\n{\n    DisplayObject->SetRenderOpacity(Alpha);\n}\n\nvoid UGObject::HandleGrayedChanged()\n{\n    DisplayObject->SetEnabled(!bGrayed);\n}\n\nvoid UGObject::HandleVisibleChanged()\n{\n    DisplayObject->SetVisible(InternalVisible2());\n}\n\nvoid UGObject::HandleControllerChanged(UGController* Controller)\n{\n    bHandlingController = true;\n    for (int32 i = 0; i < 10; i++)\n    {\n        const TSharedPtr<FGearBase>& Gear = Gears[i];\n        if (Gear.IsValid() && Gear->GetController() == Controller)\n            Gear->Apply();\n    }\n    bHandlingController = false;\n\n\n    CheckGearDisplay();\n}\n\nvoid UGObject::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    Buffer->Seek(BeginPos, 0);\n    Buffer->Skip(5);\n\n    ID = Buffer->ReadS();\n    Name = Buffer->ReadS();\n    float f1 = Buffer->ReadInt();\n    float f2 = Buffer->ReadInt();\n    SetPosition(FVector2D(f1, f2));\n\n    if (Buffer->ReadBool())\n    {\n        InitSize.X = Buffer->ReadInt();\n        InitSize.Y = Buffer->ReadInt();\n        SetSize(InitSize, true);\n    }\n\n    if (Buffer->ReadBool())\n    {\n        MinSize.X = Buffer->ReadInt();\n        MaxSize.X = Buffer->ReadInt();\n        MinSize.Y = Buffer->ReadInt();\n        MaxSize.Y = Buffer->ReadInt();\n    }\n\n    if (Buffer->ReadBool())\n    {\n        f1 = Buffer->ReadFloat();\n        f2 = Buffer->ReadFloat();\n        SetScale(FVector2D(f1, f2));\n    }\n\n    if (Buffer->ReadBool())\n    {\n        f1 = Buffer->ReadFloat();\n        f2 = Buffer->ReadFloat();\n        SetSkew(FVector2D(f1, f2));\n    }\n\n    if (Buffer->ReadBool())\n    {\n        f1 = Buffer->ReadFloat();\n        f2 = Buffer->ReadFloat();\n        SetPivot(FVector2D(f1, f2), Buffer->ReadBool());\n    }\n\n    f1 = Buffer->ReadFloat();\n    if (f1 != 1)\n        SetAlpha(f1);\n\n    f1 = Buffer->ReadFloat();\n    if (f1 != 0)\n        SetRotation(f1);\n\n    if (!Buffer->ReadBool())\n        SetVisible(false);\n    if (!Buffer->ReadBool())\n        SetTouchable(false);\n    if (Buffer->ReadBool())\n        SetGrayed(true);\n    Buffer->ReadByte(); //blendMode\n    Buffer->ReadByte(); //filter\n\n    const FString& str = Buffer->ReadS();\n    if (!str.IsEmpty())\n        UserData = str;\n}\n\nvoid UGObject::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    Buffer->Seek(BeginPos, 1);\n\n    const FString& str = Buffer->ReadS();\n    if (!str.IsEmpty())\n        SetTooltips(str);\n\n    int16 groupId = Buffer->ReadShort();\n    if (groupId >= 0)\n        Group = Cast<UGGroup>(Parent->GetChildAt(groupId));\n\n    Buffer->Seek(BeginPos, 2);\n\n    int16 cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        int16 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        GetGear(Buffer->ReadByte())->Setup(Buffer);\n\n        Buffer->SetPos(nextPos);\n    }\n}\n\nvoid UGObject::InitDrag()\n{\n    if (bDraggable)\n    {\n        OnTouchBegin.AddUniqueDynamic(this, &UGObject::OnTouchBeginHandler);\n        OnTouchMove.AddUniqueDynamic(this, &UGObject::OnTouchMoveHandler);\n        OnTouchEnd.AddUniqueDynamic(this, &UGObject::OnTouchEndHandler);\n    }\n    else\n    {\n        OnTouchBegin.RemoveDynamic(this, &UGObject::OnTouchBeginHandler);\n        OnTouchMove.RemoveDynamic(this, &UGObject::OnTouchMoveHandler);\n        OnTouchEnd.RemoveDynamic(this, &UGObject::OnTouchEndHandler);\n    }\n}\n\nvoid UGObject::DragBegin(int32 UserIndex, int32 PointerIndex)\n{\n    if (DispatchEvent(FUIEvents::DragStart))\n        return;\n\n    if (DraggingObject.IsValid())\n    {\n        UGObject* tmp = DraggingObject.Get();\n        DraggingObject->StopDrag();\n        DraggingObject.Reset();\n        tmp->DispatchEvent(FUIEvents::DragEnd);\n    }\n\n    GlobalDragStart = GetApp()->GetTouchPosition(UserIndex, PointerIndex);\n    GlobalRect = LocalToGlobalRect(FBox2D(FVector2D::ZeroVector, Size));\n    DraggingObject = this;\n    bDragTesting = false;\n\n    GetApp()->AddMouseCaptor(UserIndex, PointerIndex, this);\n\n    OnTouchMove.AddUniqueDynamic(this, &UGObject::OnTouchMoveHandler);\n    OnTouchEnd.AddUniqueDynamic(this, &UGObject::OnTouchEndHandler);\n}\n\nvoid UGObject::DragEnd()\n{\n    if (DraggingObject.Get() == this)\n    {\n        bDragTesting = false;\n        DraggingObject.Reset();\n    }\n}\n\nvoid UGObject::OnTouchBeginHandler(UEventContext* Context)\n{\n    DragTouchStartPos = Context->GetPointerPosition();\n    bDragTesting = true;\n    Context->CaptureTouch();\n}\n\nvoid UGObject::OnTouchMoveHandler(UEventContext* Context)\n{\n    if (DraggingObject.Get() != this && bDragTesting)\n    {\n        int32 sensitivity;\n        if (FPlatformMisc::DesktopTouchScreen())\n            sensitivity = FUIConfig::Config.ClickDragSensitivity;\n        else\n            sensitivity = FUIConfig::Config.TouchDragSensitivity;\n        if (FMath::Abs(DragTouchStartPos.X - Context->GetPointerPosition().X) < sensitivity\n            && FMath::Abs(DragTouchStartPos.Y - Context->GetPointerPosition().Y) < sensitivity)\n            return;\n\n        bDragTesting = false;\n        DragBegin(Context->GetUserIndex(), Context->GetPointerIndex());\n    }\n\n    if (DraggingObject.Get() == this)\n    {\n        FVector2D Pos = Context->GetPointerPosition() - GlobalDragStart + GlobalRect.Min;\n        if (DragBounds.IsSet())\n        {\n            FBox2D rect = GetUIRoot()->LocalToGlobalRect(DragBounds.GetValue());\n            if (Pos.X < rect.Min.X)\n                Pos.X = rect.Min.X;\n            else if (Pos.X + GlobalRect.GetSize().X > rect.Max.X)\n            {\n                Pos.X = rect.Max.X - GlobalRect.GetSize().X;\n                if (Pos.X < rect.Min.X)\n                    Pos.X = rect.Min.X;\n            }\n\n            if (Pos.Y < rect.Min.Y)\n                Pos.Y = rect.Min.Y;\n            else if (Pos.Y + GlobalRect.GetSize().Y > rect.Max.Y)\n            {\n                Pos.Y = rect.Max.Y - GlobalRect.GetSize().Y;\n                if (Pos.Y < rect.Min.Y)\n                    Pos.Y = rect.Min.Y;\n            }\n        }\n\n        Pos = Parent->GlobalToLocal(Pos);\n\n        bUpdateInDragging = true;\n        SetPosition(Pos.RoundToVector());\n        bUpdateInDragging = false;\n\n        DispatchEvent(FUIEvents::DragMove);\n    }\n}\n\nvoid UGObject::OnTouchEndHandler(UEventContext* Context)\n{\n    if (DraggingObject.Get() == this)\n    {\n        DraggingObject.Reset();\n        DispatchEvent(FUIEvents::DragEnd);\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GObjectPool.cpp",
    "content": "#include \"UI/GObjectPool.h\"\n#include \"UI/GObject.h\"\n#include \"UI/UIPackage.h\"\n\nUGObject* FGObjectPool::GetObject(const FString & URL, UObject* WorldContextObject)\n{\n    FString URL2 = UUIPackage::NormalizeURL(URL);\n    if (URL2.Len() == 0)\n        return nullptr;\n\n    UGObject* ret;\n    TArray<UGObject*>& arr = Pool.FindOrAdd(URL2);\n    if (arr.Num() > 0)\n        ret = arr.Pop();\n    else\n        ret = UUIPackage::CreateObjectFromURL(URL2, WorldContextObject);\n    return ret;\n}\n\nvoid FGObjectPool::ReturnObject(UGObject* Obj)\n{\n    TArray<UGObject*>& arr = Pool.FindOrAdd(Obj->GetResourceURL());\n    arr.Add(Obj);\n}\n\nvoid FGObjectPool::AddReferencedObjects(FReferenceCollector& Collector)\n{\n    for (auto& Elem : Pool)\n    {\n        Collector.AddReferencedObjects(Elem.Value);\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GProgressBar.cpp",
    "content": "#include \"UI/GProgressBar.h\"\n#include \"UI/GImage.h\"\n#include \"UI/GLoader.h\"\n#include \"Tween/GTween.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGProgressBar::UGProgressBar() :\n    Max(100)\n{\n}\n\nUGProgressBar::~UGProgressBar()\n{\n}\n\nvoid UGProgressBar::SetTitleType(EProgressTitleType InTitleType)\n{\n    if (TitleType != InTitleType)\n    {\n        TitleType = InTitleType;\n        Update(Value);\n    }\n}\n\nvoid UGProgressBar::SetMin(float InMin)\n{\n    if (Min != InMin)\n    {\n        Min = InMin;\n        Update(Value);\n    }\n}\n\nvoid UGProgressBar::SetMax(float InMax)\n{\n    if (Max != InMax)\n    {\n        Max = InMax;\n        Update(Value);\n    }\n}\n\nvoid UGProgressBar::SetValue(float InValue)\n{\n    if (Value != InValue)\n    {\n        FGTween::Kill(TweenHandle, false);\n\n        Value = InValue;\n        Update(Value);\n    }\n}\n\nvoid UGProgressBar::TweenValue(float InValue, float Duration)\n{\n    float oldValule;\n\n    FGTweener* tweener = FGTween::GetTween(TweenHandle);\n    if (tweener != nullptr)\n    {\n        oldValule = tweener->Value.X;\n        tweener->Kill(false);\n    }\n    else\n        oldValule = Value;\n\n    Value = InValue;\n    TweenHandle = FGTween::To(oldValule, Value, Duration)\n        ->SetEase(EEaseType::Linear)\n        ->OnUpdate(FTweenDelegate::CreateStatic(&FGTweenAction::SetProgress))\n        ->SetTarget(this)\n        ->GetHandle();\n}\n\nvoid UGProgressBar::Update(float InValue)\n{\n    float percent;\n    if (Max == Min)\n        percent = 0;\n    else\n        percent = FMath::Clamp<float>((InValue - Min) / (Max - Min), 0, 1);\n\n    if (TitleObject != nullptr)\n    {\n        FString NewTitle;\n        switch (TitleType)\n        {\n        case EProgressTitleType::Percent:\n            NewTitle.AppendInt(FMath::FloorToInt(percent * 100));\n            NewTitle.AppendChar('%');\n            break;\n\n        case EProgressTitleType::ValueMax:\n            NewTitle.AppendInt(FMath::FloorToInt(InValue));\n            NewTitle.AppendChar('/');\n            NewTitle.AppendInt(FMath::FloorToInt(Max));\n            break;\n\n        case EProgressTitleType::Value:\n            NewTitle.AppendInt(FMath::FloorToInt(InValue));\n            break;\n\n        case EProgressTitleType::Max:\n            NewTitle.AppendInt(FMath::FloorToInt(Max));\n            break;\n        default:\n            break;\n        }\n        TitleObject->SetText(NewTitle);\n    }\n\n    FVector2D FullSize = GetSize() - BarMaxSizeDelta;;\n    if (!bReverse)\n    {\n        if (BarObjectH != nullptr)\n        {\n            if (!SetFillAmount(BarObjectH, percent))\n                BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * percent));\n        }\n        if (BarObjectV != nullptr)\n        {\n            if (!SetFillAmount(BarObjectV, percent))\n                BarObjectV->SetHeight(FMath::RoundToFloat(FullSize.Y * percent));\n        }\n    }\n    else\n    {\n        if (BarObjectH != nullptr)\n        {\n            if (!SetFillAmount(BarObjectH, 1 - percent))\n            {\n                BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * percent));\n                BarObjectH->SetX(BarStartPosition.X + (FullSize.X - BarObjectH->GetWidth()));\n            }\n        }\n        if (BarObjectV != nullptr)\n        {\n            if (!SetFillAmount(BarObjectV, 1 - percent))\n            {\n                BarObjectV->SetHeight(round(FullSize.Y * percent));\n                BarObjectV->SetY(BarStartPosition.Y + (FullSize.Y - BarObjectV->GetHeight()));\n            }\n        }\n    }\n}\n\nbool UGProgressBar::SetFillAmount(UGObject* Bar, float Amount)\n{\n    UGImage* image = nullptr;\n    UGLoader* loader = nullptr;\n\n    if ((image = Cast<UGImage>(Bar)) != nullptr && image->GetFillMethod() != EFillMethod::None)\n        image->SetFillAmount(Amount);\n    else if ((loader = Cast<UGLoader>(Bar)) != nullptr && loader->GetFillMethod() != EFillMethod::None)\n        loader->SetFillAmount(Amount);\n    else\n        return false;\n\n    return true;\n}\n\nvoid UGProgressBar::HandleSizeChanged()\n{\n    UGComponent::HandleSizeChanged();\n\n    BarMaxSize = GetSize() - BarMaxSizeDelta;\n\n    if (!bUnderConstruct)\n        Update(Value);\n}\n\nvoid UGProgressBar::ConstructExtension(FByteBuffer* Buffer)\n{\n    Buffer->Seek(0, 6);\n\n    TitleType = (EProgressTitleType)Buffer->ReadByte();\n    bReverse = Buffer->ReadBool();\n\n    TitleObject = GetChild(\"title\");\n    BarObjectH = GetChild(\"bar\");\n    BarObjectV = GetChild(\"bar_v\");\n\n    if (BarObjectH != nullptr)\n    {\n        BarMaxSize.X = BarObjectH->GetWidth();\n        BarMaxSizeDelta.X = GetWidth() - BarMaxSize.X;\n        BarStartPosition.X = BarObjectH->GetX();\n    }\n    if (BarObjectV != nullptr)\n    {\n        BarMaxSize.Y = BarObjectV->GetHeight();\n        BarMaxSizeDelta.Y = GetHeight() - BarMaxSize.Y;\n        BarStartPosition.Y = BarObjectV->GetY();\n    }\n}\n\nvoid UGProgressBar::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupAfterAdd(Buffer, BeginPos);\n\n    if (!Buffer->Seek(BeginPos, 6))\n    {\n        Update(Value);\n        return;\n    }\n\n    if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType)\n    {\n        Update(Value);\n        return;\n    }\n\n    Value = Buffer->ReadInt();\n    Max = Buffer->ReadInt();\n    if (Buffer->Version >= 2)\n        Min = Buffer->ReadInt();\n\n    Update(Value);\n}\n\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GRichTextField.cpp",
    "content": "#include \"UI/GRichTextField.h\"\n\nUGRichTextField::UGRichTextField()\n{\n}\n\nUGRichTextField::~UGRichTextField()\n{\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GRoot.cpp",
    "content": "#include \"UI/GRoot.h\"\n#include \"Engine/World.h\"\n#include \"Engine/GameViewportClient.h\"\n#include \"Slate.h\"\n#include \"FairyApplication.h\"\n#include \"UI/GWindow.h\"\n#include \"UI/GGraph.h\"\n#include \"UI/UIPackage.h\"\n#include \"Widgets/SContainer.h\"\n\nint32 UGRoot::ContentScaleLevel = 0;\n\nclass SRootContainer : public SContainer\n{\npublic:\n    virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n};\n\nUGRoot* UGRoot::Get(UObject* WorldContextObject)\n{\n    return UFairyApplication::Get(WorldContextObject)->GetUIRoot();\n}\n\nUGRoot::UGRoot()\n{\n}\n\nUGRoot::~UGRoot()\n{\n}\n\nvoid UGRoot::AddToViewport()\n{\n    UGameViewportClient* ViewportClient = GetApp()->GetViewportClient();\n    verifyf(ViewportClient != nullptr, TEXT(\"Null Viewport?\"));\n\n    TSharedRef<SRootContainer> FullScreenCanvas = SNew(SRootContainer).GObject(this);\n    FullScreenCanvas->SetOpaque(false);\n    FullScreenCanvas->AddChild(GetDisplayObject());\n    ViewportClient->AddViewportWidgetContent(FullScreenCanvas, 100);\n\n    SetSize(FullScreenCanvas->GetParentWidget()->GetPaintSpaceGeometry().GetLocalSize().RoundToVector());\n}\n\nvoid UGRoot::ShowWindow(UGWindow* Window)\n{\n    AddChild(Window);\n    AdjustModalLayer();\n}\n\nvoid UGRoot::HideWindow(UGWindow* Window)\n{\n    Window->Hide();\n}\n\nvoid UGRoot::HideWindowImmediately(UGWindow* Window)\n{\n    if (Window->GetParent() == this)\n        RemoveChild(Window);\n\n    AdjustModalLayer();\n}\n\nvoid UGRoot::BringToFront(UGWindow* Window)\n{\n    int32 cnt = NumChildren();\n    int32 i;\n    if (ModalLayer->GetParent() != nullptr && !Window->IsModal())\n        i = GetChildIndex(ModalLayer) - 1;\n    else\n        i = cnt - 1;\n\n    for (; i >= 0; i--)\n    {\n        UGObject* g = GetChildAt(i);\n        if (g == Window)\n            return;\n        if (g->IsA<UGWindow>())\n            break;\n    }\n\n    if (i >= 0)\n        SetChildIndex(Window, i);\n}\n\nvoid UGRoot::CloseAllExceptModals()\n{\n    TArray<UGObject*> map;\n    map.Append(Children);\n\n    for (const auto& child : map)\n    {\n        if (child->IsA<UGWindow>() && !((UGWindow*)child)->IsModal())\n            HideWindowImmediately((UGWindow*)child);\n    }\n}\n\nvoid UGRoot::CloseAllWindows()\n{\n    TArray<UGObject*> map;\n    map.Append(Children);\n\n    for (const auto& child : map)\n    {\n        if (child->IsA<UGWindow>())\n            HideWindowImmediately((UGWindow*)child);\n    }\n}\n\nUGWindow* UGRoot::GetTopWindow() const\n{\n    int32 cnt = NumChildren();\n    for (int32 i = cnt - 1; i >= 0; i--)\n    {\n        UGObject* child = GetChildAt(i);\n        if (child->IsA<UGWindow>())\n        {\n            return (UGWindow*)child;\n        }\n    }\n\n    return nullptr;\n}\n\nUGGraph* UGRoot::GetModalLayer()\n{\n    if (ModalLayer == nullptr)\n        CreateModalLayer();\n\n    return ModalLayer;\n}\n\nvoid UGRoot::CreateModalLayer()\n{\n    ModalLayer = NewObject<UGGraph>(this);\n    ModalLayer->SetSize(Size);\n    ModalLayer->DrawRect(0, FColor::White, FUIConfig::Config.ModalLayerColor);\n    ModalLayer->AddRelation(this, ERelationType::Size);\n}\n\nvoid UGRoot::AdjustModalLayer()\n{\n    if (ModalLayer == nullptr)\n        CreateModalLayer();\n\n    int32 cnt = NumChildren();\n\n    if (ModalWaitPane != nullptr && ModalWaitPane->GetParent() != nullptr)\n        SetChildIndex(ModalWaitPane, cnt - 1);\n\n    for (int32 i = cnt - 1; i >= 0; i--)\n    {\n        UGObject* child = GetChildAt(i);\n        if (child->IsA<UGWindow>() && ((UGWindow*)child)->IsModal())\n        {\n            if (ModalLayer->GetParent() == nullptr)\n                AddChildAt(ModalLayer, i);\n            else\n                SetChildIndexBefore(ModalLayer, i);\n            return;\n        }\n    }\n\n    if (ModalLayer->GetParent() != nullptr)\n        RemoveChild(ModalLayer);\n}\n\nbool UGRoot::HasModalWindow() const\n{\n    return ModalLayer != nullptr && ModalLayer->GetParent() != nullptr;\n}\n\nvoid UGRoot::ShowModalWait()\n{\n    GetModalWaitingPane();\n    if (ModalWaitPane)\n        AddChild(ModalWaitPane);\n}\n\nvoid UGRoot::CloseModalWait()\n{\n    if (ModalWaitPane != nullptr && ModalWaitPane->GetParent() != nullptr)\n        RemoveChild(ModalWaitPane);\n}\n\nUGObject* UGRoot::GetModalWaitingPane()\n{\n    if (!FUIConfig::Config.GlobalModalWaiting.IsEmpty())\n    {\n        if (ModalWaitPane == nullptr)\n        {\n            ModalWaitPane = UUIPackage::CreateObjectFromURL(FUIConfig::Config.GlobalModalWaiting, this);\n            ModalWaitPane->SetSortingOrder(INT_MAX);\n        }\n\n        ModalWaitPane->SetSize(GetSize());\n        ModalWaitPane->AddRelation(this, ERelationType::Size);\n\n        return ModalWaitPane;\n    }\n    else\n        return nullptr;\n}\n\nbool UGRoot::IsModalWaiting() const\n{\n    return (ModalWaitPane != nullptr) && ModalWaitPane->OnStage();\n}\n\nvoid UGRoot::ShowPopup(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction)\n{\n    if (PopupStack.Num() > 0)\n        HidePopup(Popup);\n\n    PopupStack.Add(Popup);\n\n    if (AtObject != nullptr)\n    {\n        UGObject* p = AtObject;\n        while (p != nullptr)\n        {\n            if (p->GetParent() == this)\n            {\n                if (Popup->GetSortingOrder() < p->GetSortingOrder())\n                {\n                    Popup->SetSortingOrder(p->GetSortingOrder());\n                }\n                break;\n            }\n            p = p->GetParent();\n        }\n    }\n\n    AddChild(Popup);\n    AdjustModalLayer();\n\n    if (Popup->IsA<UGWindow>() && AtObject == nullptr && Direction == EPopupDirection::Auto)\n        return;\n\n    FVector2D pos = GetPoupPosition(Popup, AtObject, Direction);\n    Popup->SetPosition(pos);\n}\n\nvoid UGRoot::TogglePopup(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction)\n{\n    int32 Index;\n    if (JustClosedPopups.Find(Popup, Index))\n        return;\n\n    ShowPopup(Popup, AtObject, Direction);\n}\n\nvoid UGRoot::HidePopup(UGObject* Popup)\n{\n    if (Popup != nullptr)\n    {\n        int32 k;\n        if (PopupStack.Find(Popup, k))\n        {\n            for (int32 i = PopupStack.Num() - 1; i >= k; i--)\n            {\n                ClosePopup(PopupStack.Last().Get());\n                PopupStack.Pop();\n            }\n        }\n    }\n    else\n    {\n        for (const auto& it : PopupStack)\n            ClosePopup(it.Get());\n        PopupStack.Reset();\n    }\n}\n\nvoid UGRoot::ClosePopup(UGObject* Popup)\n{\n    if (Popup != nullptr && Popup->GetParent() != nullptr)\n    {\n        if (Popup->IsA<UGWindow>())\n            ((UGWindow*)Popup)->Hide();\n        else\n            RemoveChild(Popup);\n    }\n}\n\nvoid UGRoot::CheckPopups(SWidget* ClickTarget)\n{\n    JustClosedPopups.Reset();\n    if (PopupStack.Num() > 0)\n    {\n        bool handled = false;\n        SWidget* Ptr = ClickTarget;\n        SWidget* Top = DisplayObject.Get();\n        while (Ptr != Top && Ptr != nullptr)\n        {\n            if (Ptr->GetTag() == SDisplayObject::SDisplayObjectTag)\n            {\n                UGObject* Obj = static_cast<SDisplayObject*>(Ptr)->GObject.Get();\n\n                int32 k;\n                if (PopupStack.Find(Obj, k))\n                {\n                    for (int32 i = PopupStack.Num() - 1; i > k; i--)\n                    {\n                        ClosePopup(PopupStack.Pop().Get());\n                    }\n                    handled = true;\n                    break;\n                }\n            }\n            Ptr = Ptr->GetParentWidget().Get();\n        }\n\n        if (!handled)\n        {\n            for (int32 i = PopupStack.Num() - 1; i >= 0; i--)\n            {\n                UGObject* popup = PopupStack[i].Get();\n                if (popup != nullptr)\n                {\n                    JustClosedPopups.Add(popup);\n                    ClosePopup(popup);\n                }\n            }\n            PopupStack.Reset();\n        }\n    }\n}\n\nbool UGRoot::HasAnyPopup() const\n{\n    return PopupStack.Num() > 0;\n}\n\nFVector2D UGRoot::GetPoupPosition(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction)\n{\n    FVector2D pos;\n    FVector2D size;\n    if (AtObject != nullptr)\n    {\n        pos = AtObject->LocalToGlobal(FVector2D::ZeroVector);\n        pos = this->GlobalToLocal(pos);\n        size = AtObject->LocalToGlobal(AtObject->GetSize());\n        size = this->GlobalToLocal(size);\n        size -= pos;\n    }\n    else\n    {\n        pos = GlobalToLocal(GetApp()->GetTouchPosition());\n    }\n    FVector2D RetPosition;\n    RetPosition.X = pos.X;\n    if (RetPosition.X + Popup->GetWidth() > GetWidth())\n        RetPosition.X += size.X - Popup->GetWidth();\n    RetPosition.Y = pos.Y + size.Y;\n    if ((Direction == EPopupDirection::Auto && RetPosition.Y + Popup->GetHeight() > GetHeight()) || Direction == EPopupDirection::Up)\n    {\n        RetPosition.Y = pos.Y - Popup->GetHeight() - 1;\n        if (RetPosition.Y < 0)\n        {\n            RetPosition.Y = 0;\n            RetPosition.X += size.X / 2;\n        }\n    }\n\n    return RetPosition.RoundToVector();\n}\n\nvoid UGRoot::ShowTooltips(const FString& Text)\n{\n    if (DefaultTooltipWin == nullptr)\n    {\n        const FString& resourceURL = FUIConfig::Config.TooltipsWin;\n        if (resourceURL.IsEmpty())\n        {\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"UIConfig.tooltipsWin not defined\"));\n            return;\n        }\n\n        DefaultTooltipWin = UUIPackage::CreateObjectFromURL(resourceURL, this);\n        DefaultTooltipWin->SetTouchable(false);\n    }\n\n    DefaultTooltipWin->SetText(Text);\n    ShowTooltipsWin(DefaultTooltipWin);\n}\n\nvoid UGRoot::ShowTooltipsWin(UGObject* InTooltipWin)\n{\n    HideTooltips();\n\n    TooltipWin = InTooltipWin;\n    GWorld->GetTimerManager().SetTimer(\n        ShowTooltipsTimerHandle,\n        FTimerDelegate::CreateUObject(this, &UGRoot::DoShowTooltipsWin),\n        0.1f,\n        false);\n}\n\nvoid UGRoot::DoShowTooltipsWin()\n{\n    if (TooltipWin == nullptr)\n        return;\n\n    FVector2D pt = GetApp()->GetTouchPosition();\n    FVector2D Pos = pt + FVector2D(10, 20);\n\n    Pos = GlobalToLocal(Pos);\n\n    if (Pos.X + TooltipWin->GetWidth() > GetWidth())\n        Pos.X -= TooltipWin->GetWidth();\n    if (Pos.Y + TooltipWin->GetHeight() > GetHeight())\n    {\n        Pos.Y -= TooltipWin->GetHeight() - 1;\n        if (Pos.Y < 0)\n            Pos.Y = 0;\n    }\n\n    TooltipWin->SetPosition(Pos.RoundToVector());\n    AddChild(TooltipWin);\n}\n\nvoid UGRoot::HideTooltips()\n{\n    if (TooltipWin != nullptr)\n    {\n        if (TooltipWin->GetParent() != nullptr)\n            RemoveChild(TooltipWin);\n        TooltipWin = nullptr;\n    }\n}\n\nvoid SRootContainer::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n    FVector2D LocalSize = AllottedGeometry.GetLocalSize().RoundToVector();\n    if (LocalSize != GObject->GetSize())\n    {\n        GObject->SetSize(LocalSize);\n        UE_LOG(LogFairyGUI, Log, TEXT(\"UIRoot resize to %f,%f\"), LocalSize.X, LocalSize.Y);\n    }\n\n    SContainer::OnArrangeChildren(AllottedGeometry, ArrangedChildren);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GScrollBar.cpp",
    "content": "#include \"UI/GScrollBar.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGScrollBar::UGScrollBar()\n{\n}\n\nUGScrollBar::~UGScrollBar()\n{\n}\n\n\nvoid UGScrollBar::SetScrollPane(UScrollPane* InTarget, bool bInVertical)\n{\n    Target = InTarget;\n    bVertical = bInVertical;\n}\n\nvoid UGScrollBar::SetDisplayPerc(float Value)\n{\n    if (bVertical)\n    {\n        if (!bFixedGripSize)\n            GripObject->SetHeight(FMath::FloorToFloat(Value * BarObject->GetHeight()));\n        GripObject->SetY(round(BarObject->GetY() + (BarObject->GetHeight() - GripObject->GetHeight()) * ScrollPerc));\n    }\n    else\n    {\n        if (!bFixedGripSize)\n            GripObject->SetWidth(FMath::FloorToFloat(Value * BarObject->GetWidth()));\n        GripObject->SetX(round(BarObject->GetX() + (BarObject->GetWidth() - GripObject->GetWidth()) * ScrollPerc));\n    }\n\n    GripObject->SetVisible(Value != 0 && Value != 1);\n}\n\nvoid UGScrollBar::SetScrollPerc(float Value)\n{\n    ScrollPerc = Value;\n    if (bVertical)\n        GripObject->SetY(round(BarObject->GetY() + (BarObject->GetHeight() - GripObject->GetHeight()) * ScrollPerc));\n    else\n        GripObject->SetX(round(BarObject->GetX() + (BarObject->GetWidth() - GripObject->GetWidth()) * ScrollPerc));\n}\n\nfloat UGScrollBar::GetMinSize()\n{\n    if (bVertical)\n        return (ArrowButton1 != nullptr ? ArrowButton1->GetHeight() : 0) + (ArrowButton2 != nullptr ? ArrowButton2->GetHeight() : 0);\n    else\n        return (ArrowButton1 != nullptr ? ArrowButton1->GetWidth() : 0) + (ArrowButton2 != nullptr ? ArrowButton2->GetWidth() : 0);\n}\n\nvoid UGScrollBar::ConstructExtension(FByteBuffer* buffer)\n{\n    buffer->Seek(0, 6);\n\n    bFixedGripSize = buffer->ReadBool();\n\n    GripObject = GetChild(\"grip\");\n    verifyf(GripObject != nullptr, TEXT(\"FairyGUI: should define grip\"));\n    BarObject = GetChild(\"bar\");\n    verifyf(BarObject != nullptr, TEXT(\"FairyGUI: should define bar\"));\n\n    ArrowButton1 = GetChild(\"arrow1\");\n    ArrowButton2 = GetChild(\"arrow2\");\n\n    GripObject->On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnGripTouchBegin);\n    GripObject->On(FUIEvents::TouchMove).AddUObject(this, &UGScrollBar::OnGripTouchMove);\n    GripObject->On(FUIEvents::TouchEnd).AddUObject(this, &UGScrollBar::OnGripTouchEnd);\n\n    On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnTouchBeginHandler);\n\n    if (ArrowButton1 != nullptr)\n        ArrowButton1->On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnArrowButton1Click);\n    if (ArrowButton2 != nullptr)\n        ArrowButton2->On(FUIEvents::TouchBegin).AddUObject(this, &UGScrollBar::OnArrowButton2Click);\n}\n\nvoid UGScrollBar::OnTouchBeginHandler(UEventContext* Context)\n{\n    Context->StopPropagation();\n\n    FVector2D pt = GripObject->GlobalToLocal(Context->GetPointerPosition());\n    if (bVertical)\n    {\n        if (pt.Y < 0)\n            Target->ScrollUp(4, false);\n        else\n            Target->ScrollDown(4, false);\n    }\n    else\n    {\n        if (pt.X < 0)\n            Target->ScrollLeft(4, false);\n        else\n            Target->ScrollRight(4, false);\n    }\n}\n\nvoid UGScrollBar::OnGripTouchBegin(UEventContext* Context)\n{\n    if (BarObject == nullptr)\n        return;\n\n    Context->StopPropagation();\n    Context->CaptureTouch();\n\n    bGripDragging = true;\n    Target->UpdateScrollBarVisible();\n\n    FVector2D pt = GlobalToLocal(Context->GetPointerPosition());\n    DragOffset = pt - GripObject->GetPosition();\n}\n\nvoid UGScrollBar::OnGripTouchMove(UEventContext* Context)\n{\n    FVector2D pt = GlobalToLocal(Context->GetPointerPosition());\n    if (bVertical)\n    {\n        float curY = pt.Y - DragOffset.Y;\n        float diff = BarObject->GetHeight() - GripObject->GetHeight();\n        if (diff == 0)\n            Target->SetPercY(0);\n        else\n            Target->SetPercY((curY - BarObject->GetY()) / diff);\n    }\n    else\n    {\n        float curX = pt.X - DragOffset.X;\n        float diff = BarObject->GetWidth() - GripObject->GetWidth();\n        if (diff == 0)\n            Target->SetPercX(0);\n        else\n            Target->SetPercX((curX - BarObject->GetX()) / diff);\n    }\n}\n\nvoid UGScrollBar::OnGripTouchEnd(UEventContext* Context)\n{\n    bGripDragging = false;\n    Target->UpdateScrollBarVisible();\n}\n\nvoid UGScrollBar::OnArrowButton1Click(UEventContext* Context)\n{\n    Context->StopPropagation();\n\n    if (bVertical)\n        Target->ScrollUp();\n    else\n        Target->ScrollLeft();\n}\n\nvoid UGScrollBar::OnArrowButton2Click(UEventContext* Context)\n{\n    Context->StopPropagation();\n\n    if (bVertical)\n        Target->ScrollDown();\n    else\n        Target->ScrollRight();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GSlider.cpp",
    "content": "#include \"UI/GSlider.h\"\n#include \"Utils/ByteBuffer.h\"\n\nUGSlider::UGSlider()\n{\n}\n\nUGSlider::~UGSlider()\n{\n}\n\nvoid UGSlider::SetTitleType(EProgressTitleType InTitleType)\n{\n    if (TitleType != InTitleType)\n    {\n        TitleType = InTitleType;\n        Update();\n    }\n}\n\nvoid UGSlider::SetMin(float InMin)\n{\n    if (Min != InMin)\n    {\n        Min = InMin;\n        Update();\n    }\n}\n\nvoid UGSlider::SetMax(float InMax)\n{\n    if (Max != InMax)\n    {\n        Max = InMax;\n        Update();\n    }\n}\n\nvoid UGSlider::SetValue(float InValue)\n{\n    if (Value != InValue)\n    {\n        Value = InValue;\n        Update();\n    }\n}\n\nvoid UGSlider::SetWholeNumbers(bool InFlag)\n{\n    if (bWholeNumbers != InFlag)\n    {\n        bWholeNumbers = InFlag;\n        Update();\n    }\n}\n\nvoid UGSlider::Update()\n{\n    float Percent = FMath::Min((float)(Value / Max), 1.f);\n    UpdateWithPercent(Percent, false);\n}\n\nvoid UGSlider::UpdateWithPercent(float Percent, bool bManual)\n{\n    Percent = FMath::Clamp(Percent, 0.f, 1.f);\n    if (bManual)\n    {\n        float newValue = Min + (Max - Min) * Percent;\n        if (newValue < Min)\n            newValue = Min;\n        if (newValue > Max)\n            newValue = Max;\n        if (bWholeNumbers)\n        {\n            newValue = round(newValue);\n            Percent = FMath::Clamp((float)((newValue - Min) / (Max - Min)), 0.f, 1.f);\n        }\n\n        if (newValue != Value)\n        {\n            Value = newValue;\n            if (DispatchEvent(FUIEvents::Changed))\n                return;\n        }\n    }\n\n    if (TitleObject != nullptr)\n    {\n        FString NewTitle;\n        switch (TitleType)\n        {\n        case EProgressTitleType::Percent:\n            NewTitle.AppendInt(FMath::FloorToInt(Percent * 100));\n            NewTitle.AppendChar('%');\n            break;\n\n        case EProgressTitleType::ValueMax:\n            NewTitle.AppendInt(FMath::FloorToInt(Value));\n            NewTitle.AppendChar('/');\n            NewTitle.AppendInt(FMath::FloorToInt(Max));\n            break;\n\n        case EProgressTitleType::Value:\n            NewTitle.AppendInt(FMath::FloorToInt(Value));\n            break;\n\n        case EProgressTitleType::Max:\n            NewTitle.AppendInt(FMath::FloorToInt(Max));\n            break;\n        default:\n            break;\n        }\n        TitleObject->SetText(NewTitle);\n    }\n\n    FVector2D FullSize = GetSize() - BarMaxSizeDelta;;\n    if (!bReverse)\n    {\n        if (BarObjectH != nullptr)\n            BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * Percent));\n\n        if (BarObjectV != nullptr)\n            BarObjectV->SetHeight(FMath::RoundToFloat(FullSize.Y * Percent));\n\n    }\n    else\n    {\n        if (BarObjectH != nullptr)\n        {\n            BarObjectH->SetWidth(FMath::RoundToFloat(FullSize.X * Percent));\n            BarObjectH->SetX(BarStartPosition.X + (FullSize.X - BarObjectH->GetWidth()));\n        }\n        if (BarObjectV != nullptr)\n        {\n            BarObjectV->SetHeight(round(FullSize.Y * Percent));\n            BarObjectV->SetY(BarStartPosition.Y + (FullSize.Y - BarObjectV->GetHeight()));\n        }\n    }\n}\n\nvoid UGSlider::HandleSizeChanged()\n{\n    UGComponent::HandleSizeChanged();\n\n    BarMaxSize = GetSize() - BarMaxSizeDelta;\n\n    if (!bUnderConstruct)\n        Update();\n}\n\nvoid UGSlider::ConstructExtension(FByteBuffer* Buffer)\n{\n    TitleType = (EProgressTitleType)Buffer->ReadByte();\n    bReverse = Buffer->ReadBool();\n    if (Buffer->Version >= 2)\n    {\n        bWholeNumbers = Buffer->ReadBool();\n        bChangeOnClick = Buffer->ReadBool();\n    }\n\n    TitleObject = GetChild(\"title\");\n    BarObjectH = GetChild(\"bar\");\n    BarObjectV = GetChild(\"bar_v\");\n    GripObject = GetChild(\"grip\");\n\n    if (BarObjectH != nullptr)\n    {\n        BarMaxSize.X = BarObjectH->GetWidth();\n        BarMaxSizeDelta.X = GetWidth() - BarMaxSize.X;\n        BarStartPosition.X = BarObjectH->GetX();\n    }\n    if (BarObjectV != nullptr)\n    {\n        BarMaxSize.Y = BarObjectV->GetHeight();\n        BarMaxSizeDelta.Y = GetHeight() - BarMaxSize.Y;\n        BarStartPosition.Y = BarObjectV->GetY();\n    }\n\n    if (GripObject != nullptr)\n    {\n        GripObject->On(FUIEvents::TouchBegin).AddUObject(this, &UGSlider::OnGripTouchBegin);\n        GripObject->On(FUIEvents::TouchMove).AddUObject(this, &UGSlider::OnGripTouchMove);\n    }\n\n    On(FUIEvents::TouchBegin).AddUObject(this, &UGSlider::OnTouchBeginHandler);\n}\n\nvoid UGSlider::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGComponent::SetupAfterAdd(Buffer, BeginPos);\n\n    if (!Buffer->Seek(BeginPos, 6))\n    {\n        Update();\n        return;\n    }\n\n    if ((EObjectType)Buffer->ReadByte() != PackageItem->ObjectType)\n    {\n        Update();\n        return;\n    }\n\n    Value = Buffer->ReadInt();\n    Max = Buffer->ReadInt();\n    if (Buffer->Version >= 2)\n        Min = Buffer->ReadInt();\n\n    Update();\n}\n\nvoid UGSlider::OnTouchBeginHandler(UEventContext* Context)\n{\n    if (!bChangeOnClick)\n        return;\n\n    if (Context->GetMouseButton() != EKeys::LeftMouseButton)\n        return;\n\n    FVector2D pt = GripObject->GlobalToLocal(Context->GetPointerPosition());\n    float percent = FMath::Clamp((float)((Value - Min) / (Max - Min)), 0.f, 1.f);\n    float delta = 0;\n    if (BarObjectH != nullptr)\n        delta = pt.X / BarMaxSize.X;\n    if (BarObjectV != nullptr)\n        delta = pt.Y / BarMaxSize.Y;\n    if (bReverse)\n        percent -= delta;\n    else\n        percent += delta;\n    UpdateWithPercent(percent, true);\n}\n\nvoid UGSlider::OnGripTouchBegin(UEventContext* Context)\n{\n    if (Context->GetMouseButton() != EKeys::LeftMouseButton)\n        return;\n\n    bCanDrag = true;\n    Context->StopPropagation();\n    Context->CaptureTouch();\n\n    ClickPos = GlobalToLocal(Context->GetPointerPosition());\n    ClickPercent = FMath::Clamp((float)((Value - Min) / (Max - Min)), 0.f, 1.f);\n}\n\nvoid UGSlider::OnGripTouchMove(UEventContext* Context)\n{\n    if (!bCanDrag)\n        return;\n\n    FVector2D pt = GlobalToLocal(Context->GetPointerPosition());\n    FVector2D delta = pt - ClickPos;\n    if (bReverse)\n    {\n        delta.X = -delta.X;\n        delta.Y = -delta.Y;\n    }\n\n    float percent;\n    if (BarObjectH != nullptr)\n        percent = ClickPercent + delta.X / BarMaxSize.X;\n    else\n        percent = ClickPercent + delta.Y / BarMaxSize.Y;\n    UpdateWithPercent(percent, true);\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GTextField.cpp",
    "content": "#include \"UI/GTextField.h\"\n#include \"UI/GRichTextField.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Utils/UBBParser.h\"\n#include \"Widgets/STextField.h\"\n\nUGTextField::UGTextField()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        DisplayObject = Content = SNew(STextField).GObject(this);\n        bSupportHTML = IsA<UGRichTextField>();\n        DisplayObject->SetInteractable(bSupportHTML);\n    }\n}\n\nUGTextField::~UGTextField()\n{\n}\n\nvoid UGTextField::SetText(const FString& InText)\n{\n    if (!bFormatApplied)\n        ApplyFormat();\n    Text = InText;\n\n    if (bUBBEnabled)\n    {\n        FString parsedText = FUBBParser::DefaultParser.Parse(Text);\n        if (TemplateVars.IsSet())\n            parsedText = ParseTemplate(parsedText);\n        Content->SetText(parsedText, true);\n    }\n    else\n    {\n        if (TemplateVars.IsSet())\n            Content->SetText(ParseTemplate(Text), bSupportHTML);\n        else\n            Content->SetText(Text, bSupportHTML);\n    }\n    Content->SetMaxWidth(MaxSize.X);\n\n    UpdateSize();\n    UpdateGear(6);\n}\n\nvoid UGTextField::SetUBBEnabled(bool bFlag)\n{\n    if (bUBBEnabled != bFlag)\n    {\n        bUBBEnabled = bFlag;\n        SetText(Text);\n    }\n}\n\nEAutoSizeType UGTextField::GetAutoSize() const\n{\n    return Content->GetAutoSize();\n}\n\nvoid UGTextField::SetAutoSize(EAutoSizeType InAutoSize)\n{\n    Content->SetAutoSize(InAutoSize);\n}\n\nbool UGTextField::IsSingleLine() const\n{\n    return Content->IsSingleLine();\n}\n\nvoid UGTextField::SetSingleLine(bool bFlag)\n{\n    Content->SetSingleLine(bFlag);\n}\n\nFNTextFormat& UGTextField::GetTextFormat()\n{\n    return Content->GetTextFormat();\n}\n\nvoid UGTextField::SetTextFormat(const FNTextFormat& InTextFormat)\n{\n    Content->SetTextFormat(InTextFormat);\n    bFormatApplied = true;\n\n    UpdateGear(4);\n}\n\nvoid UGTextField::ApplyFormat()\n{\n    SetTextFormat(Content->GetTextFormat());\n}\n\nFVector2D UGTextField::GetTextSize()\n{\n    return Content->GetTextSize();\n}\n\nvoid UGTextField::UpdateSize()\n{\n    if (Content->GetAutoSize() == EAutoSizeType::Both || Content->GetAutoSize() == EAutoSizeType::Height)\n        Content->GetTextSize(); //force text layout update\n}\n\nUGTextField* UGTextField::SetVar(const FString& VarKey, const FString& VarValue)\n{\n    if (!TemplateVars.IsSet())\n        TemplateVars.Emplace();\n    TemplateVars.GetValue().Add(VarKey, VarValue);\n\n    return this;\n}\n\nvoid UGTextField::FlushVars()\n{\n    SetText(Text);\n}\n\nFString UGTextField::ParseTemplate(const FString& Template)\n{\n    int32 pos1 = 0, pos2 = 0;\n    int32 pos3;\n    FString tag;\n    FString value;\n    FString buffer;\n    TMap<FString, FString>& Vars = TemplateVars.GetValue();\n\n    while ((pos2 = Template.Find(\"{\", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1)) != -1)\n    {\n        if (pos2 > 0 && Template[pos2 - 1] == '\\\\')\n        {\n            buffer.Append(*Template + pos1, pos2 - pos1 - 1);\n            buffer.AppendChar('{');\n            pos1 = pos2 + 1;\n            continue;\n        }\n\n        buffer.Append(*Template + pos1, pos2 - pos1);\n        pos1 = pos2;\n        pos2 = Template.Find(\"}\", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1);\n        if (pos2 == -1)\n            break;\n\n        if (pos2 == pos1 + 1)\n        {\n            buffer.Append(*Template + pos1, 2);\n            pos1 = pos2 + 1;\n            continue;\n        }\n\n        tag = Template.Mid(pos1 + 1, pos2 - pos1 - 1);\n        if (tag.FindChar('=', pos3))\n        {\n            FString* ptr = Vars.Find(tag.Mid(0, pos3));\n            if (ptr != nullptr)\n                buffer.Append(*ptr);\n            else\n                buffer.Append(tag.Mid(pos3 + 1));\n        }\n        else\n        {\n            FString* ptr = Vars.Find(tag);\n            if (ptr != nullptr)\n                buffer.Append(*ptr);\n        }\n        pos1 = pos2 + 1;\n    }\n    if (pos1 < Template.Len())\n        buffer.Append(Template.Mid(pos1, Template.Len() - pos1));\n\n    return buffer;\n}\n\nFNVariant UGTextField::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(Content->GetTextFormat().Color);\n    case EObjectPropID::OutlineColor:\n        return FNVariant(Content->GetTextFormat().OutlineColor);\n    case EObjectPropID::FontSize:\n        return FNVariant(Content->GetTextFormat().Size);\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGTextField::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        Content->GetTextFormat().Color = InValue.AsColor();\n        ApplyFormat();\n        break;\n    case EObjectPropID::OutlineColor:\n        Content->GetTextFormat().OutlineColor = InValue.AsColor();\n        ApplyFormat();\n        break;\n    case EObjectPropID::FontSize:\n        Content->GetTextFormat().Size = InValue.AsInt();\n        ApplyFormat();\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGTextField::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    FNTextFormat& TextFormat = Content->GetTextFormat();\n    TextFormat.Face = Buffer->ReadS();\n    TextFormat.Size = Buffer->ReadShort();\n    TextFormat.Color = Buffer->ReadColor();\n    TextFormat.Align = (EAlignType)Buffer->ReadByte();\n    TextFormat.VerticalAlign = (EVerticalAlignType)Buffer->ReadByte();\n    TextFormat.LineSpacing = Buffer->ReadShort();\n    TextFormat.LetterSpacing = Buffer->ReadShort();\n    bUBBEnabled = Buffer->ReadBool();\n    SetAutoSize((EAutoSizeType)Buffer->ReadByte());\n    TextFormat.bUnderline = Buffer->ReadBool();\n    TextFormat.bItalic = Buffer->ReadBool();\n    TextFormat.bBold = Buffer->ReadBool();\n    if (Buffer->ReadBool())\n        SetSingleLine(true);\n    if (Buffer->ReadBool())\n    {\n        TextFormat.OutlineColor = Buffer->ReadColor();\n        TextFormat.OutlineSize = Buffer->ReadFloat();\n    }\n\n    if (Buffer->ReadBool())\n    {\n        TextFormat.ShadowColor = Buffer->ReadColor();\n        float f1 = Buffer->ReadFloat();\n        float f2 = Buffer->ReadFloat();\n        TextFormat.ShadowOffset = FVector2D(f1, f2);\n    }\n\n    if (Buffer->ReadBool())\n        TemplateVars.Emplace();\n}\n\nvoid UGTextField::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupAfterAdd(Buffer, BeginPos);\n\n    ApplyFormat();\n\n    Buffer->Seek(BeginPos, 6);\n\n    const FString& str = Buffer->ReadS();\n    if (!str.IsEmpty())\n        SetText(str);\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GTextInput.cpp",
    "content": "#include \"UI/GTextInput.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Utils/UBBParser.h\"\n#include \"Widgets/STextInput.h\"\n\nUGTextInput::UGTextInput()\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        DisplayObject = Content = SNew(STextInput).GObject(this);\n        Content->SetOnTextChanged(FOnTextChanged::CreateLambda([this](const FText& InText) {\n            Text = InText.ToString();\n        }));\n        Content->SetOnTextCommitted(FOnTextCommitted::CreateLambda([this](const FText& InText, ETextCommit::Type InType) {\n            if (InType == ETextCommit::OnEnter)\n                DispatchEvent(FUIEvents::Submit);\n        }));\n    }\n}\n\nUGTextInput::~UGTextInput()\n{\n\n}\n\nTSharedRef<SMultiLineEditableText> UGTextInput::GetInputWidget() const\n{\n    return StaticCastSharedRef<SMultiLineEditableText>(Content->Widget);\n}\n\nvoid UGTextInput::SetText(const FString& InText)\n{\n    Content->Widget->SetText(FText::FromString(InText));\n}\n\nbool UGTextInput::IsSingleLine() const\n{\n    return false;\n}\n\nvoid UGTextInput::SetSingleLine(bool bFlag)\n{\n    Content->SetSingleLine(bFlag);\n}\n\nvoid UGTextInput::SetTextFormat(const FNTextFormat& InTextFormat)\n{\n    Content->SetTextFormat(InTextFormat);\n}\n\nvoid UGTextInput::ApplyFormat()\n{\n    Content->SetTextFormat(TextFormat);\n}\n\nvoid UGTextInput::SetPrompt(const FString& InPrompt)\n{\n    Content->Widget->SetHintText(FText::FromString(FUBBParser::DefaultParser.Parse(InPrompt, true)));\n}\n\nvoid UGTextInput::SetPassword(bool bInPassword)\n{\n    Content->SetPassword(bInPassword);\n}\n\nvoid UGTextInput::SetKeyboardType(int32 InKeyboardType)\n{\n\n}\n\nvoid UGTextInput::SetMaxLength(int32 InMaxLength)\n{\n}\n\nvoid UGTextInput::SetRestrict(const FString& InRestrict)\n{\n\n}\n\nvoid UGTextInput::NotifyTextChanged(const FText& InText)\n{\n    Text = InText.ToString();\n}\n\nFNVariant UGTextInput::GetProp(EObjectPropID PropID) const\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        return FNVariant(TextFormat.Color);\n    case EObjectPropID::OutlineColor:\n        return FNVariant(TextFormat.OutlineColor);\n    case EObjectPropID::FontSize:\n        return FNVariant(TextFormat.Size);\n    default:\n        return UGObject::GetProp(PropID);\n    }\n}\n\nvoid UGTextInput::SetProp(EObjectPropID PropID, const FNVariant& InValue)\n{\n    switch (PropID)\n    {\n    case EObjectPropID::Color:\n        TextFormat.Color = InValue.AsColor();\n        ApplyFormat();\n        break;\n    case EObjectPropID::OutlineColor:\n        TextFormat.OutlineColor = InValue.AsColor();\n        ApplyFormat();\n        break;\n    case EObjectPropID::FontSize:\n        TextFormat.Size = InValue.AsInt();\n        ApplyFormat();\n        break;\n    default:\n        UGObject::SetProp(PropID, InValue);\n        break;\n    }\n}\n\nvoid UGTextInput::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 5);\n\n    TextFormat.Face = Buffer->ReadS();\n    TextFormat.Size = Buffer->ReadShort();\n    TextFormat.Color = Buffer->ReadColor();\n    TextFormat.Align = (EAlignType)Buffer->ReadByte();\n    TextFormat.VerticalAlign = (EVerticalAlignType)Buffer->ReadByte();\n    TextFormat.LineSpacing = Buffer->ReadShort();\n    TextFormat.LetterSpacing = Buffer->ReadShort();\n    Buffer->ReadBool(); //bUBBEnabled\n    Buffer->ReadByte(); //AutoSize\n    TextFormat.bUnderline = Buffer->ReadBool();\n    TextFormat.bItalic = Buffer->ReadBool();\n    TextFormat.bBold = Buffer->ReadBool();\n    if (Buffer->ReadBool())\n        SetSingleLine(true);\n    if (Buffer->ReadBool())\n    {\n        TextFormat.OutlineColor = Buffer->ReadColor();\n        TextFormat.OutlineSize = Buffer->ReadFloat();\n    }\n\n    if (Buffer->ReadBool())\n    {\n        TextFormat.ShadowColor = Buffer->ReadColor();\n        float f1 = Buffer->ReadFloat();\n        float f2 = Buffer->ReadFloat();\n        TextFormat.ShadowOffset = FVector2D(f1, -f2);\n    }\n\n    Buffer->ReadBool(); //TemplateVars;\n\n    Buffer->Seek(BeginPos, 4);\n\n    const FString* str;\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetPrompt(*str);\n\n    if ((str = Buffer->ReadSP()) != nullptr)\n        SetRestrict(*str);\n\n    int32 iv = Buffer->ReadInt();\n    if (iv != 0)\n        SetMaxLength(iv);\n    iv = Buffer->ReadInt();\n    if (iv != 0)\n        SetKeyboardType(iv);\n    if (Buffer->ReadBool())\n        SetPassword(true);\n}\n\nvoid UGTextInput::SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    UGObject::SetupAfterAdd(Buffer, BeginPos);\n\n    ApplyFormat();\n\n    Buffer->Seek(BeginPos, 6);\n\n    const FString& str = Buffer->ReadS();\n    SetText(str);\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GTree.cpp",
    "content": "#include \"UI/GTree.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"UI/GController.h\"\n#include \"UI/GObjectPool.h\"\n\nUGTree::UGTree() :\n    Indent(30)\n{\n    if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))\n    {\n        RootNode = UGTreeNode::CreateNode(true);\n        RootNode->SetTree(this);\n        RootNode->SetExpaned(true);\n    }\n}\n\nUGTree::~UGTree()\n{\n}\n\nUGTreeNode* UGTree::GetSelectedNode() const\n{\n    int32 i = GetSelectedIndex();\n    if (i != -1)\n        return GetChildAt(i)->TreeNode;\n    else\n        return nullptr;\n}\n\nvoid UGTree::GetSelectedNodes(TArray<UGTreeNode*>& Result) const\n{\n    TArray<int32> ids;\n    GetSelection(ids);\n    for (auto& it : ids)\n    {\n        UGTreeNode* Node = GetChildAt(it)->TreeNode;\n        Result.Add(Node);\n    }\n}\n\nvoid UGTree::SelectNode(UGTreeNode* Node, bool bScrollItToView)\n{\n    UGTreeNode* ParentNode = Node->Parent.Get();\n    while (ParentNode != nullptr && ParentNode != RootNode)\n    {\n        ParentNode->SetExpaned(true);\n        ParentNode = ParentNode->GetParent();\n    }\n    if (Node->Cell != nullptr)\n        AddSelection(GetChildIndex(Node->Cell), bScrollItToView);\n}\n\nvoid UGTree::UnselectNode(UGTreeNode* Node)\n{\n    if (Node->Cell != nullptr)\n        RemoveSelection(GetChildIndex(Node->Cell));\n}\n\nvoid UGTree::ExpandAll(UGTreeNode* FolderNode)\n{\n    FolderNode->SetExpaned(true);\n    for (auto& it : FolderNode->Children)\n    {\n        if (it->IsFolder())\n            ExpandAll(it);\n    }\n}\n\nvoid UGTree::CollapseAll(UGTreeNode* FolderNode)\n{\n    if (FolderNode != RootNode)\n        FolderNode->SetExpaned(false);\n    for (auto& it : FolderNode->Children)\n    {\n        if (it->IsFolder())\n            CollapseAll(it);\n    }\n}\n\nvoid UGTree::CreateCell(UGTreeNode* Node)\n{\n    const FString& url = Node->ResourceURL.IsEmpty() ? GetDefaultItem() : Node->ResourceURL;\n    UGComponent* Child = GetItemPool()->GetObject(url, this)->As<UGComponent>();\n    verifyf(Child != nullptr, TEXT(\"Unable to create tree cell\"));\n\n    Child->TreeNode = Node;\n    Node->Cell = Child;\n\n    UGObject* IndentObj = Node->Cell->GetChild(\"indent\");\n    if (IndentObj != nullptr)\n        IndentObj->SetWidth((Node->Level - 1) * Indent);\n\n    UGController* cc;\n\n    cc = Child->GetController(\"expanded\");\n    if (cc != nullptr)\n    {\n        cc->OnChanged().AddUObject(this, &UGTree::OnExpandedStateChanged);\n        cc->SetSelectedIndex(Node->IsExpanded() ? 1 : 0);\n    }\n\n    cc = Child->GetController(\"leaf\");\n    if (cc != nullptr)\n        cc->SetSelectedIndex(Node->IsFolder() ? 0 : 1);\n\n    if (Node->IsFolder())\n        Child->OnTouchBegin.AddUniqueDynamic(this, &UGTree::OnCellTouchBegin);\n\n    TreeNodeRenderer.ExecuteIfBound(Node, Child);\n}\n\nvoid UGTree::AfterInserted(UGTreeNode* Node)\n{\n    if (Node->Cell == nullptr)\n        CreateCell(Node);\n\n    int32 Index = GetInsertIndexForNode(Node);\n    AddChildAt(Node->Cell, Index);\n    TreeNodeRenderer.ExecuteIfBound(Node, Node->Cell);\n\n    if (Node->IsFolder() && Node->IsExpanded())\n        CheckChildren(Node, Index);\n}\n\nint32 UGTree::GetInsertIndexForNode(UGTreeNode* Node)\n{\n    UGTreeNode* PrevNode = Node->GetPrevSibling();\n    if (PrevNode == nullptr)\n        PrevNode = Node->GetParent();\n    int32 InsertIndex;\n    if (PrevNode->Cell != nullptr)\n        InsertIndex = GetChildIndex(PrevNode->Cell) + 1;\n    else\n        InsertIndex = 0;\n    int32 myLevel = Node->Level;\n    int32 cnt = NumChildren();\n    for (int32 i = InsertIndex; i < cnt; i++)\n    {\n        UGTreeNode* TestNode = GetChildAt(i)->TreeNode;\n        if (TestNode->Level <= myLevel)\n            break;\n\n        InsertIndex++;\n    }\n\n    return InsertIndex;\n}\n\nvoid UGTree::AfterRemoved(UGTreeNode* Node)\n{\n    RemoveNode(Node);\n}\n\nvoid UGTree::AfterExpanded(UGTreeNode* Node)\n{\n    if (Node == RootNode)\n    {\n        CheckChildren(RootNode, 0);\n        return;\n    }\n\n    OnTreeNodeWillExpand.ExecuteIfBound(Node, true);\n\n    if (Node->Cell == nullptr)\n        return;\n\n    TreeNodeRenderer.ExecuteIfBound(Node, Node->Cell);\n\n    UGController* cc = Node->Cell->GetController(\"expanded\");\n    if (cc != nullptr)\n        cc->SetSelectedIndex(1);\n\n    if (Node->Cell->GetParent() != nullptr)\n        CheckChildren(Node, GetChildIndex(Node->Cell));\n}\n\nvoid UGTree::AfterCollapsed(UGTreeNode* Node)\n{\n    if (Node == RootNode)\n    {\n        CheckChildren(RootNode, 0);\n        return;\n    }\n\n    OnTreeNodeWillExpand.ExecuteIfBound(Node, false);\n\n    if (Node->Cell == nullptr)\n        return;\n\n    TreeNodeRenderer.ExecuteIfBound(Node, Node->Cell);\n\n    UGController* cc = Node->Cell->GetController(\"expanded\");\n    if (cc != nullptr)\n        cc->SetSelectedIndex(0);\n\n    if (Node->Cell->GetParent() != nullptr)\n        HideFolderNode(Node);\n}\n\nvoid UGTree::AfterMoved(UGTreeNode* Node)\n{\n    int32 startIndex = GetChildIndex(Node->Cell);\n    int32 endIndex;\n    if (Node->IsFolder())\n        endIndex = GetFolderEndIndex(startIndex, Node->Level);\n    else\n        endIndex = startIndex + 1;\n    int32 insertIndex = GetInsertIndexForNode(Node);\n    int32 cnt = endIndex - startIndex;\n\n    if (insertIndex < startIndex)\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* obj = GetChildAt(startIndex + i);\n            SetChildIndex(obj, insertIndex + i);\n        }\n    }\n    else\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGObject* obj = GetChildAt(startIndex);\n            SetChildIndex(obj, insertIndex);\n        }\n    }\n}\n\nint32 UGTree::GetFolderEndIndex(int32 StartIndex, int32 Level)\n{\n    int32 cnt = NumChildren();\n    for (int32 i = StartIndex + 1; i < cnt; i++)\n    {\n        UGTreeNode* Node = GetChildAt(i)->TreeNode;\n        if (Node->Level <= Level)\n            return i;\n    }\n\n    return cnt;\n}\n\nint32 UGTree::CheckChildren(UGTreeNode* FolderNode, int32 Index)\n{\n    int32 cnt = FolderNode->NumChildren();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        Index++;\n        UGTreeNode* Node = FolderNode->GetChildAt(i);\n        if (Node->Cell == nullptr)\n            CreateCell(Node);\n\n        if (Node->Cell->GetParent() == nullptr)\n            AddChildAt(Node->Cell, Index);\n\n        if (Node->IsFolder() && Node->IsExpanded())\n            Index = CheckChildren(Node, Index);\n    }\n\n    return Index;\n}\n\nvoid UGTree::HideFolderNode(UGTreeNode* FolderNode)\n{\n    int32 cnt = FolderNode->NumChildren();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        UGTreeNode* Node = FolderNode->GetChildAt(i);\n        if (Node->Cell != nullptr && Node->Cell->GetParent() != nullptr)\n            RemoveChild(Node->Cell);\n\n        if (Node->IsFolder() && Node->IsExpanded())\n            HideFolderNode(Node);\n    }\n}\n\nvoid UGTree::RemoveNode(UGTreeNode* Node)\n{\n    if (Node->Cell != nullptr)\n    {\n        if (Node->Cell->GetParent() != nullptr)\n            RemoveChild(Node->Cell);\n        GetItemPool()->ReturnObject(Node->Cell);\n        Node->Cell->TreeNode = nullptr;\n        Node->Cell = nullptr;\n    }\n\n    if (Node->IsFolder())\n    {\n        int32 cnt = Node->NumChildren();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            UGTreeNode* Node2 = Node->GetChildAt(i);\n            RemoveNode(Node2);\n        }\n    }\n}\n\nvoid UGTree::OnCellTouchBegin(UEventContext* Context)\n{\n    UGTreeNode* Node = Context->GetSender()->TreeNode;\n    bExpandedStatusInEvt = Node->IsExpanded();\n}\n\nvoid UGTree::OnExpandedStateChanged(UGController* Controller)\n{\n    UGTreeNode* Node = Cast<UGObject>(Controller->GetOuter())->TreeNode;\n    Node->SetExpaned(Controller->GetSelectedIndex() == 1);\n}\n\nvoid UGTree::DispatchItemEvent(UGObject* Obj, UEventContext* Context)\n{\n    if (ClickToExpand != 0)\n    {\n        UGTreeNode* Node = Obj->TreeNode;\n        if (Node != nullptr && bExpandedStatusInEvt == Node->IsExpanded())\n        {\n            if (ClickToExpand == 2)\n            {\n                if (Context->IsDoubleClick())\n                    Node->SetExpaned(!Node->IsExpanded());\n            }\n            else\n                Node->SetExpaned(!Node->IsExpanded());\n        }\n    }\n\n    Super::DispatchItemEvent(Obj, Context);\n}\n\nvoid UGTree::SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos)\n{\n    Super::SetupBeforeAdd(Buffer, BeginPos);\n\n    Buffer->Seek(BeginPos, 9);\n\n    Indent = Buffer->ReadInt();\n    ClickToExpand = Buffer->ReadByte();\n}\n\nvoid UGTree::ReadItems(FByteBuffer* Buffer)\n{\n    int32 nextPos;\n    FString str;\n    bool bIsFolder;\n    UGTreeNode* lastNode = nullptr;\n    int32 level;\n    int32 prevLevel = 0;\n\n    int32 cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        str = Buffer->ReadS();\n        if (!str.IsEmpty())\n        {\n            str = GetDefaultItem();\n            if (str.IsEmpty())\n            {\n                Buffer->SetPos(nextPos);\n                continue;\n            }\n        }\n\n        bIsFolder = Buffer->ReadBool();\n        level = Buffer->ReadByte();\n\n        UGTreeNode* node = UGTreeNode::CreateNode(bIsFolder, str);\n        node->SetExpaned(true);\n        if (i == 0)\n            RootNode->AddChild(node);\n        else\n        {\n            if (level > prevLevel)\n                lastNode->AddChild(node);\n            else if (level < prevLevel)\n            {\n                for (int32 j = level; j <= prevLevel; j++)\n                    lastNode = lastNode->GetParent();\n                lastNode->AddChild(node);\n            }\n            else\n                lastNode->GetParent()->AddChild(node);\n        }\n        lastNode = node;\n        prevLevel = level;\n\n        SetupItem(Buffer, node->Cell);\n\n        Buffer->SetPos(nextPos);\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GTreeNode.cpp",
    "content": "#include \"UI/GTreeNode.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/GTree.h\"\n\nUGTreeNode* UGTreeNode::CreateNode(bool bIsFolder, const FString& ResourceURL)\n{\n    UGTreeNode* Node = NewObject<UGTreeNode>();\n    Node->bIsFolder = bIsFolder;\n    Node->ResourceURL = ResourceURL;\n\n    return Node;\n}\n\nUGTreeNode::UGTreeNode()\n{\n}\n\nUGTreeNode::~UGTreeNode()\n{\n}\n\nvoid UGTreeNode::SetParent(UGTreeNode* InParent)\n{\n    verifyf(InParent == nullptr || InParent->IsFolder(), TEXT(\"Parent must be a folder node\"));\n    verifyf(InParent != this, TEXT(\"Parent must not be self\"));\n\n    if (InParent != nullptr)\n        InParent->AddChild(this);\n    else if (Parent.IsValid())\n        Parent->RemoveChild(this);\n}\n\nvoid UGTreeNode::SetExpaned(bool bInExpanded)\n{\n    if (!bIsFolder)\n        return;\n\n    if (bExpanded != bInExpanded)\n    {\n        bExpanded = bInExpanded;\n        if (Tree.IsValid())\n        {\n            if (bExpanded)\n                Tree->AfterExpanded(this);\n            else\n                Tree->AfterCollapsed(this);\n        }\n    }\n}\n\nconst FString& UGTreeNode::GetText() const\n{\n    if (Cell != nullptr)\n        return Cell->GetText();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGTreeNode::SetText(const FString& InText)\n{\n    if (Cell != nullptr)\n        return Cell->SetText(InText);\n}\n\nconst FString& UGTreeNode::GetIcon() const\n{\n    if (Cell != nullptr)\n        return Cell->GetIcon();\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UGTreeNode::SetIcon(const FString& InIcon)\n{\n    if (Cell != nullptr)\n        return Cell->SetIcon(InIcon);\n}\n\nUGTreeNode* UGTreeNode::AddChild(UGTreeNode* Child)\n{\n    AddChildAt(Child, Children.Num());\n    return Child;\n}\n\nUGTreeNode* UGTreeNode::AddChildAt(UGTreeNode* Child, int32 Index)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    if (Child->Parent == this)\n    {\n        SetChildIndex(Child, Index);\n    }\n    else\n    {\n        if (Child->Parent.IsValid())\n            Child->Parent->RemoveChild(Child);\n        Child->Parent = this;\n\n        int32 cnt = Children.Num();\n        if (Index == cnt)\n            Children.Add(Child);\n        else\n            Children.Insert(Child, Index);\n\n        Child->Level = Level + 1;\n        Child->SetTree(Tree.Get());\n        if ((Tree.IsValid() && this == Tree->GetRootNode()) || (Cell != nullptr && Cell->GetParent() != nullptr && bExpanded))\n            Tree->AfterInserted(Child);\n    }\n    return Child;\n}\n\nvoid UGTreeNode::RemoveChild(UGTreeNode* Child)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    int32 ChildIndex = Children.Find(Child);\n    if (ChildIndex != INDEX_NONE)\n        RemoveChildAt(ChildIndex);\n}\n\nvoid UGTreeNode::RemoveChildAt(int32 Index)\n{\n    verifyf(Index >= 0 && Index < Children.Num(), TEXT(\"Invalid child index\"));\n\n    UGTreeNode* Child = Children[Index];\n    Child->Parent = nullptr;\n\n    if (Tree.IsValid())\n    {\n        Child->SetTree(nullptr);\n        Tree->AfterRemoved(Child);\n    }\n\n    Children.RemoveAt(Index);\n}\n\nvoid UGTreeNode::RemoveChildren(int32 BeginIndex, int32 EndIndex)\n{\n    if (EndIndex < 0 || EndIndex >= Children.Num())\n        EndIndex = Children.Num() - 1;\n\n    for (int32 i = BeginIndex; i <= EndIndex; ++i)\n        RemoveChildAt(BeginIndex);\n}\n\nUGTreeNode* UGTreeNode::GetChildAt(int32 Index) const\n{\n    verifyf(Index >= 0 && Index < Children.Num(), TEXT(\"Invalid child index\"));\n\n    return Children[Index];\n}\n\nUGTreeNode* UGTreeNode::GetPrevSibling() const\n{\n    if (!Parent.IsValid())\n        return nullptr;\n\n    int32 i = Parent->Children.IndexOfByKey(this);\n    if (i <= 0)\n        return nullptr;\n\n    return Parent->Children[i - 1];\n}\n\nUGTreeNode* UGTreeNode::GetNextSibling() const\n{\n    if (!Parent.IsValid())\n        return nullptr;\n\n    int32 i = Parent->Children.IndexOfByKey(this);\n    if (i < 0 || i >= Parent->Children.Num() - 1)\n        return nullptr;\n\n    return Parent->Children[i + 1];\n}\n\nint32 UGTreeNode::GetChildIndex(const UGTreeNode* Child) const\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    return Children.IndexOfByKey(Child);\n}\n\nvoid UGTreeNode::SetChildIndex(UGTreeNode* Child, int32 Index)\n{\n    verifyf(Child != nullptr, TEXT(\"Argument must be non-nil\"));\n\n    int32 OldIndex = Children.Find(Child);\n    verifyf(OldIndex != -1, TEXT(\"Not a child of this container\"));\n\n    int32 cnt = Children.Num();\n    if (Index < 0)\n        Index = 0;\n    else if (Index > cnt)\n        Index = cnt;\n\n    if (OldIndex == Index)\n        return;\n\n    Children.RemoveAt(OldIndex);\n    Children.Insert(Child, Index);\n    if ((Tree.IsValid() && this == Tree->RootNode) || (Cell != nullptr && Cell->GetParent() != nullptr && bExpanded))\n        Tree->AfterMoved(Child);\n}\n\nvoid UGTreeNode::SwapChildren(UGTreeNode* Child1, UGTreeNode* Child2)\n{\n    int32 Index1 = Children.Find(Child1);\n    int32 Index2 = Children.Find(Child2);\n\n    verifyf(Index1 != -1, TEXT(\"Not a child of this container\"));\n    verifyf(Index2 != -1, TEXT(\"Not a child of this container\"));\n\n    SwapChildrenAt(Index1, Index2);\n}\n\nvoid UGTreeNode::SwapChildrenAt(int32 Index1, int32 Index2)\n{\n    UGTreeNode* Child1 = Children[Index1];\n    UGTreeNode* Child2 = Children[Index2];\n\n    SetChildIndex(Child1, Index2);\n    SetChildIndex(Child2, Index1);\n}\n\nint32 UGTreeNode::NumChildren() const\n{\n    return Children.Num();\n}\n\nvoid UGTreeNode::SetTree(UGTree* InTree)\n{\n    Tree = InTree;\n    if (Tree.IsValid() && Tree->OnTreeNodeWillExpand.IsBound() && bExpanded)\n        Tree->OnTreeNodeWillExpand.Execute(this, true);\n\n    if (bIsFolder)\n    {\n        for (auto& Child : Children)\n        {\n            Child->Level = Level + 1;\n            Child->SetTree(InTree);\n        }\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/GWindow.cpp",
    "content": "#include \"UI/GWindow.h\"\n#include \"UI/GGraph.h\"\n#include \"UI/GRoot.h\"\n#include \"UI/UIPackage.h\"\n\nUGWindow* UGWindow::CreateWindow(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject)\n{\n    UGObject* ContentPane = UUIPackage::CreateObject(PackageName, ResourceName, WorldContextObject);\n    verifyf(ContentPane->IsA<UGComponent>(), TEXT(\"Window content should be a component\"));\n    UGWindow* Window = NewObject<UGWindow>(WorldContextObject);\n    Window->SetContentPane(Cast<UGComponent>(ContentPane));\n\n    return Window;\n}\n\nUGWindow::UGWindow()\n{\n    bBringToFontOnClick = FUIConfig::Config.BringWindowToFrontOnClick;\n\n    On(FUIEvents::AddedToStage).AddUObject(this, &UGWindow::OnAddedToStageHandler);\n    On(FUIEvents::RemovedFromStage).AddUObject(this, &UGWindow::OnRemovedFromStageHandler);\n    On(FUIEvents::TouchBegin).AddUObject(this, &UGWindow::OnTouchBeginHandler);\n}\n\nUGWindow::~UGWindow()\n{\n}\n\nvoid UGWindow::SetContentPane(UGComponent* Obj)\n{\n    if (ContentPane != Obj)\n    {\n        if (ContentPane != nullptr)\n        {\n            RemoveChild(ContentPane);\n\n            FrameObject = nullptr;\n        }\n        ContentPane = Obj;\n        if (ContentPane != nullptr)\n        {\n            AddChild(ContentPane);\n            SetSize(ContentPane->GetSize());\n            ContentPane->AddRelation(this, ERelationType::Size);\n            FrameObject = Cast<UGComponent>(ContentPane->GetChild(\"frame\"));\n            if (FrameObject != nullptr)\n            {\n                SetCloseButton(FrameObject->GetChild(\"closeButton\"));\n                SetDragArea(FrameObject->GetChild(\"dragArea\"));\n                SetContentArea(FrameObject->GetChild(\"contentArea\"));\n            }\n        }\n        else\n            FrameObject = nullptr;\n    }\n}\n\nvoid UGWindow::SetCloseButton(UGObject * Obj)\n{\n    if (CloseButton != Obj)\n    {\n        if (CloseButton != nullptr)\n            CloseButton->OnClick.RemoveDynamic(this, &UGWindow::CloseEventHandler);\n        CloseButton = Obj;\n        if (CloseButton != nullptr)\n            CloseButton->OnClick.AddUniqueDynamic(this, &UGWindow::CloseEventHandler);\n    }\n}\n\nvoid UGWindow::SetDragArea(UGObject * Obj)\n{\n    if (DragArea != Obj)\n    {\n        if (DragArea != nullptr)\n        {\n            DragArea->SetDraggable(false);\n            DragArea->OnDragStart.RemoveDynamic(this, &UGWindow::OnDragStartHandler);\n        }\n\n        DragArea = Obj;\n        if (DragArea != nullptr)\n        {\n            UGGraph* DragGraph;\n            if ((DragGraph = Cast<UGGraph>(DragArea)) != nullptr && DragGraph->IsEmpty())\n                DragGraph->DrawRect(0, FColor::Transparent, FColor::Transparent);\n\n            DragArea->SetDraggable(true);\n            DragArea->OnDragStart.AddUniqueDynamic(this, &UGWindow::OnDragStartHandler);\n        }\n    }\n}\n\nvoid UGWindow::Show()\n{\n    GetUIRoot()->ShowWindow(this);\n}\n\nvoid UGWindow::Hide()\n{\n    if (IsShowing())\n        DoHideAnimation();\n}\n\nvoid UGWindow::HideImmediately()\n{\n    GetUIRoot()->HideWindowImmediately(this);\n}\n\nvoid UGWindow::ToggleStatus()\n{\n    if (IsTop())\n        Hide();\n    else\n        Show();\n}\n\nvoid UGWindow::BringToFront()\n{\n    GetUIRoot()->BringToFront(this);\n}\n\nbool UGWindow::IsTop() const\n{\n    return Parent.IsValid() && Parent->GetChildIndex(this) == Parent->NumChildren() - 1;\n}\n\nvoid UGWindow::ShowModalWait(int32 InRequestingCmd)\n{\n    if (InRequestingCmd != 0)\n        RequestingCmd = InRequestingCmd;\n\n    if (!FUIConfig::Config.WindowModalWaiting.IsEmpty())\n    {\n        if (ModalWaitPane == nullptr)\n            ModalWaitPane = UUIPackage::CreateObjectFromURL(FUIConfig::Config.WindowModalWaiting, this);\n\n        LayoutModalWaitPane();\n\n        AddChild(ModalWaitPane);\n    }\n}\n\nvoid UGWindow::LayoutModalWaitPane()\n{\n    if (ContentArea != nullptr)\n    {\n        FVector2D pt = FrameObject->LocalToGlobal(FVector2D::ZeroVector);\n        pt = GlobalToLocal(pt);\n        ModalWaitPane->SetPosition(pt + ContentArea->GetPosition());\n        ModalWaitPane->SetSize(ContentArea->GetSize());\n    }\n    else\n        ModalWaitPane->SetSize(Size);\n}\n\nbool UGWindow::CloseModalWait(int32 InRequestingCmd)\n{\n    if (InRequestingCmd != 0)\n    {\n        if (RequestingCmd != InRequestingCmd)\n            return false;\n    }\n    RequestingCmd = 0;\n\n    if (ModalWaitPane != nullptr && ModalWaitPane->GetParent() != nullptr)\n        RemoveChild(ModalWaitPane);\n\n    return true;\n}\n\nvoid UGWindow::Init()\n{\n    if (bInited || bLoading)\n        return;\n\n    if (UISources.Num() > 0)\n    {\n        bLoading = false;\n        int32 cnt = UISources.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            const TSharedPtr<IUISource>& lib = UISources[i];\n            if (!lib->IsLoaded())\n            {\n                lib->Load(FSimpleDelegate::CreateUObject(this, &UGWindow::OnUILoadComplete));\n                bLoading = true;\n            }\n        }\n\n        if (!bLoading)\n            InternalInit();\n    }\n    else\n        InternalInit();\n}\n\nvoid UGWindow::InternalInit()\n{\n    bInited = true;\n    OnInit();\n\n    if (IsShowing())\n        DoShowAnimation();\n}\n\nvoid UGWindow::AddUISource(TSharedPtr<IUISource> UISource)\n{\n    UISources.Add(UISource);\n}\n\nvoid UGWindow::OnInit()\n{\n    InitCallback.ExecuteIfBound(this);\n}\n\nvoid UGWindow::OnShown()\n{\n    ShownCallback.ExecuteIfBound(this);\n}\n\nvoid UGWindow::OnHide()\n{\n    HideCallback.ExecuteIfBound(this);\n}\n\nvoid UGWindow::DoShowAnimation()\n{\n    if (ShowingCallback.IsBound())\n        ShowingCallback.Execute(this);\n    else\n        OnShown();\n}\n\nvoid UGWindow::DoHideAnimation()\n{\n    if (HidingCallback.IsBound())\n        HidingCallback.Execute(this);\n    else\n        HideImmediately();\n}\n\nvoid UGWindow::CloseEventHandler(UEventContext * Context)\n{\n    Hide();\n}\n\nvoid UGWindow::OnUILoadComplete()\n{\n    int32 cnt = UISources.Num();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        const TSharedPtr<IUISource>& lib = UISources[i];\n        if (!lib->IsLoaded())\n            return;\n    }\n\n    bLoading = false;\n    InternalInit();\n}\n\nvoid UGWindow::OnAddedToStageHandler(UEventContext * Context)\n{\n    if (!bInited)\n        Init();\n    else\n        DoShowAnimation();\n}\n\nvoid UGWindow::OnRemovedFromStageHandler(UEventContext * Context)\n{\n    CloseModalWait();\n    OnHide();\n}\n\nvoid UGWindow::OnTouchBeginHandler(UEventContext * Context)\n{\n    if (IsShowing() && bBringToFontOnClick)\n    {\n        BringToFront();\n    }\n}\n\nvoid UGWindow::OnDragStartHandler(UEventContext * Context)\n{\n    Context->PreventDefault();\n\n    StartDrag(Context->GetUserIndex(), Context->GetPointerIndex());\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearAnimation.cpp",
    "content": "#include \"UI/Gears/GearAnimation.h\"\n#include \"UI/GObject.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearAnimation::FValue::FValue() :\n    bPlaying(false), Frame(0)\n{\n}\n\nFGearAnimation::FGearAnimation(UGObject* InOwner) : FGearBase(InOwner)\n{\n    Type = EType::Animation;\n}\n\nFGearAnimation::~FGearAnimation()\n{\n}\n\nvoid FGearAnimation::Init()\n{\n    Default.bPlaying = Owner->GetProp<bool>(EObjectPropID::Playing);\n    Default.Frame = Owner->GetProp<int32>(EObjectPropID::Frame);\n    Storage.Reset();\n}\n\nvoid FGearAnimation::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    FValue Value;\n    Value.bPlaying = Buffer->ReadBool();\n    Value.Frame = Buffer->ReadInt();\n    if (PageID.IsEmpty())\n        Default = Value;\n    else\n        Storage.Add(PageID, MoveTemp(Value));\n}\n\nvoid FGearAnimation::Apply()\n{\n    Owner->bGearLocked = true;\n\n    FValue* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    Owner->SetProp(EObjectPropID::Playing, FNVariant(Value->bPlaying));\n    Owner->SetProp(EObjectPropID::Frame, FNVariant(Value->Frame));\n\n    Owner->bGearLocked = false;\n}\n\nvoid FGearAnimation::UpdateState()\n{\n    FValue Value;\n    Value.bPlaying = Owner->GetProp<bool>(EObjectPropID::Playing);\n    Value.Frame = Owner->GetProp<int32>(EObjectPropID::Frame);\n    Storage.Add(Controller->GetSelectedPageID(), MoveTemp(Value));\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearBase.cpp",
    "content": "#include \"UI/Gears/GearBase.h\"\n#include \"UI/Gears/GearDisplay.h\"\n#include \"UI/Gears/GearAnimation.h\"\n#include \"UI/Gears/GearColor.h\"\n#include \"UI/Gears/GearDisplay2.h\"\n#include \"UI/Gears/GearFontSize.h\"\n#include \"UI/Gears/GearIcon.h\"\n#include \"UI/Gears/GearLook.h\"\n#include \"UI/Gears/GearSize.h\"\n#include \"UI/Gears/GearText.h\"\n#include \"UI/Gears/GearXY.h\"\n#include \"UI/GComponent.h\"\n#include \"Utils/ByteBuffer.h\"\n\nbool FGearBase::bDisableAllTweenEffect = false;\n\nTSharedPtr<FGearBase> FGearBase::Create(UGObject* InOwner, EType InType)\n{\n    FGearBase* Gear = nullptr;\n    switch (InType)\n    {\n    case EType::Display:\n        Gear = new FGearDisplay(InOwner);\n        break;\n    case EType::XY:\n        Gear = new FGearXY(InOwner);\n        break;\n    case EType::Size:\n        Gear = new FGearSize(InOwner);\n        break;\n    case EType::Look:\n        Gear = new FGearLook(InOwner);\n        break;\n    case EType::Color:\n        Gear = new FGearColor(InOwner);\n        break;\n    case EType::Animation:\n        Gear = new FGearAnimation(InOwner);\n        break;\n    case EType::Text:\n        Gear = new FGearText(InOwner);\n        break;\n    case EType::Icon:\n        Gear = new FGearIcon(InOwner);\n        break;\n    case EType::Display2:\n        Gear = new FGearDisplay2(InOwner);\n        break;\n    case EType::FontSize:\n        Gear = new FGearFontSize(InOwner);\n        break;\n    }\n\n    return MakeShareable(Gear);\n}\n\nFGearTweenConfig::FGearTweenConfig():\n    bTween(true),\n    EaseType(EEaseType::QuadOut),\n    Duration(0.3f),\n    Delay(0),\n    DisplayLockToken(0)\n{\n}\n\nFGearBase::FGearBase(UGObject* InOwner) : Owner(InOwner)\n{\n}\n\nFGearBase::~FGearBase()\n{\n}\n\nvoid FGearBase::SetController(UGController* InController)\n{\n    if (Controller != InController)\n    {\n        Controller = InController;\n        if (Controller != nullptr)\n            Init();\n    }\n}\n\nFGearTweenConfig& FGearBase::GetTweenConfig()\n{\n    if (!TweenConfig.IsSet())\n        TweenConfig.Emplace();\n\n    return TweenConfig.GetValue();\n}\n\nvoid FGearBase::Init()\n{\n}\n\nvoid FGearBase::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n}\n\nvoid FGearBase::Apply()\n{\n}\n\nvoid FGearBase::UpdateState()\n{\n}\n\nvoid FGearBase::UpdateFromRelations(const FVector2D& Delta)\n{\n}\n\nvoid FGearBase::Setup(FByteBuffer* Buffer)\n{\n    Controller = Owner->GetParent()->GetControllerAt(Buffer->ReadShort());\n    Init();\n\n    int32 Count = Buffer->ReadShort();\n    FGearDisplay* g0 = Type == EType::Display ? static_cast<FGearDisplay*>(this) : nullptr;\n    FGearDisplay2* g1 = Type == EType::Display2 ? static_cast<FGearDisplay2*>(this) : nullptr;\n    FGearXY* g2 = nullptr;\n    if (g0)\n        Buffer->ReadSArray(g0->Pages, Count);\n    else if (g1)\n        Buffer->ReadSArray(g1->Pages, Count);\n    else\n    {\n        for (int32 i = 0; i < Count; i++)\n        {\n            const FString& page = Buffer->ReadS();\n            if (page.IsEmpty())\n                continue;\n\n            AddStatus(page, Buffer);\n        }\n\n        if (Buffer->ReadBool())\n            AddStatus(G_EMPTY_STRING, Buffer);\n    }\n\n    if (Buffer->ReadBool())\n    {\n        TweenConfig.Emplace();\n        TweenConfig->bTween = true;\n        TweenConfig->EaseType = (EEaseType)Buffer->ReadByte();\n        TweenConfig->Duration = Buffer->ReadFloat();\n        TweenConfig->Delay = Buffer->ReadFloat();\n    }\n\n    if (Buffer->Version >= 2)\n    {\n        g2 = Type == EType::XY ? static_cast<FGearXY*>(this) : nullptr;\n        if (g2)\n        {\n            if (Buffer->ReadBool())\n            {\n                if (g2)\n                {\n                    g2->bPositionsInPercent = true;\n                    for (int32 i = 0; i < Count; i++)\n                    {\n                        const FString& page = Buffer->ReadS();\n                        if (page.IsEmpty())\n                            continue;\n\n                        g2->AddExtStatus(page, Buffer);\n                    }\n\n                    if (Buffer->ReadBool())\n                        g2->AddExtStatus(G_EMPTY_STRING, Buffer);\n                }\n            }\n        }\n        else if (g1 != nullptr)\n            g1->Condition = Buffer->ReadByte();\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearColor.cpp",
    "content": "#include \"UI/Gears/GearColor.h\"\n#include \"UI/GObject.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n#include \"Tween/GTween.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearColor::FValue::FValue()\n{\n}\n\nFGearColor::FGearColor(UGObject* InOwner) : FGearBase(InOwner)\n{\n    Type = EType::Color;\n}\n\nFGearColor::~FGearColor()\n{\n}\n\nvoid FGearColor::Init()\n{\n    Default.Color = Owner->GetProp<FColor>(EObjectPropID::Color);\n    Default.OutlineColor = Owner->GetProp<FColor>(EObjectPropID::OutlineColor);\n    Storage.Reset();\n}\n\nvoid FGearColor::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    FValue Value;\n    Value.Color = Buffer->ReadColor();\n    Value.OutlineColor = Buffer->ReadColor();\n    if (PageID.IsEmpty())\n        Default = Value;\n    else\n        Storage.Add(PageID, MoveTemp(Value));\n}\n\nvoid FGearColor::Apply()\n{\n    FValue* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect)\n    {\n        FColor curColor = Owner->GetProp<FColor>(EObjectPropID::Color);\n        FColor curOutlineColor = Owner->GetProp<FColor>(EObjectPropID::OutlineColor);\n\n        if (Value->OutlineColor != curOutlineColor)\n        {\n            Owner->bGearLocked = true;\n            Owner->SetProp(EObjectPropID::OutlineColor, FNVariant(Value->OutlineColor));\n            Owner->bGearLocked = false;\n        }\n\n        FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle);\n        if (tweener != nullptr)\n        {\n            if (tweener->EndValue.GetColor() != Value->Color)\n                tweener->Kill(true);\n            else\n                return;\n        }\n\n        if (Value->Color != curColor)\n        {\n            if (Owner->CheckGearController(0, Controller))\n                TweenConfig->DisplayLockToken = Owner->AddDisplayLock();\n\n            TweenConfig->Handle = FGTween::To(curColor, Value->Color, TweenConfig->Duration)\n                ->SetDelay(TweenConfig->Delay)\n                ->SetEase(TweenConfig->EaseType)\n                ->SetTarget(Owner)\n                ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearColor::OnTweenUpdate))\n                ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearColor::OnTweenComplete))\n                ->GetHandle();\n        }\n    }\n    else\n    {\n        Owner->bGearLocked = true;\n        Owner->SetProp(EObjectPropID::Color, FNVariant(Value->Color));\n        Owner->SetProp(EObjectPropID::OutlineColor, FNVariant(Value->OutlineColor));\n        Owner->bGearLocked = false;\n    }\n}\n\nvoid FGearColor::OnTweenUpdate(FGTweener* Tweener)\n{\n    Owner->bGearLocked = true;\n    Owner->SetProp(EObjectPropID::Color, FNVariant(Tweener->Value.GetColor()));\n    Owner->bGearLocked = false;\n}\n\nvoid FGearColor::OnTweenComplete()\n{\n    if (TweenConfig->DisplayLockToken != 0)\n    {\n        Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken);\n        TweenConfig->DisplayLockToken = 0;\n    }\n    TweenConfig->Handle.Invalidate();\n    Owner->DispatchEvent(FUIEvents::GearStop);\n}\n\nvoid FGearColor::UpdateState()\n{\n    FValue Value;\n    Value.Color = Owner->GetProp<FColor>(EObjectPropID::Color);\n    Value.OutlineColor = Owner->GetProp<FColor>(EObjectPropID::OutlineColor);\n    Storage.Add(Controller->GetSelectedPageID(), MoveTemp(Value));\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearDisplay.cpp",
    "content": "#include \"UI/Gears/GearDisplay.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearDisplay::FGearDisplay(UGObject* InOwner) :\n    FGearBase(InOwner),\n    Visible(0),\n    DisplayLockToken(1)\n{\n    Type = EType::Display;\n}\n\nFGearDisplay::~FGearDisplay()\n{\n}\n\nvoid FGearDisplay::Apply()\n{\n    DisplayLockToken++;\n    if (DisplayLockToken == 0)\n        DisplayLockToken = 1;\n\n    if (Pages.Num() == 0)\n        Visible = 1;\n    else\n    {\n        if (Pages.Contains(Controller->GetSelectedPageID()))\n            Visible = 1;\n        else\n            Visible = 0;\n    }\n}\n\nvoid FGearDisplay::UpdateState()\n{\n}\n\nvoid FGearDisplay::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n}\n\nvoid FGearDisplay::Init()\n{\n    Pages.Reset();\n}\n\nuint32 FGearDisplay::AddLock()\n{\n    Visible++;\n    return DisplayLockToken;\n}\n\nvoid FGearDisplay::ReleaseLock(uint32 token)\n{\n    if (token == DisplayLockToken)\n        Visible--;\n}\n\nbool FGearDisplay::IsConnected()\n{\n    return Controller == nullptr || Visible > 0;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearDisplay2.cpp",
    "content": "#include \"UI/Gears/GearDisplay2.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearDisplay2::FGearDisplay2(UGObject* InOwner) :\n    FGearBase(InOwner),\n    Condition(0),\n    Visible(0)\n{\n    Type = EType::Display2;\n}\n\nFGearDisplay2::~FGearDisplay2()\n{\n}\n\nvoid FGearDisplay2::Apply()\n{\n    if (Controller == nullptr || Pages.Num() == 0)\n        Visible = 1;\n    else\n    {\n        if (Pages.Contains(Controller->GetSelectedPageID()))\n            Visible = 1;\n        else\n            Visible = 0;\n    }\n}\n\nbool FGearDisplay2::Evaluate(bool bConnected)\n{\n    bool v = Controller == nullptr || Visible > 0;\n    if (Condition == 0)\n        v = v && bConnected;\n    else\n        v = v || bConnected;\n    return v;\n}\n\nvoid FGearDisplay2::UpdateState()\n{\n}\n\nvoid FGearDisplay2::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n}\n\nvoid FGearDisplay2::Init()\n{\n    Pages.Reset();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearFontSize.cpp",
    "content": "#include \"UI/Gears/GearFontSize.h\"\n#include \"UI/GObject.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearFontSize::FGearFontSize(UGObject* InOwner) : FGearBase(InOwner)\n{\n    Type = EType::FontSize;\n}\n\nFGearFontSize::~FGearFontSize()\n{\n}\n\nvoid FGearFontSize::Init()\n{\n    Default = Owner->GetProp<int32>(EObjectPropID::FontSize);\n    Storage.Reset();\n}\n\nvoid FGearFontSize::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    if (PageID.IsEmpty())\n        Default = Buffer->ReadInt();\n    else\n        Storage.Add(PageID, Buffer->ReadInt());\n}\n\nvoid FGearFontSize::Apply()\n{\n    int32* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    Owner->bGearLocked = true;\n    Owner->SetProp(EObjectPropID::FontSize, FNVariant(*Value));\n    Owner->bGearLocked = false;\n}\n\nvoid FGearFontSize::UpdateState()\n{\n    Storage.Add(Controller->GetSelectedPageID(), Owner->GetProp<int32>(EObjectPropID::FontSize));\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearIcon.cpp",
    "content": "#include \"UI/Gears/GearIcon.h\"\n#include \"UI/GObject.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearIcon::FGearIcon(UGObject * InOwner) :FGearBase(InOwner)\n{\n    Type = EType::Icon;\n}\n\nFGearIcon::~FGearIcon()\n{\n}\n\nvoid FGearIcon::Init()\n{\n    Default = Owner->GetIcon();\n    Storage.Reset();\n}\n\nvoid FGearIcon::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    if (PageID.IsEmpty())\n        Default = Buffer->ReadS();\n    else\n        Storage.Add(PageID, Buffer->ReadS());\n}\n\nvoid FGearIcon::Apply()\n{\n    FString* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    Owner->bGearLocked = true;\n    Owner->SetIcon(*Value);\n    Owner->bGearLocked = false;\n}\n\nvoid FGearIcon::UpdateState()\n{\n    Storage.Add(Controller->GetSelectedPageID(), Owner->GetIcon());\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearLook.cpp",
    "content": "#include \"UI/Gears/GearLook.h\"\n#include \"UI/GObject.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n#include \"Tween/GTween.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearLook::FValue::FValue() :\n    Alpha(0),\n    Rotation(0),\n    bGrayed(false),\n    bTouchable(false)\n{\n}\n\nFGearLook::FGearLook(UGObject* InOwner) : FGearBase(InOwner)\n{\n    Type = EType::Look;\n}\n\nFGearLook::~FGearLook()\n{\n}\n\nvoid FGearLook::Init()\n{\n    Default.Alpha = Owner->GetAlpha();\n    Default.Rotation = Owner->GetRotation();\n    Default.bGrayed = Owner->IsGrayed();\n    Default.bTouchable = Owner->IsTouchable();\n    Storage.Reset();\n}\n\nvoid FGearLook::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    FValue Value;\n    Value.Alpha = Buffer->ReadFloat();\n    Value.Rotation = Buffer->ReadFloat();\n    Value.bGrayed = Buffer->ReadBool();\n    Value.bTouchable = Buffer->ReadBool();\n\n    if (PageID.IsEmpty())\n        Default = Value;\n    else\n        Storage.Add(PageID, MoveTemp(Value));\n}\n\nvoid FGearLook::Apply()\n{\n    FValue* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect)\n    {\n        Owner->bGearLocked = true;\n        Owner->SetGrayed(Value->bGrayed);\n        Owner->SetTouchable(Value->bTouchable);\n        Owner->bGearLocked = false;\n\n        FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle);\n        if (tweener != nullptr)\n        {\n            if (tweener->EndValue.X != Value->Alpha || tweener->EndValue.Y != Value->Rotation)\n                tweener->Kill(true);\n            else\n                return;\n        }\n\n        bool a = Value->Alpha != Owner->GetAlpha();\n        bool b = Value->Rotation != Owner->GetRotation();\n        if (a || b)\n        {\n            if (Owner->CheckGearController(0, Controller))\n                TweenConfig->DisplayLockToken = Owner->AddDisplayLock();\n\n            TweenConfig->Handle = FGTween::To(FVector2D(Owner->GetAlpha(), Owner->GetRotation()), FVector2D(Value->Alpha, Value->Rotation), TweenConfig->Duration)\n                ->SetDelay(TweenConfig->Delay)\n                ->SetEase(TweenConfig->EaseType)\n                ->SetTarget(Owner)\n                ->SetUserData(FNVariant((a ? 1 : 0) + (b ? 2 : 0)))\n                ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearLook::OnTweenUpdate))\n                ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearLook::OnTweenComplete))\n                ->GetHandle();\n        }\n    }\n    else\n    {\n        Owner->bGearLocked = true;\n        Owner->SetAlpha(Value->Alpha);\n        Owner->SetRotation(Value->Rotation);\n        Owner->SetGrayed(Value->bGrayed);\n        Owner->SetTouchable(Value->bTouchable);\n        Owner->bGearLocked = false;\n    }\n}\n\nvoid FGearLook::OnTweenUpdate(FGTweener* Tweener)\n{\n    int32 flag = Tweener->GetUserData().AsInt();\n    Owner->bGearLocked = true;\n\n    if ((flag & 1) != 0)\n        Owner->SetAlpha(Tweener->Value.X);\n    if ((flag & 2) != 0)\n        Owner->SetRotation(Tweener->Value.Y);\n    Owner->bGearLocked = false;\n}\n\nvoid FGearLook::OnTweenComplete()\n{\n    if (TweenConfig->DisplayLockToken != 0)\n    {\n        Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken);\n        TweenConfig->DisplayLockToken = 0;\n    }\n    TweenConfig->Handle.Invalidate();\n    Owner->DispatchEvent(FUIEvents::GearStop);\n}\n\nvoid FGearLook::UpdateState()\n{\n    FValue Value;\n    Value.Alpha = Owner->GetAlpha();\n    Value.Rotation = Owner->GetRotation();\n    Value.bGrayed = Owner->IsGrayed();\n    Value.bTouchable = Owner->IsTouchable();\n    Storage.Add(Controller->GetSelectedPageID(), MoveTemp(Value));\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearSize.cpp",
    "content": "#include \"UI/Gears/GearSize.h\"\n#include \"UI/GObject.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n#include \"Tween/GTween.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearSize::FGearSize(UGObject* InOwner) : FGearBase(InOwner)\n{\n    Type = EType::Size;\n}\n\nFGearSize::~FGearSize()\n{\n}\n\nvoid FGearSize::Init()\n{\n    Default = FVector4(Owner->GetWidth(), Owner->GetHeight(),\n        Owner->GetScaleX(), Owner->GetScaleY());\n    Storage.Reset();\n}\n\nvoid FGearSize::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    FVector4 Value;\n    Value.X = Buffer->ReadInt();\n    Value.Y = Buffer->ReadInt();\n    Value.Z = Buffer->ReadFloat();\n    Value.W = Buffer->ReadFloat();\n\n    if (PageID.IsEmpty())\n        Default = Value;\n    else\n        Storage.Add(PageID, MoveTemp(Value));\n}\n\nvoid FGearSize::Apply()\n{\n    FVector4* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect)\n    {\n        FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle);\n        if (tweener != nullptr)\n        {\n            if (tweener->EndValue.GetVec4() != *Value)\n                tweener->Kill(true);\n            else\n                return;\n        }\n\n        bool a = Value->X != Owner->GetWidth() || Value->Y != Owner->GetHeight();\n        bool b = Value->Z != Owner->GetScaleX() || Value->W != Owner->GetScaleY();\n        if (a || b)\n        {\n            if (Owner->CheckGearController(0, Controller))\n                TweenConfig->DisplayLockToken = Owner->AddDisplayLock();\n\n            TweenConfig->Handle = FGTween::To(FVector4(Owner->GetWidth(), Owner->GetHeight(), Owner->GetScaleX(), Owner->GetScaleY()), *Value, TweenConfig->Duration)\n                ->SetDelay(TweenConfig->Delay)\n                ->SetEase(TweenConfig->EaseType)\n                ->SetTarget(Owner)\n                ->SetUserData(FNVariant((a ? 1 : 0) + (b ? 2 : 0)))\n                ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearSize::OnTweenUpdate))\n                ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearSize::OnTweenComplete))\n                ->GetHandle();\n        }\n    }\n    else\n    {\n        Owner->bGearLocked = true;\n        Owner->SetSize(FVector2D(Value->X, Value->Y), Owner->CheckGearController(1, Controller));\n        Owner->SetScale(FVector2D(Value->Z, Value->W));\n        Owner->bGearLocked = false;\n    }\n}\n\nvoid FGearSize::OnTweenUpdate(FGTweener* Tweener)\n{\n    int32 flag = Tweener->GetUserData().AsInt();\n    Owner->bGearLocked = true;\n    if ((flag & 1) != 0)\n        Owner->SetSize(Tweener->Value.GetVec2(), Owner->CheckGearController(1, Controller));\n    if ((flag & 2) != 0)\n        Owner->SetScale(FVector2D(Tweener->Value.Z, Tweener->Value.W));\n    Owner->bGearLocked = false;\n}\n\nvoid FGearSize::OnTweenComplete()\n{\n    if (TweenConfig->DisplayLockToken != 0)\n    {\n        Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken);\n        TweenConfig->DisplayLockToken = 0;\n    }\n    TweenConfig->Handle.Invalidate();\n    Owner->DispatchEvent(FUIEvents::GearStop);\n}\n\nvoid FGearSize::UpdateState()\n{\n    Storage.Add(Controller->GetSelectedPageID(), FVector4(Owner->GetWidth(), Owner->GetHeight(),\n        Owner->GetScaleX(), Owner->GetScaleY()));\n}\n\nvoid FGearSize::UpdateFromRelations(const FVector2D& Delta)\n{\n    if (Controller != nullptr && Storage.Num() > 0)\n    {\n        for (auto It = Storage.CreateIterator(); It; ++It)\n        {\n            It->Value = FVector4(It->Value.X + Delta.X, It->Value.Y + Delta.Y,\n                It->Value.Z, It->Value.W);\n        }\n        Default.X += Delta.X;\n        Default.Y += Delta.Y;\n\n        UpdateState();\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearText.cpp",
    "content": "#include \"UI/Gears/GearText.h\"\n#include \"UI/GObject.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearText::FGearText(UGObject* InOwner) : FGearBase(InOwner)\n{\n    Type = EType::Text;\n}\n\nFGearText::~FGearText()\n{\n}\n\nvoid FGearText::Init()\n{\n    Default = Owner->GetText();\n    Storage.Reset();\n}\n\nvoid FGearText::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    if (PageID.IsEmpty())\n        Default = Buffer->ReadS();\n    else\n        Storage.Add(PageID, Buffer->ReadS());\n}\n\nvoid FGearText::Apply()\n{\n    FString* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    Owner->bGearLocked = true;\n    Owner->SetText(*Value);\n    Owner->bGearLocked = false;\n}\n\nvoid FGearText::UpdateState()\n{\n    Storage.Add(Controller->GetSelectedPageID(), Owner->GetText());\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Gears/GearXY.cpp",
    "content": "#include \"UI/Gears/GearXY.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n#include \"Tween/GTween.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFGearXY::FGearXY(UGObject* InOwner) :\n    FGearBase(InOwner),\n    bPositionsInPercent(false)\n{\n    Type = EType::XY;\n}\n\nFGearXY::~FGearXY()\n{\n}\n\nvoid FGearXY::Init()\n{\n    Default = FVector4(Owner->GetX(),\n        Owner->GetY(),\n        Owner->GetX() / Owner->GetParent()->GetWidth(),\n        Owner->GetY() / Owner->GetParent()->GetHeight());\n    Storage.Reset();\n}\n\nvoid FGearXY::AddStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    FVector4 Value;\n    Value.X = Buffer->ReadInt();\n    Value.Y = Buffer->ReadInt();\n\n    if (PageID.IsEmpty())\n        Default = Value;\n    else\n        Storage.Add(PageID, MoveTemp(Value));\n}\n\nvoid FGearXY::AddExtStatus(const FString& PageID, FByteBuffer* Buffer)\n{\n    FVector4* Value = PageID.IsEmpty() ? &Default : Storage.Find(Controller->GetSelectedPageID());\n    Value->Z = Buffer->ReadFloat();\n    Value->W = Buffer->ReadFloat();\n}\n\nvoid FGearXY::Apply()\n{\n    FVector4* Value = Storage.Find(Controller->GetSelectedPageID());\n    if (Value == nullptr)\n        Value = &Default;\n\n    FVector2D EndPt;\n\n    if (bPositionsInPercent && Owner->GetParent())\n    {\n        EndPt.X = Value->Z * Owner->GetParent()->GetWidth();\n        EndPt.Y = Value->W * Owner->GetParent()->GetHeight();\n    }\n    else\n    {\n        EndPt.X = Value->X;\n        EndPt.Y = Value->Y;\n    }\n\n    if (TweenConfig.IsSet() && TweenConfig->bTween && UUIPackage::Constructing == 0 && !bDisableAllTweenEffect)\n    {\n        FGTweener* tweener = FGTween::GetTween(TweenConfig->Handle);\n        if (tweener != nullptr)\n        {\n            if (tweener->EndValue.GetVec2() != EndPt)\n                tweener->Kill(true);\n            else\n                return;\n        }\n\n        FVector2D OriginPt(Owner->GetX(), Owner->GetY());\n\n        if (OriginPt != EndPt)\n        {\n            if (Owner->CheckGearController(0, Controller))\n                TweenConfig->DisplayLockToken = Owner->AddDisplayLock();\n\n            TweenConfig->Handle = FGTween::To(OriginPt, EndPt, TweenConfig->Duration)\n                ->SetDelay(TweenConfig->Delay)\n                ->SetEase(TweenConfig->EaseType)\n                ->SetTarget(Owner)\n                ->OnUpdate(FTweenDelegate::CreateRaw(this, &FGearXY::OnTweenUpdate))\n                ->OnComplete(FSimpleDelegate::CreateRaw(this, &FGearXY::OnTweenComplete))\n                ->GetHandle();\n        }\n    }\n    else\n    {\n        Owner->bGearLocked = true;\n        Owner->SetPosition(EndPt);\n        Owner->bGearLocked = false;\n    }\n}\n\nvoid FGearXY::OnTweenUpdate(FGTweener* Tweener)\n{\n    Owner->bGearLocked = true;\n    Owner->SetPosition(Tweener->Value.GetVec2());\n    Owner->bGearLocked = false;\n}\n\nvoid FGearXY::OnTweenComplete()\n{\n    if (TweenConfig->DisplayLockToken != 0)\n    {\n        Owner->ReleaseDisplayLock(TweenConfig->DisplayLockToken);\n        TweenConfig->DisplayLockToken = 0;\n    }\n    TweenConfig->Handle.Invalidate();\n    Owner->DispatchEvent(FUIEvents::GearStop);\n}\n\nvoid FGearXY::UpdateState()\n{\n    Storage.Add(Controller->GetSelectedPageID(), FVector4(\n        Owner->GetX(),\n        Owner->GetY(),\n        Owner->GetX() / Owner->GetParent()->GetWidth(),\n        Owner->GetY() / Owner->GetParent()->GetHeight()));\n}\n\nvoid FGearXY::UpdateFromRelations(const FVector2D& Delta)\n{\n    if (Controller != nullptr && Storage.Num() > 0 && !bPositionsInPercent)\n    {\n        for (auto It = Storage.CreateIterator(); It; ++It)\n        {\n            It->Value = FVector4(It->Value.X + Delta.X, It->Value.Y + Delta.Y,\n                It->Value.Z, It->Value.W);\n        }\n        Default.X += Delta.X;\n        Default.Y += Delta.Y;\n\n        UpdateState();\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/PackageItem.cpp",
    "content": "#include \"UI/PackageItem.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GRoot.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFPackageItem::FPackageItem() :\n    Owner(nullptr),\n    Type(EPackageItemType::Unknown),\n    ObjectType(EObjectType::Component),\n    Size(0, 0),\n    Texture(nullptr),\n    bScaleByTile(false),\n    TileGridIndice(0)\n{\n}\n\nvoid FPackageItem::Load()\n{\n    Owner->GetItemAsset(AsShared());\n}\n\nTSharedPtr<FPackageItem> FPackageItem::GetBranch()\n{\n    if (Branches.IsSet() && Owner->BranchIndex != -1)\n    {\n        const FString& ItemID = Branches.GetValue()[Owner->BranchIndex];\n        if (!ItemID.IsEmpty())\n            return Owner->GetItem(ItemID);\n    }\n\n    return AsShared();\n}\n\nTSharedPtr<FPackageItem> FPackageItem::GetHighResolution()\n{\n    if (HighResolution.IsSet() && UGRoot::ContentScaleLevel > 0)\n    {\n        FString ItemID = HighResolution.GetValue()[UGRoot::ContentScaleLevel - 1];\n        if (!ItemID.IsEmpty())\n            return Owner->GetItem(ItemID);\n    }\n\n    return AsShared();\n}\n\nvoid FPackageItem::AddReferencedObjects(FReferenceCollector& Collector)\n{\n    if (Texture != nullptr)\n        Collector.AddReferencedObject(Texture);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/PopupMenu.cpp",
    "content": "#include \"UI/PopupMenu.h\"\n#include \"UI/GRoot.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n\nconst FName UPopupMenu::ClickMenu(\"ClickMenu\");\n\nUPopupMenu* UPopupMenu::CreatePopupMenu(const FString& ResourceURL, UObject* WorldContextObject)\n{\n    UPopupMenu* Instance = NewObject<UPopupMenu>(WorldContextObject);\n    Instance->Create(ResourceURL);\n    return Instance;\n}\n\nUPopupMenu::UPopupMenu()\n{\n}\n\nUPopupMenu::~UPopupMenu()\n{\n}\n\nvoid UPopupMenu::Create(const FString& ResourceURL)\n{\n    FString url = ResourceURL;\n    if (url.IsEmpty())\n    {\n        url = FUIConfig::Config.PopupMenu;\n        if (url.IsEmpty())\n        {\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"UIConfig.PopupMenu not defined\"));\n            return;\n        }\n    }\n\n    ContentPane = UUIPackage::CreateObjectFromURL(url, this)->As<UGComponent>();\n    ContentPane->On(FUIEvents::AddedToStage).AddUObject(this, &UPopupMenu::OnAddedToStage);\n\n    List = ContentPane->GetChild(\"list\")->As<UGList>();\n    List->RemoveChildrenToPool();\n\n    List->AddRelation(ContentPane, ERelationType::Width);\n    List->RemoveRelation(ContentPane, ERelationType::Height);\n    ContentPane->AddRelation(List, ERelationType::Height);\n\n    List->On(FUIEvents::ClickItem).AddUObject(this, &UPopupMenu::OnClickItem);\n}\n\nUGButton* UPopupMenu::AddItem(const FString& Caption, FGUIEventDelegate Callback)\n{\n    UGButton* item = List->AddItemFromPool()->As<UGButton>();\n    item->SetTitle(Caption);\n    item->SetGrayed(false);\n    UGController* c = item->GetController(\"checked\");\n    if (c != nullptr)\n        c->SetSelectedIndex(0);\n    item->On(ClickMenu).Clear();\n    if (Callback.IsBound())\n        item->On(ClickMenu).Add(Callback);\n\n    return item;\n}\n\nUGButton* UPopupMenu::AddItem(const FString& Caption, const FGUIEventDynDelegate& Callback)\n{\n    return AddItem(Caption, Callback.IsBound() ?\n        FGUIEventDelegate::CreateUFunction(const_cast<UObject*>(Callback.GetUObject()), Callback.GetFunctionName())\n        : FGUIEventDelegate());\n}\n\nUGButton* UPopupMenu::AddItemAt(const FString& Caption, int32 Index, FGUIEventDelegate Callback)\n{\n    UGButton* item = List->GetFromPool(List->GetDefaultItem())->As<UGButton>();\n    List->AddChildAt(item, Index);\n\n    item->SetTitle(Caption);\n    item->SetGrayed(false);\n    UGController* c = item->GetController(\"checked\");\n    if (c != nullptr)\n        c->SetSelectedIndex(0);\n    if (Callback.IsBound())\n        item->On(ClickMenu).Add(Callback);\n\n    return item;\n}\n\nUGButton* UPopupMenu::AddItemAt(const FString& Caption, int32 index, const FGUIEventDynDelegate& Callback)\n{\n    return AddItemAt(Caption, index, Callback.IsBound() ?\n        FGUIEventDelegate::CreateUFunction(const_cast<UObject*>(Callback.GetUObject()), Callback.GetFunctionName())\n        : FGUIEventDelegate());\n}\n\nvoid UPopupMenu::AddSeperator()\n{\n    if (FUIConfig::Config.PopupMenuSeperator.IsEmpty())\n    {\n        UE_LOG(LogFairyGUI, Warning, TEXT(\"UIConfig.PopupMenuSeperator not defined\"));\n        return;\n    }\n\n    List->AddItemFromPool(FUIConfig::Config.PopupMenuSeperator);\n}\n\nconst FString& UPopupMenu::GetItemName(int32 Index) const\n{\n    UGButton* item = List->GetChildAt(Index)->As<UGButton>();\n    return item->Name;\n}\n\nvoid UPopupMenu::SetItemText(const FString& Name, const FString& Caption)\n{\n    UGButton* item = List->GetChild(Name)->As<UGButton>();\n    item->SetTitle(Caption);\n}\n\nvoid UPopupMenu::SetItemVisible(const FString& Name, bool bVisible)\n{\n    UGButton* item = List->GetChild(Name)->As<UGButton>();\n    if (item->IsVisible() != bVisible)\n    {\n        item->SetVisible(bVisible);\n        List->SetBoundsChangedFlag();\n    }\n}\n\nvoid UPopupMenu::SetItemGrayed(const FString& Name, bool bGrayed)\n{\n    UGButton* item = List->GetChild(Name)->As<UGButton>();\n    item->SetGrayed(bGrayed);\n}\n\nvoid UPopupMenu::SetItemCheckable(const FString& Name, bool bCheckable)\n{\n    UGButton* item = List->GetChild(Name)->As<UGButton>();\n    UGController* c = item->GetController(\"checked\");\n    if (c != nullptr)\n    {\n        if (bCheckable)\n        {\n            if (c->GetSelectedIndex() == 0)\n                c->SetSelectedIndex(1);\n        }\n        else\n            c->SetSelectedIndex(0);\n    }\n}\n\nvoid UPopupMenu::SetItemChecked(const FString& Name, bool bCheck)\n{\n    UGButton* item = List->GetChild(Name)->As<UGButton>();\n    UGController* c = item->GetController(\"checked\");\n    if (c != nullptr)\n        c->SetSelectedIndex(bCheck ? 2 : 1);\n}\n\nbool UPopupMenu::IsItemChecked(const FString& Name) const\n{\n    UGButton* item = List->GetChild(Name)->As<UGButton>();\n    UGController* c = item->GetController(\"checked\");\n    if (c != nullptr)\n        return c->GetSelectedIndex() == 2;\n    else\n        return false;\n}\n\nbool UPopupMenu::RemoveItem(const FString& Name)\n{\n    UGObject* item = List->GetChild(Name);\n    if (item != nullptr)\n    {\n        int32 index = List->GetChildIndex(item);\n        List->RemoveChildToPoolAt(index);\n        item->On(ClickMenu).Clear();\n\n        return true;\n    }\n    else\n        return false;\n}\n\nvoid UPopupMenu::ClearItems()\n{\n    int32 cnt = List->NumChildren();\n    for (int32 i = 0; i < cnt; i++)\n        List->GetChildAt(i)->On(ClickMenu).Clear();\n    List->RemoveChildrenToPool();\n}\n\nint32 UPopupMenu::GetItemCount() const\n{\n    return List->NumChildren();\n}\n\nvoid UPopupMenu::Show(UGObject* AtObject, EPopupDirection Dir)\n{\n    ContentPane->GetUIRoot()->ShowPopup(ContentPane, AtObject, Dir);\n}\n\nvoid UPopupMenu::OnClickItem(UEventContext* Context)\n{\n    UGButton* item = Cast<UGButton>(Context->GetData().AsUObject());\n    if (item == nullptr)\n        return;\n\n    if (item->IsGrayed())\n    {\n        List->SetSelectedIndex(-1);\n        return;\n    }\n\n    UGController* c = item->GetController(\"checked\");\n    if (c != nullptr && c->GetSelectedIndex() != 0)\n    {\n        if (c->GetSelectedIndex() == 1)\n            c->SetSelectedIndex(2);\n        else\n            c->SetSelectedIndex(1);\n    }\n\n    ContentPane->GetUIRoot()->HidePopup(ContentPane);\n\n    item->DispatchEvent(ClickMenu, Context->GetData());\n}\n\nvoid UPopupMenu::OnAddedToStage(UEventContext* Context)\n{\n    List->SetSelectedIndex(-1);\n    List->ResizeToFit(INT_MAX, 10);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/RelationItem.cpp",
    "content": "#include \"UI/RelationItem.h\"\n#include \"UI/Relations.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/GGroup.h\"\n#include \"UI/Transition.h\"\n\nFRelationItem::FRelationItem(UGObject* InOwner) :\n    TargetData(ForceInit)\n{\n    Owner = InOwner;\n}\n\nFRelationItem::~FRelationItem()\n{\n    ReleaseRefTarget();\n}\n\nvoid FRelationItem::SetTarget(UGObject* InTarget)\n{\n    if (Target.Get() != InTarget)\n    {\n        ReleaseRefTarget();\n        Target = InTarget;\n        if (InTarget)\n            AddRefTarget(InTarget);\n    }\n}\n\nvoid FRelationItem::Add(ERelationType RelationType, bool bUsePercent)\n{\n    if (RelationType == ERelationType::Size)\n    {\n        Add(ERelationType::Width, bUsePercent);\n        Add(ERelationType::Height, bUsePercent);\n        return;\n    }\n\n    for (auto& it : Defs)\n    {\n        if (it.Type == RelationType)\n            return;\n    }\n\n    InternalAdd(RelationType, bUsePercent);\n}\n\nvoid FRelationItem::InternalAdd(ERelationType RelationType, bool bUsePercent)\n{\n    if (RelationType == ERelationType::Size)\n    {\n        InternalAdd(ERelationType::Width, bUsePercent);\n        InternalAdd(ERelationType::Height, bUsePercent);\n        return;\n    }\n\n    FRelationDef info;\n    info.bPercent = bUsePercent;\n    info.Type = RelationType;\n    info.Axis = (RelationType <= ERelationType::Right_Right || RelationType == ERelationType::Width || (RelationType >= ERelationType::LeftExt_Left && RelationType <= ERelationType::RightExt_Right)) ? 0 : 1;\n    Defs.Add(info);\n}\n\nvoid FRelationItem::Remove(ERelationType RelationType)\n{\n    if (RelationType == ERelationType::Size)\n    {\n        Remove(ERelationType::Width);\n        Remove(ERelationType::Height);\n        return;\n    }\n\n    int32 i = 0;\n    for (auto& def : Defs)\n    {\n        if (def.Type == RelationType)\n        {\n            Defs.RemoveAt(i);\n            break;\n        }\n        i++;\n    }\n}\n\nvoid FRelationItem::CopyFrom(const FRelationItem& Source)\n{\n    SetTarget(Source.Target.Get());\n\n    Defs.Reset();\n    for (auto& it : Source.Defs)\n        Defs.Add(it);\n}\n\nbool FRelationItem::IsEmpty() const\n{\n    return Defs.Num() == 0;\n}\n\nvoid FRelationItem::ApplyOnSelfSizeChanged(float DeltaWidth, float DeltaHeight, bool bApplyPivot)\n{\n    if (!Target.IsValid() || Defs.Num() == 0)\n        return;\n\n    FVector2D Pos = Owner->Position;\n\n    for (auto& it : Defs)\n    {\n        switch (it.Type)\n        {\n        case ERelationType::Center_Center:\n            Owner->SetX(Owner->Position.X - (0.5 - (bApplyPivot ? Owner->Pivot.X : 0)) * DeltaWidth);\n            break;\n\n        case ERelationType::Right_Center:\n        case ERelationType::Right_Left:\n        case ERelationType::Right_Right:\n            Owner->SetX(Owner->Position.X - (1 - (bApplyPivot ? Owner->Pivot.X : 0)) * DeltaWidth);\n            break;\n\n        case ERelationType::Middle_Middle:\n            Owner->SetY(Owner->Position.Y - (0.5 - (bApplyPivot ? Owner->Pivot.Y : 0)) * DeltaHeight);\n            break;\n\n        case ERelationType::Bottom_Middle:\n        case ERelationType::Bottom_Top:\n        case ERelationType::Bottom_Bottom:\n            Owner->SetY(Owner->Position.Y - (1 - (bApplyPivot ? Owner->Pivot.Y : 0)) * DeltaHeight);\n            break;\n\n        default:\n            break;\n        }\n    }\n\n    if (Pos != Owner->Position)\n    {\n        FVector2D Delta = Owner->Position - Pos;\n\n        Owner->UpdateGearFromRelations(1, Delta);\n\n        if (Owner->Parent.IsValid())\n        {\n            const TArray<UTransition*>& arr = Owner->Parent->GetTransitions();\n            for (auto& it : arr)\n                it->UpdateFromRelations(Owner->ID, Delta);\n        }\n    }\n}\n\nvoid FRelationItem::ApplyOnXYChanged(UGObject* InTarget, const FRelationDef& info, float dx, float dy)\n{\n    float tmp;\n\n    switch (info.Type)\n    {\n    case ERelationType::Left_Left:\n    case ERelationType::Left_Center:\n    case ERelationType::Left_Right:\n    case ERelationType::Center_Center:\n    case ERelationType::Right_Left:\n    case ERelationType::Right_Center:\n    case ERelationType::Right_Right:\n        Owner->SetX(Owner->Position.X + dx);\n        break;\n\n    case ERelationType::Top_Top:\n    case ERelationType::Top_Middle:\n    case ERelationType::Top_Bottom:\n    case ERelationType::Middle_Middle:\n    case ERelationType::Bottom_Top:\n    case ERelationType::Bottom_Middle:\n    case ERelationType::Bottom_Bottom:\n        Owner->SetY(Owner->Position.Y + dy);\n        break;\n\n    case ERelationType::Width:\n    case ERelationType::Height:\n        break;\n\n    case ERelationType::LeftExt_Left:\n    case ERelationType::LeftExt_Right:\n        if (Owner != InTarget->Parent)\n        {\n            tmp = Owner->GetXMin();\n            Owner->SetWidth(Owner->RawSize.X - dx);\n            Owner->SetXMin(tmp + dx);\n        }\n        else\n            Owner->SetWidth(Owner->RawSize.X - dx);\n        break;\n\n    case ERelationType::RightExt_Left:\n    case ERelationType::RightExt_Right:\n        if (Owner != InTarget->Parent)\n        {\n            tmp = Owner->GetXMin();\n            Owner->SetWidth(Owner->RawSize.X + dx);\n            Owner->SetXMin(tmp);\n        }\n        else\n            Owner->SetWidth(Owner->RawSize.X + dx);\n        break;\n\n    case ERelationType::TopExt_Top:\n    case ERelationType::TopExt_Bottom:\n        if (Owner != InTarget->Parent)\n        {\n            tmp = Owner->GetYMin();\n            Owner->SetHeight(Owner->RawSize.Y - dy);\n            Owner->SetYMin(tmp + dy);\n        }\n        else\n            Owner->SetHeight(Owner->RawSize.Y - dy);\n        break;\n\n    case ERelationType::BottomExt_Top:\n    case ERelationType::BottomExt_Bottom:\n        if (Owner != InTarget->Parent)\n        {\n            tmp = Owner->GetYMin();\n            Owner->SetHeight(Owner->RawSize.Y + dy);\n            Owner->SetYMin(tmp);\n        }\n        else\n            Owner->SetHeight(Owner->RawSize.Y + dy);\n        break;\n\n    default:\n        break;\n    }\n}\n\nvoid FRelationItem::ApplyOnSizeChanged(UGObject* InTarget, const FRelationDef& info)\n{\n    float pos = 0, pivot = 0, delta = 0;\n    if (info.Axis == 0)\n    {\n        if (InTarget != Owner->Parent)\n        {\n            pos = InTarget->Position.X;\n            if (InTarget->bPivotAsAnchor)\n                pivot = InTarget->Pivot.X;\n        }\n\n        if (info.bPercent)\n        {\n            if (TargetData.Z != 0)\n                delta = InTarget->Size.X / TargetData.Z;\n        }\n        else\n            delta = InTarget->Size.X - TargetData.Z;\n    }\n    else\n    {\n        if (InTarget != Owner->Parent)\n        {\n            pos = InTarget->Position.Y;\n            if (InTarget->bPivotAsAnchor)\n                pivot = InTarget->Pivot.Y;\n        }\n\n        if (info.bPercent)\n        {\n            if (TargetData.W != 0)\n                delta = InTarget->Size.Y / TargetData.W;\n        }\n        else\n            delta = InTarget->Size.Y - TargetData.W;\n    }\n\n    float v, tmp;\n    switch (info.Type)\n    {\n    case ERelationType::Left_Left:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() - pos) * delta);\n        else if (pivot != 0)\n            Owner->SetX(Owner->Position.X + delta * (-pivot));\n        break;\n    case ERelationType::Left_Center:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() - pos) * delta);\n        else\n            Owner->SetX(Owner->Position.X + delta * (0.5f - pivot));\n        break;\n    case ERelationType::Left_Right:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() - pos) * delta);\n        else\n            Owner->SetX(Owner->Position.X + delta * (1 - pivot));\n        break;\n    case ERelationType::Center_Center:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X * 0.5f - pos) * delta - Owner->RawSize.X * 0.5f);\n        else\n            Owner->SetX(Owner->Position.X + delta * (0.5f - pivot));\n        break;\n    case ERelationType::Right_Left:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X - pos) * delta - Owner->RawSize.X);\n        else if (pivot != 0)\n            Owner->SetX(Owner->Position.X + delta * (-pivot));\n        break;\n    case ERelationType::Right_Center:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X - pos) * delta - Owner->RawSize.X);\n        else\n            Owner->SetX(Owner->Position.X + delta * (0.5f - pivot));\n        break;\n    case ERelationType::Right_Right:\n        if (info.bPercent)\n            Owner->SetXMin(pos + (Owner->GetXMin() + Owner->RawSize.X - pos) * delta - Owner->RawSize.X);\n        else\n            Owner->SetX(Owner->Position.X + delta * (1 - pivot));\n        break;\n\n    case ERelationType::Top_Top:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() - pos) * delta);\n        else if (pivot != 0)\n            Owner->SetY(Owner->Position.Y + delta * (-pivot));\n        break;\n    case ERelationType::Top_Middle:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() - pos) * delta);\n        else\n            Owner->SetY(Owner->Position.Y + delta * (0.5f - pivot));\n        break;\n    case ERelationType::Top_Bottom:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() - pos) * delta);\n        else\n            Owner->SetY(Owner->Position.Y + delta * (1 - pivot));\n        break;\n    case ERelationType::Middle_Middle:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y * 0.5f - pos) * delta - Owner->RawSize.Y * 0.5f);\n        else\n            Owner->SetY(Owner->Position.Y + delta * (0.5f - pivot));\n        break;\n    case ERelationType::Bottom_Top:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y - pos) * delta - Owner->RawSize.Y);\n        else if (pivot != 0)\n            Owner->SetY(Owner->Position.Y + delta * (-pivot));\n        break;\n    case ERelationType::Bottom_Middle:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y - pos) * delta - Owner->RawSize.Y);\n        else\n            Owner->SetY(Owner->Position.Y + delta * (0.5f - pivot));\n        break;\n    case ERelationType::Bottom_Bottom:\n        if (info.bPercent)\n            Owner->SetYMin(pos + (Owner->GetYMin() + Owner->RawSize.Y - pos) * delta - Owner->RawSize.Y);\n        else\n            Owner->SetY(Owner->Position.Y + delta * (1 - pivot));\n        break;\n\n    case ERelationType::Width:\n        if (Owner->bUnderConstruct && Owner == InTarget->Parent)\n            v = Owner->SourceSize.X - InTarget->InitSize.X;\n        else\n            v = Owner->RawSize.X - TargetData.Z;\n        if (info.bPercent)\n            v = v * delta;\n        if (InTarget == Owner->Parent)\n        {\n            if (Owner->bPivotAsAnchor)\n            {\n                tmp = Owner->GetXMin();\n                Owner->SetSize(FVector2D(InTarget->Size.X + v, Owner->RawSize.Y), true);\n                Owner->SetXMin(tmp);\n            }\n            else\n                Owner->SetSize(FVector2D(InTarget->Size.X + v, Owner->RawSize.Y), true);\n        }\n        else\n            Owner->SetWidth(InTarget->Size.X + v);\n        break;\n    case ERelationType::Height:\n        if (Owner->bUnderConstruct && Owner == InTarget->Parent)\n            v = Owner->SourceSize.Y - InTarget->InitSize.Y;\n        else\n            v = Owner->RawSize.Y - TargetData.W;\n        if (info.bPercent)\n            v = v * delta;\n        if (InTarget == Owner->Parent)\n        {\n            if (Owner->bPivotAsAnchor)\n            {\n                tmp = Owner->GetYMin();\n                Owner->SetSize(FVector2D(Owner->RawSize.X, InTarget->Size.Y + v), true);\n                Owner->SetYMin(tmp);\n            }\n            else\n                Owner->SetSize(FVector2D(Owner->RawSize.X, InTarget->Size.Y + v), true);\n        }\n        else\n            Owner->SetHeight(InTarget->Size.Y + v);\n        break;\n\n    case ERelationType::LeftExt_Left:\n        tmp = Owner->GetXMin();\n        if (info.bPercent)\n            v = pos + (tmp - pos) * delta - tmp;\n        else\n            v = delta * (-pivot);\n        Owner->SetWidth(Owner->RawSize.X - v);\n        Owner->SetXMin(tmp + v);\n        break;\n    case ERelationType::LeftExt_Right:\n        tmp = Owner->GetXMin();\n        if (info.bPercent)\n            v = pos + (tmp - pos) * delta - tmp;\n        else\n            v = delta * (1 - pivot);\n        Owner->SetWidth(Owner->RawSize.X - v);\n        Owner->SetXMin(tmp + v);\n        break;\n    case ERelationType::RightExt_Left:\n        tmp = Owner->GetXMin();\n        if (info.bPercent)\n            v = pos + (tmp + Owner->RawSize.X - pos) * delta - (tmp + Owner->RawSize.X);\n        else\n            v = delta * (-pivot);\n        Owner->SetWidth(Owner->RawSize.X + v);\n        Owner->SetXMin(tmp);\n        break;\n    case ERelationType::RightExt_Right:\n        tmp = Owner->GetXMin();\n        if (info.bPercent)\n        {\n            if (Owner == InTarget->Parent)\n            {\n                if (Owner->bUnderConstruct)\n                    Owner->SetWidth(pos + InTarget->Size.X - InTarget->Size.X * pivot +\n                    (Owner->SourceSize.X - pos - InTarget->InitSize.X + InTarget->InitSize.X * pivot) * delta);\n                else\n                    Owner->SetWidth(pos + (Owner->RawSize.X - pos) * delta);\n            }\n            else\n            {\n                v = pos + (tmp + Owner->RawSize.X - pos) * delta - (tmp + Owner->RawSize.X);\n                Owner->SetWidth(Owner->RawSize.X + v);\n                Owner->SetXMin(tmp);\n            }\n        }\n        else\n        {\n            if (Owner == InTarget->Parent)\n            {\n                if (Owner->bUnderConstruct)\n                    Owner->SetWidth(Owner->SourceSize.X + (InTarget->Size.X - InTarget->InitSize.X) * (1 - pivot));\n                else\n                    Owner->SetWidth(Owner->RawSize.X + delta * (1 - pivot));\n            }\n            else\n            {\n                v = delta * (1 - pivot);\n                Owner->SetWidth(Owner->RawSize.X + v);\n                Owner->SetXMin(tmp);\n            }\n        }\n        break;\n    case ERelationType::TopExt_Top:\n        tmp = Owner->GetYMin();\n        if (info.bPercent)\n            v = pos + (tmp - pos) * delta - tmp;\n        else\n            v = delta * (-pivot);\n        Owner->SetHeight(Owner->RawSize.Y - v);\n        Owner->SetYMin(tmp + v);\n        break;\n    case ERelationType::TopExt_Bottom:\n        tmp = Owner->GetYMin();\n        if (info.bPercent)\n            v = pos + (tmp - pos) * delta - tmp;\n        else\n            v = delta * (1 - pivot);\n        Owner->SetHeight(Owner->RawSize.Y - v);\n        Owner->SetYMin(tmp + v);\n        break;\n    case ERelationType::BottomExt_Top:\n        tmp = Owner->GetYMin();\n        if (info.bPercent)\n            v = pos + (tmp + Owner->RawSize.Y - pos) * delta - (tmp + Owner->RawSize.Y);\n        else\n            v = delta * (-pivot);\n        Owner->SetHeight(Owner->RawSize.Y + v);\n        Owner->SetYMin(tmp);\n        break;\n    case ERelationType::BottomExt_Bottom:\n        tmp = Owner->GetYMin();\n        if (info.bPercent)\n        {\n            if (Owner == InTarget->Parent)\n            {\n                if (Owner->bUnderConstruct)\n                    Owner->SetHeight(pos + InTarget->Size.Y - InTarget->Size.Y * pivot +\n                    (Owner->SourceSize.Y - pos - InTarget->InitSize.Y + InTarget->InitSize.Y * pivot) * delta);\n                else\n                    Owner->SetHeight(pos + (Owner->RawSize.Y - pos) * delta);\n            }\n            else\n            {\n                v = pos + (tmp + Owner->RawSize.Y - pos) * delta - (tmp + Owner->RawSize.Y);\n                Owner->SetHeight(Owner->RawSize.Y + v);\n                Owner->SetYMin(tmp);\n            }\n        }\n        else\n        {\n            if (Owner == InTarget->Parent)\n            {\n                if (Owner->bUnderConstruct)\n                    Owner->SetHeight(Owner->SourceSize.Y + (InTarget->Size.Y - InTarget->InitSize.Y) * (1 - pivot));\n                else\n                    Owner->SetHeight(Owner->RawSize.Y + delta * (1 - pivot));\n            }\n            else\n            {\n                v = delta * (1 - pivot);\n                Owner->SetHeight(Owner->RawSize.Y + v);\n                Owner->SetYMin(tmp);\n            }\n        }\n        break;\n    default:\n        break;\n    }\n}\n\nvoid FRelationItem::AddRefTarget(UGObject* InTarget)\n{\n    if (!InTarget)\n        return;\n\n    if (InTarget != Owner->GetParent())\n        PositionDelegateHandle = InTarget->OnPositionChanged().AddRaw(this, &FRelationItem::OnTargetXYChanged);\n    SizeDelegateHandle = InTarget->OnSizeChanged().AddRaw(this, &FRelationItem::OnTargetSizeChanged);\n\n    TargetData.X = InTarget->Position.X;\n    TargetData.Y = InTarget->Position.Y;\n    TargetData.Z = InTarget->Size.X;\n    TargetData.W = InTarget->Size.Y;\n}\n\nvoid FRelationItem::ReleaseRefTarget()\n{\n    if (!Target.IsValid())\n        return;\n\n    Target->OnPositionChanged().Remove(PositionDelegateHandle);\n    Target->OnSizeChanged().Remove(SizeDelegateHandle);\n}\n\nvoid FRelationItem::OnTargetXYChanged()\n{\n    if (Owner->Relations->Handling != nullptr || (Owner->Group.IsValid() && Owner->Group->Updating != 0))\n    {\n        TargetData.X = Target->Position.X;\n        TargetData.Y = Target->Position.Y;\n        return;\n    }\n\n    Owner->Relations->Handling = Target.Get();\n\n    FVector2D Pos = Owner->Position;\n    float dx = Target->Position.X - TargetData.X;\n    float dy = Target->Position.Y - TargetData.Y;\n\n    for (auto& it : Defs)\n        ApplyOnXYChanged(Target.Get(), it, dx, dy);\n\n    TargetData.X = Target->Position.X;\n    TargetData.Y = Target->Position.Y;\n\n    if (Pos != Owner->Position)\n    {\n        FVector2D Delta = Owner->Position - Pos;\n\n        Owner->UpdateGearFromRelations(1, Delta);\n\n        if (Owner->Parent.IsValid())\n        {\n            const TArray<UTransition*>& arr = Owner->Parent->GetTransitions();\n            for (auto& it : arr)\n                it->UpdateFromRelations(Owner->ID, Delta);\n        }\n    }\n\n    Owner->Relations->Handling = nullptr;\n}\n\nvoid FRelationItem::OnTargetSizeChanged()\n{\n    if (Owner->Relations->Handling != nullptr\n        || (Owner->Group.IsValid() && Owner->Group->Updating != 0))\n    {\n        TargetData.Z = Target->Size.X;\n        TargetData.W = Target->Size.Y;\n        return;\n    }\n    Owner->Relations->Handling = Target.Get();\n\n    FVector2D Pos = Owner->Position;\n    FVector2D RawSize = Owner->RawSize;\n\n    for (auto& it : Defs)\n        ApplyOnSizeChanged(Target.Get(), it);\n\n    TargetData.Z = Target->Size.X;\n    TargetData.W = Target->Size.Y;\n\n    if (Pos != Owner->Position)\n    {\n        FVector2D Delta = Owner->Position - Pos;\n\n        Owner->UpdateGearFromRelations(1, Delta);\n\n        if (Owner->Parent.IsValid())\n        {\n            const TArray<UTransition*>& arr = Owner->Parent->GetTransitions();\n            for (auto& it : arr)\n                it->UpdateFromRelations(Owner->ID, Delta);\n        }\n    }\n\n    if (RawSize != Owner->RawSize)\n    {\n        FVector2D Delta = Owner->RawSize - RawSize;\n\n        Owner->UpdateGearFromRelations(2, Delta);\n    }\n\n    Owner->Relations->Handling = nullptr;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Relations.cpp",
    "content": "#include \"UI/Relations.h\"\n#include \"UI/GComponent.h\"\n#include \"Utils/ByteBuffer.h\"\n\nFRelations::FRelations(UGObject* InOwner) :\n    Handling(nullptr)\n{\n    Owner = InOwner;\n}\n\nFRelations::~FRelations()\n{\n}\n\nvoid FRelations::Add(UGObject * InTarget, ERelationType ERelationType)\n{\n    Add(InTarget, ERelationType, false);\n}\n\nvoid FRelations::Add(UGObject * InTarget, ERelationType ERelationType, bool bUsePercent)\n{\n    verifyf(InTarget, TEXT(\"target is null\"));\n\n    for (auto& it : Items)\n    {\n        if (it.GetTarget() == InTarget)\n        {\n            it.Add(ERelationType, bUsePercent);\n            return;\n        }\n    }\n    FRelationItem* newItem = new FRelationItem(Owner);\n    newItem->SetTarget(InTarget);\n    newItem->Add(ERelationType, bUsePercent);\n    Items.Add(newItem);\n}\n\nvoid FRelations::Remove(UGObject * InTarget, ERelationType ERelationType)\n{\n    int32 Index = 0;\n    while (Index < Items.Num())\n    {\n        FRelationItem& Item = Items[Index];\n        if (Item.GetTarget() == InTarget)\n        {\n            Item.Remove(ERelationType);\n            if (Item.IsEmpty())\n            {\n                Items.RemoveAt(Index);\n            }\n            else\n                Index++;\n        }\n        else\n            Index++;\n    }\n}\n\nbool FRelations::Contains(UGObject * InTarget)\n{\n    for (auto& it : Items)\n    {\n        if (it.GetTarget() == InTarget)\n            return true;\n    }\n\n    return false;\n}\n\nvoid FRelations::ClearFor(UGObject * InTarget)\n{\n    int32 Index = 0;\n    while (Index < Items.Num())\n    {\n        FRelationItem& Item = Items[Index];\n        if (Item.GetTarget() == InTarget)\n            Items.RemoveAt(Index);\n        else\n            Index++;\n    }\n}\n\nvoid FRelations::ClearAll()\n{\n    Items.Reset();\n}\n\nvoid FRelations::CopyFrom(const FRelations & Source)\n{\n    ClearAll();\n\n    for (auto& it : Source.Items)\n    {\n        FRelationItem* item = new FRelationItem(Owner);\n        item->CopyFrom(it);\n        Items.Add(item);\n    }\n}\n\nvoid FRelations::OnOwnerSizeChanged(const FVector2D& Delta, bool bApplyPivot)\n{\n    for (auto& it : Items)\n        it.ApplyOnSelfSizeChanged(Delta.X, Delta.Y, bApplyPivot);\n}\n\nbool FRelations::IsEmpty() const\n{\n    return Items.Num() == 0;\n}\n\nvoid FRelations::Setup(FByteBuffer * Buffer, bool bParentToChild)\n{\n    int32 cnt = Buffer->ReadByte();\n    UGObject* target;\n    for (int32 i = 0; i < cnt; i++)\n    {\n        int16 targetIndex = Buffer->ReadShort();\n        if (targetIndex == -1)\n            target = Owner->GetParent();\n        else if (bParentToChild)\n            target = (Cast<UGComponent>(Owner))->GetChildAt(targetIndex);\n        else\n            target = Owner->GetParent()->GetChildAt(targetIndex);\n\n        FRelationItem* newItem = new FRelationItem(Owner);\n        newItem->SetTarget(target);\n        Items.Add(newItem);\n\n        int32 cnt2 = Buffer->ReadByte();\n        for (int32 j = 0; j < cnt2; j++)\n        {\n            ERelationType rt = (ERelationType)Buffer->ReadByte();\n            bool usePercent = Buffer->ReadBool();\n            newItem->InternalAdd(rt, usePercent);\n        }\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/ScrollPane.cpp",
    "content": "#include \"UI/ScrollPane.h\"\n#include \"Engine/World.h\"\n#include \"Engine/GameViewportClient.h\"\n#include \"TimerManager.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GList.h\"\n#include \"UI/GController.h\"\n#include \"UI/GScrollBar.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Tween/GTween.h\"\n#include \"Widgets/SContainer.h\"\n#include \"FairyApplication.h\"\n\nTWeakObjectPtr<UScrollPane> UScrollPane::DraggingPane;\nint32 UScrollPane::GestureFlag = 0;\n\nstatic const float TWEEN_TIME_GO = 0.5f;      //tween time for SetPos(ani)\nstatic const float TWEEN_TIME_DEFAULT = 0.3f; //min tween time for inertial scroll\nstatic const float PULL_RATIO = 0.5f;         //pull down/up ratio\n\nstatic inline float sp_EaseFunc(float t, float d)\n{\n    t = t / d - 1;\n    return t * t * t + 1; //cubicOut\n}\n\nUScrollPane::UScrollPane()\n{\n}\n\nUScrollPane::~UScrollPane()\n{\n}\n\nvoid UScrollPane::Setup(FByteBuffer* Buffer)\n{\n    Owner = Cast<UGComponent>(GetOuter());\n    Container = Owner->Container;\n    ScrollStep = FUIConfig::Config.DefaultScrollStep;\n    DecelerationRate = FUIConfig::Config.DefaultScrollDecelerationRate;\n    bTouchEffect = FUIConfig::Config.DefaultScrollTouchEffect;\n    bBouncebackEffect = FUIConfig::Config.DefaultScrollBounceEffect;\n    bMouseWheelEnabled = true;\n    PageSize.Set(0, 0);\n\n    MaskContainer = SNew(SContainer);\n    MaskContainer->SetOpaque(false);\n    Owner->RootContainer->RemoveChild(Container.ToSharedRef());\n    Owner->RootContainer->AddChild(MaskContainer.ToSharedRef());\n    MaskContainer->AddChild(Container.ToSharedRef());\n\n    Owner->On(FUIEvents::MouseWheel).AddUObject(this, &UScrollPane::OnMouseWheel);\n    Owner->On(FUIEvents::TouchBegin).AddUObject(this, &UScrollPane::OnTouchBegin);\n    Owner->On(FUIEvents::TouchMove).AddUObject(this, &UScrollPane::OnTouchMove);\n    Owner->On(FUIEvents::TouchEnd).AddUObject(this, &UScrollPane::OnTouchEnd);\n    Owner->On(FUIEvents::RemovedFromStage).AddLambda([this](UEventContext*) {\n        if (DraggingPane.Get() == this)\n            DraggingPane.Reset();\n    });\n\n    ScrollType = (EScrollType)Buffer->ReadByte();\n    EScrollBarDisplayType scrollBarDisplay = (EScrollBarDisplayType)Buffer->ReadByte();\n    int32 flags = Buffer->ReadInt();\n\n    if (Buffer->ReadBool())\n    {\n        ScrollBarMargin.Top = Buffer->ReadInt();\n        ScrollBarMargin.Bottom = Buffer->ReadInt();\n        ScrollBarMargin.Left = Buffer->ReadInt();\n        ScrollBarMargin.Right = Buffer->ReadInt();\n    }\n\n    const FString& vtScrollBarRes = Buffer->ReadS();\n    const FString& hzScrollBarRes = Buffer->ReadS();\n    const FString& headerRes = Buffer->ReadS();\n    const FString& footerRes = Buffer->ReadS();\n\n    bDisplayOnLeft = (flags & 1) != 0;\n    bSnapToItem = (flags & 2) != 0;\n    bDisplayInDemand = (flags & 4) != 0;\n    bPageMode = (flags & 8) != 0;\n    if ((flags & 16) != 0)\n        bTouchEffect = true;\n    else if ((flags & 32) != 0)\n        bTouchEffect = false;\n    if ((flags & 64) != 0)\n        bBouncebackEffect = true;\n    else if ((flags & 128) != 0)\n        bBouncebackEffect = false;\n    bInertiaDisabled = (flags & 256) != 0;\n    if ((flags & 512) == 0)\n        MaskContainer->SetClipping(EWidgetClipping::ClipToBoundsAlways);\n    bFloating = (flags & 1024) != 0;\n    bDontClipMargin = (flags & 2048) != 0;\n\n    if (scrollBarDisplay == EScrollBarDisplayType::Default)\n        scrollBarDisplay = FUIConfig::Config.DefaultScrollBarDisplay;\n\n    if (scrollBarDisplay != EScrollBarDisplayType::Hidden)\n    {\n        if (ScrollType == EScrollType::Both || ScrollType == EScrollType::Vertical)\n        {\n            \n            const FString& res = vtScrollBarRes.Len() == 0 ? FUIConfig::Config.VerticalScrollBar : vtScrollBarRes;\n            if (res.Len() > 0)\n            {\n                VtScrollBar = Cast<UGScrollBar>(UUIPackage::CreateObjectFromURL(res, Owner));\n                if (VtScrollBar == nullptr)\n                {\n                    UE_LOG(LogFairyGUI, Warning, TEXT(\"cannot create scrollbar from %s\"), *res);\n                }\n                else\n                {\n                    VtScrollBar->SetScrollPane(this, true);\n                    Owner->RootContainer->AddChild(VtScrollBar->GetDisplayObject());\n                }\n            }\n        }\n        if (ScrollType == EScrollType::Both || ScrollType == EScrollType::Horizontal)\n        {\n            const FString& res = hzScrollBarRes.Len() == 0 ? FUIConfig::Config.HorizontalScrollBar : hzScrollBarRes;\n            if (res.Len() > 0)\n            {\n                HzScrollBar = Cast<UGScrollBar>(UUIPackage::CreateObjectFromURL(res, Owner));\n                if (HzScrollBar == nullptr)\n                {\n                    UE_LOG(LogFairyGUI, Warning, TEXT(\"cannot create scrollbar from %s\"), *res);\n                }\n                else\n                {\n                    HzScrollBar->SetScrollPane(this, false);\n                    Owner->RootContainer->AddChild(HzScrollBar->GetDisplayObject());\n                }\n            }\n        }\n\n        bScrollBarDisplayAuto = scrollBarDisplay == EScrollBarDisplayType::Auto;\n        if (bScrollBarDisplayAuto)\n        {\n            if (VtScrollBar != nullptr)\n                VtScrollBar->SetVisible(false);\n            if (HzScrollBar != nullptr)\n                HzScrollBar->SetVisible(false);\n\n            Owner->On(FUIEvents::RollOver).AddUObject(this, &UScrollPane::OnRollOver);\n            Owner->On(FUIEvents::RollOut).AddUObject(this, &UScrollPane::OnRollOut);\n        }\n    }\n    else\n        bMouseWheelEnabled = false;\n\n    if (headerRes.Len() > 0)\n    {\n        Header = Cast<UGComponent>(UUIPackage::CreateObjectFromURL(headerRes, Owner));\n        if (Header == nullptr)\n        {\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"cannot create UScrollPane header from %s\"), *headerRes);\n        }\n        else\n        {\n            Header->SetVisible(false);\n            Owner->RootContainer->AddChild(Header->GetDisplayObject());\n        }\n    }\n\n    if (footerRes.Len() > 0)\n    {\n        Footer = Cast<UGComponent>(UUIPackage::CreateObjectFromURL(footerRes, Owner));\n        if (Footer == nullptr)\n        {\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"cannot create UScrollPane footer from %s\"), *footerRes);\n        }\n        else\n        {\n            Footer->SetVisible(false);\n            Owner->RootContainer->AddChild(Footer->GetDisplayObject());\n        }\n    }\n\n    if (Header != nullptr || Footer != nullptr)\n        RefreshBarAxis = (ScrollType == EScrollType::Both || ScrollType == EScrollType::Vertical) ? 1 : 0;\n\n    SetSize(Owner->GetSize());\n}\n\nvoid UScrollPane::SetPosX(float Value, bool bAnimation)\n{\n    Owner->EnsureBoundsCorrect();\n\n    if (LoopMode == 1)\n        LoopCheckingNewPos(Value, 0);\n\n    Value = FMath::Clamp(Value, 0.f, OverlapSize.X);\n    if (Value != XPos)\n    {\n        XPos = Value;\n        PosChanged(bAnimation);\n    }\n}\n\nvoid UScrollPane::SetPosY(float Value, bool bAnimation)\n{\n    Owner->EnsureBoundsCorrect();\n\n    if (LoopMode == 2)\n        LoopCheckingNewPos(Value, 1);\n\n    Value = FMath::Clamp(Value, 0.f, OverlapSize.Y);\n    if (Value != YPos)\n    {\n        YPos = Value;\n        PosChanged(bAnimation);\n    }\n}\n\nfloat UScrollPane::GetPercX() const\n{\n    return OverlapSize.X == 0 ? 0 : XPos / OverlapSize.X;\n}\n\nvoid UScrollPane::SetPercX(float Value, bool bAnimation)\n{\n    Owner->EnsureBoundsCorrect();\n    SetPosX(OverlapSize.X * FMath::Clamp(Value, 0.f, 1.f), bAnimation);\n}\n\nfloat UScrollPane::GetPercY() const\n{\n    return OverlapSize.Y == 0 ? 0 : YPos / OverlapSize.Y;\n}\n\nvoid UScrollPane::SetPercY(float Value, bool bAnimation)\n{\n    Owner->EnsureBoundsCorrect();\n    SetPosY(OverlapSize.Y * FMath::Clamp(Value, 0.f, 1.f), bAnimation);\n}\n\nbool UScrollPane::IsBottomMost() const\n{\n    return YPos == OverlapSize.Y || OverlapSize.Y == 0;\n}\n\nbool UScrollPane::IsRightMost() const\n{\n    return XPos == OverlapSize.X || OverlapSize.X == 0;\n}\n\nvoid UScrollPane::ScrollLeft(float Ratio, bool bAnimation)\n{\n    if (bPageMode)\n        SetPosX(XPos - PageSize.X * Ratio, bAnimation);\n    else\n        SetPosX(XPos - ScrollStep * Ratio, bAnimation);\n}\n\nvoid UScrollPane::ScrollRight(float Ratio, bool bAnimation)\n{\n    if (bPageMode)\n        SetPosX(XPos + PageSize.X * Ratio, bAnimation);\n    else\n        SetPosX(XPos + ScrollStep * Ratio, bAnimation);\n}\n\nvoid UScrollPane::ScrollUp(float Ratio, bool bAnimation)\n{\n    if (bPageMode)\n        SetPosY(YPos - PageSize.Y * Ratio, bAnimation);\n    else\n        SetPosY(YPos - ScrollStep * Ratio, bAnimation);\n}\n\nvoid UScrollPane::ScrollDown(float Ratio, bool bAnimation)\n{\n    if (bPageMode)\n        SetPosY(YPos + PageSize.Y * Ratio, bAnimation);\n    else\n        SetPosY(YPos + ScrollStep * Ratio, bAnimation);\n}\n\nvoid UScrollPane::ScrollTop(bool bAnimation)\n{\n    SetPercY(0, bAnimation);\n}\n\nvoid UScrollPane::ScrollBottom(bool bAnimation)\n{\n    SetPercY(1, bAnimation);\n}\n\nvoid UScrollPane::ScrollToView(UGObject* Obj, bool bAnimation, bool bSetFirst)\n{\n    Owner->EnsureBoundsCorrect();\n    if (bNeedRefresh)\n        Refresh();\n\n    FBox2D rect(Obj->GetPosition(), Obj->GetPosition() + Obj->GetSize());\n    if (Obj->GetParent() != Owner)\n    {\n        rect = Obj->GetParent()->LocalToGlobalRect(rect);\n        rect = Owner->GlobalToLocalRect(rect);\n    }\n    ScrollToView(rect, bAnimation, bSetFirst);\n}\n\nvoid UScrollPane::ScrollToView(const FBox2D& Rect, bool bAnimation, bool bSetFirst)\n{\n    Owner->EnsureBoundsCorrect();\n    if (bNeedRefresh)\n        Refresh();\n\n    if (OverlapSize.Y > 0)\n    {\n        float bottom = YPos + ViewSize.Y;\n        if (bSetFirst || Rect.Min.Y <= YPos || Rect.GetSize().Y >= ViewSize.Y)\n        {\n            if (bPageMode)\n                SetPosY(FMath::FloorToFloat(Rect.Min.Y / PageSize.Y) * PageSize.Y, bAnimation);\n            else\n                SetPosY(Rect.Min.Y, bAnimation);\n        }\n        else if (Rect.Max.Y > bottom)\n        {\n            if (bPageMode)\n                SetPosY(FMath::FloorToFloat(Rect.Min.Y / PageSize.Y) * PageSize.Y, bAnimation);\n            else if (Rect.GetSize().Y <= ViewSize.Y / 2)\n                SetPosY(Rect.Min.Y + Rect.GetSize().Y * 2 - ViewSize.Y, bAnimation);\n            else\n                SetPosY(Rect.Max.Y - ViewSize.Y, bAnimation);\n        }\n    }\n    if (OverlapSize.X > 0)\n    {\n        float right = XPos + ViewSize.X;\n        if (bSetFirst || Rect.Min.X <= XPos || Rect.GetSize().X >= ViewSize.X)\n        {\n            if (bPageMode)\n                SetPosX(FMath::FloorToFloat(Rect.Min.X / PageSize.X) * PageSize.X, bAnimation);\n            SetPosX(Rect.Min.X, bAnimation);\n        }\n        else if (Rect.Max.X > right)\n        {\n            if (bPageMode)\n                SetPosX(FMath::FloorToFloat(Rect.Min.X / PageSize.X) * PageSize.X, bAnimation);\n            else if (Rect.GetSize().X <= ViewSize.X / 2)\n                SetPosX(Rect.Min.X + Rect.GetSize().X * 2 - ViewSize.X, bAnimation);\n            else\n                SetPosX(Rect.Max.X - ViewSize.X, bAnimation);\n        }\n    }\n\n    if (!bAnimation && bNeedRefresh)\n        Refresh();\n}\n\nbool UScrollPane::IsChildInView(UGObject* Obj) const\n{\n    if (OverlapSize.Y > 0)\n    {\n        float dist = Obj->GetY() + Container->GetPosition().Y;\n        if (dist <= -Obj->GetHeight() || dist >= ViewSize.Y)\n            return false;\n    }\n    if (OverlapSize.X > 0)\n    {\n        float dist = Obj->GetX() + Container->GetPosition().X;\n        if (dist <= -Obj->GetWidth() || dist >= ViewSize.X)\n            return false;\n    }\n\n    return true;\n}\n\nint32 UScrollPane::GetPageX() const\n{\n    if (!bPageMode)\n        return 0;\n\n    int32 page = FMath::FloorToInt(XPos / PageSize.X);\n    if (XPos - page * PageSize.X > PageSize.X * 0.5f)\n        page++;\n\n    return page;\n}\n\nvoid UScrollPane::SetPageX(int32 Value, bool bAnimation)\n{\n    if (!bPageMode)\n        return;\n\n    Owner->EnsureBoundsCorrect();\n\n    if (OverlapSize.X > 0)\n        SetPosX(Value * PageSize.X, bAnimation);\n}\n\nint32 UScrollPane::GetPageY() const\n{\n    if (!bPageMode)\n        return 0;\n\n    int32 page = FMath::FloorToInt(YPos / PageSize.Y);\n    if (YPos - page * PageSize.Y > PageSize.Y * 0.5f)\n        page++;\n\n    return page;\n}\n\nvoid UScrollPane::SetPageY(int32 Value, bool bAnimation)\n{\n    if (!bPageMode)\n        return;\n\n    Owner->EnsureBoundsCorrect();\n\n    if (OverlapSize.Y > 0)\n        SetPosY(Value * PageSize.Y, bAnimation);\n}\n\nfloat UScrollPane::GetScrollingPosX() const\n{\n    return FMath::Clamp(-Container->GetPosition().X, 0.f, OverlapSize.X);\n}\n\nfloat UScrollPane::GetScrollingPosY() const\n{\n    return FMath::Clamp(-Container->GetPosition().Y, 0.f, OverlapSize.Y);\n}\n\nvoid UScrollPane::SetViewWidth(float Width)\n{\n    Width = Width + Owner->Margin.Left + Owner->Margin.Right;\n    if (VtScrollBar != nullptr && !bFloating)\n        Width += VtScrollBar->GetWidth();\n    Owner->SetWidth(Width);\n}\n\nvoid UScrollPane::SetViewHeight(float Height)\n{\n    Height = Height + Owner->Margin.Top + Owner->Margin.Bottom;\n    if (HzScrollBar != nullptr && !bFloating)\n        Height += HzScrollBar->GetHeight();\n    Owner->SetHeight(Height);\n}\n\nvoid UScrollPane::LockHeader(int32 Size)\n{\n    if (HeaderLockedSize == Size)\n        return;\n\n    const FVector2D& cpos = Container->GetPosition();\n\n    HeaderLockedSize = Size;\n    if (!bDispatchingPullDown && cpos.Component(RefreshBarAxis) >= 0)\n    {\n        TweenStart = cpos;\n        TweenChange.Set(0, 0);\n        TweenChange[RefreshBarAxis] = HeaderLockedSize - TweenStart.Component(RefreshBarAxis);\n        TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);\n        StartTween(2);\n    }\n}\n\nvoid UScrollPane::LockFooter(int32 Size)\n{\n    if (FooterLockedSize == Size)\n        return;\n\n    const FVector2D& cpos = Container->GetPosition();\n\n    FooterLockedSize = Size;\n    if (!bDispatchingPullUp && cpos.Component(RefreshBarAxis) >= 0)\n    {\n        TweenStart = cpos;\n        TweenChange.Set(0, 0);\n        float max = OverlapSize.Component(RefreshBarAxis);\n        if (max == 0)\n            max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f);\n        else\n            max += FooterLockedSize;\n        TweenChange.Component(RefreshBarAxis) = -max - TweenStart.Component(RefreshBarAxis);\n        TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);\n        StartTween(2);\n    }\n}\n\nvoid UScrollPane::CancelDragging()\n{\n    if (DraggingPane.Get() == this)\n        DraggingPane.Reset();\n\n    GestureFlag = 0;\n    bDragged = false;\n}\n\nvoid UScrollPane::HandleControllerChanged(UGController* Controller)\n{\n    if (PageController == Controller)\n    {\n        if (ScrollType == EScrollType::Horizontal)\n            SetPageX(Controller->GetSelectedIndex(), true);\n        else\n            SetPageY(Controller->GetSelectedIndex(), true);\n    }\n}\n\nvoid UScrollPane::UpdatePageController()\n{\n    if (PageController != nullptr && !PageController->bChanging)\n    {\n        int32 index;\n        if (ScrollType == EScrollType::Horizontal)\n            index = GetPageX();\n        else\n            index = GetPageY();\n        if (index < PageController->GetPageCount())\n        {\n            UGController* Controller = PageController;\n            PageController = nullptr; //avoid calling handleControllerChanged\n            Controller->SetSelectedIndex(index);\n            PageController = Controller;\n        }\n    }\n}\n\nvoid UScrollPane::AdjustMaskContainer()\n{\n    FVector2D Pos;\n    if (bDisplayOnLeft && VtScrollBar != nullptr && !bFloating)\n        Pos.X = FMath::FloorToFloat(Owner->Margin.Left + VtScrollBar->GetWidth());\n    else\n        Pos.X = FMath::FloorToFloat(Owner->Margin.Left);\n    Pos.Y = FMath::FloorToFloat(Owner->Margin.Top);\n    Pos += Owner->AlignOffset;\n\n    MaskContainer->SetPosition(Pos);\n}\n\nvoid UScrollPane::OnOwnerSizeChanged()\n{\n    SetSize(Owner->GetSize());\n    PosChanged(false);\n}\n\nvoid UScrollPane::SetSize(const FVector2D& InSize)\n{\n    if (HzScrollBar != nullptr)\n    {\n        HzScrollBar->SetY(InSize.Y - HzScrollBar->GetHeight());\n        if (VtScrollBar != nullptr)\n        {\n            HzScrollBar->SetWidth(InSize.X - VtScrollBar->GetWidth() - ScrollBarMargin.Left - ScrollBarMargin.Right);\n            if (bDisplayOnLeft)\n                HzScrollBar->SetX(ScrollBarMargin.Left + VtScrollBar->GetWidth());\n            else\n                HzScrollBar->SetX(ScrollBarMargin.Left);\n        }\n        else\n        {\n            HzScrollBar->SetWidth(InSize.X - ScrollBarMargin.Left - ScrollBarMargin.Right);\n            HzScrollBar->SetX(ScrollBarMargin.Left);\n        }\n    }\n    if (VtScrollBar != nullptr)\n    {\n        if (!bDisplayOnLeft)\n            VtScrollBar->SetX(InSize.X - VtScrollBar->GetWidth());\n        if (HzScrollBar != nullptr)\n            VtScrollBar->SetHeight(InSize.Y - HzScrollBar->GetHeight() - ScrollBarMargin.Top - ScrollBarMargin.Bottom);\n        else\n            VtScrollBar->SetHeight(InSize.Y - ScrollBarMargin.Top - ScrollBarMargin.Bottom);\n        VtScrollBar->SetY(ScrollBarMargin.Top);\n    }\n\n    ViewSize = InSize;\n    if (HzScrollBar != nullptr && !bFloating)\n        ViewSize.Y -= HzScrollBar->GetHeight();\n    if (VtScrollBar != nullptr && !bFloating)\n        ViewSize.X -= VtScrollBar->GetWidth();\n    ViewSize.X -= (Owner->Margin.Left + Owner->Margin.Right);\n    ViewSize.Y -= (Owner->Margin.Top + Owner->Margin.Bottom);\n\n    ViewSize.X = FMath::Max(1.f, ViewSize.X);\n    ViewSize.Y = FMath::Max(1.f, ViewSize.Y);\n    PageSize = ViewSize;\n\n    AdjustMaskContainer();\n    HandleSizeChanged();\n}\n\nvoid UScrollPane::SetContentSize(const FVector2D& InSize)\n{\n    if (ContentSize == InSize)\n        return;\n\n    ContentSize = InSize;\n    HandleSizeChanged();\n}\n\nvoid UScrollPane::ChangeContentSizeOnScrolling(float DeltaWidth, float DeltaHeight, float DeltaPosX, float DeltaPosY)\n{\n    bool isRightmost = XPos == OverlapSize.X;\n    bool isBottom = YPos == OverlapSize.Y;\n\n    ContentSize.X += DeltaWidth;\n    ContentSize.Y += DeltaHeight;\n    HandleSizeChanged();\n\n    if (Tweening == 1)\n    {\n        if (DeltaWidth != 0 && isRightmost && TweenChange.X < 0)\n        {\n            XPos = OverlapSize.X;\n            TweenChange.X = -XPos - TweenStart.X;\n        }\n\n        if (DeltaHeight != 0 && isBottom && TweenChange.Y < 0)\n        {\n            YPos = OverlapSize.Y;\n            TweenChange.Y = -YPos - TweenStart.Y;\n        }\n    }\n    else if (Tweening == 2)\n    {\n        if (DeltaPosX != 0)\n        {\n            Container->SetX(Container->GetPosition().X - DeltaPosX);\n            TweenStart.X -= DeltaPosX;\n            XPos = -Container->GetPosition().X;\n        }\n        if (DeltaPosY != 0)\n        {\n            Container->SetY(Container->GetPosition().Y - DeltaPosY);\n            TweenStart.Y -= DeltaPosY;\n            YPos = -Container->GetPosition().Y;\n        }\n    }\n    else if (bDragged)\n    {\n        if (DeltaPosX != 0)\n        {\n            Container->SetX(Container->GetPosition().X - DeltaPosX);\n            ContainerPos.X -= DeltaPosX;\n            XPos = -Container->GetPosition().X;\n        }\n        if (DeltaPosY != 0)\n        {\n            Container->SetY(Container->GetPosition().Y - DeltaPosY);\n            ContainerPos.Y -= DeltaPosY;\n            YPos = -Container->GetPosition().Y;\n        }\n    }\n    else\n    {\n        if (DeltaWidth != 0 && isRightmost)\n        {\n            XPos = OverlapSize.X;\n            Container->SetX(Container->GetPosition().X - XPos);\n        }\n\n        if (DeltaHeight != 0 && isBottom)\n        {\n            YPos = OverlapSize.Y;\n            Container->SetY(Container->GetPosition().Y - YPos);\n        }\n    }\n\n    if (bPageMode)\n        UpdatePageController();\n}\n\nvoid UScrollPane::HandleSizeChanged()\n{\n    if (bDisplayInDemand)\n    {\n        bVScrollNone = ContentSize.Y <= ViewSize.Y;\n        bHScrollNone = ContentSize.X <= ViewSize.X;\n    }\n\n    if (VtScrollBar != nullptr)\n    {\n        if (ContentSize.Y == 0)\n            VtScrollBar->SetDisplayPerc(0);\n        else\n            VtScrollBar->SetDisplayPerc(FMath::Min(1.f, ViewSize.Y / ContentSize.Y));\n    }\n    if (HzScrollBar != nullptr)\n    {\n        if (ContentSize.X == 0)\n            HzScrollBar->SetDisplayPerc(0);\n        else\n            HzScrollBar->SetDisplayPerc(FMath::Min(1.f, ViewSize.X / ContentSize.X));\n    }\n\n    UpdateScrollBarVisible();\n\n    MaskContainer->SetSize(ViewSize);\n    FBox2D maskRect(-Owner->AlignOffset, -Owner->AlignOffset + ViewSize);\n    if (bVScrollNone && VtScrollBar != nullptr)\n        maskRect.Max.X += VtScrollBar->GetWidth();\n    if (bHScrollNone && HzScrollBar != nullptr)\n        maskRect.Max.Y += HzScrollBar->GetHeight();\n    if (bDontClipMargin)\n    {\n        maskRect.ShiftBy(FVector2D(-Owner->Margin.Left, -Owner->Margin.Top));\n        maskRect.Max.X += Owner->Margin.Left + Owner->Margin.Right;\n        maskRect.Max.Y += Owner->Margin.Top + Owner->Margin.Bottom;\n    }\n    MaskContainer->SetCullingBoundsExtension(FMargin(-maskRect.Min.X, -maskRect.Min.Y, maskRect.Max.X - ViewSize.X, maskRect.Max.Y - ViewSize.Y));\n\n    if (ScrollType == EScrollType::Horizontal || ScrollType == EScrollType::Both)\n        OverlapSize.X = FMath::CeilToFloat(FMath::Max(0.f, ContentSize.X - ViewSize.X));\n    else\n        OverlapSize.X = 0;\n    if (ScrollType == EScrollType::Vertical || ScrollType == EScrollType::Both)\n        OverlapSize.Y = FMath::CeilToFloat(FMath::Max(0.f, ContentSize.Y - ViewSize.Y));\n    else\n        OverlapSize.Y = 0;\n\n    XPos = FMath::Clamp(XPos, 0.f, OverlapSize.X);\n    YPos = FMath::Clamp(YPos, 0.f, OverlapSize.Y);\n    float max = OverlapSize.Component(RefreshBarAxis);\n    if (max == 0)\n        max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f);\n    else\n        max += FooterLockedSize;\n    const FVector2D& Pos = Container->GetPosition();\n    if (RefreshBarAxis == 0)\n        Container->SetPosition(FVector2D(FMath::Clamp(Pos.X, -max, HeaderLockedSize),\n            FMath::Clamp(Pos.Y, -OverlapSize.Y, 0.f)));\n    else\n        Container->SetPosition(FVector2D(FMath::Clamp(Pos.X, -OverlapSize.X, 0.f),\n            FMath::Clamp(Pos.Y, -max, HeaderLockedSize)));\n\n    if (Header != nullptr)\n    {\n        if (RefreshBarAxis == 0)\n            Header->SetHeight(ViewSize.Y);\n        else\n            Header->SetWidth(ViewSize.X);\n    }\n\n    if (Footer != nullptr)\n    {\n        if (RefreshBarAxis == 0)\n            Footer->SetHeight(ViewSize.Y);\n        else\n            Footer->SetWidth(ViewSize.X);\n    }\n\n    UpdateScrollBarPos();\n    if (bPageMode)\n        UpdatePageController();\n}\n\nvoid UScrollPane::PosChanged(bool bAnimation)\n{\n    if (AniFlag == 0)\n        AniFlag = bAnimation ? 1 : -1;\n    else if (AniFlag == 1 && !bAnimation)\n        AniFlag = -1;\n\n    bNeedRefresh = true;\n    Owner->GetApp()->DelayCall(RefreshTimerHandle, this, &UScrollPane::Refresh);\n}\n\nvoid UScrollPane::Refresh()\n{\n    Owner->GetApp()->CancelDelayCall(RefreshTimerHandle);\n\n    bNeedRefresh = false;\n\n    if (bPageMode || bSnapToItem)\n    {\n        FVector2D pos(-XPos, -YPos);\n        AlignPosition(pos, false);\n        XPos = -pos.X;\n        YPos = -pos.Y;\n    }\n\n    Refresh2();\n\n    Owner->DispatchEvent(FUIEvents::Scroll);\n    if (bNeedRefresh) //pos may change in onScroll\n    {\n        bNeedRefresh = false;\n        Owner->GetApp()->CancelDelayCall(RefreshTimerHandle);\n\n        Refresh2();\n    }\n\n    UpdateScrollBarPos();\n    AniFlag = 0;\n}\n\nvoid UScrollPane::Refresh2()\n{\n    if (AniFlag == 1 && !bDragged)\n    {\n        FVector2D pos;\n\n        if (OverlapSize.X > 0)\n            pos.X = -(int32)XPos;\n        else\n        {\n            if (Container->GetPosition().X != 0)\n                Container->SetX(0);\n            pos.X = 0;\n        }\n        if (OverlapSize.Y > 0)\n            pos.Y = -(int32)YPos;\n        else\n        {\n            if (Container->GetPosition().Y != 0)\n                Container->SetY(0);\n            pos.Y = 0;\n        }\n\n        if (pos != Container->GetPosition())\n        {\n            TweenDuration.Set(TWEEN_TIME_GO, TWEEN_TIME_GO);\n            TweenStart = Container->GetPosition();\n            TweenChange = pos - TweenStart;\n            StartTween(1);\n        }\n        else if (Tweening != 0)\n            KillTween();\n    }\n    else\n    {\n        if (Tweening != 0)\n            KillTween();\n\n        Container->SetPosition(FVector2D((int32)-XPos, (int32)-YPos));\n\n        LoopCheckingCurrent();\n    }\n\n    if (bPageMode)\n        UpdatePageController();\n}\n\nvoid UScrollPane::UpdateScrollBarPos()\n{\n    if (VtScrollBar != nullptr)\n        VtScrollBar->SetScrollPerc(OverlapSize.Y == 0 ? 0 : FMath::Clamp(-Container->GetPosition().Y, 0.f, OverlapSize.Y) / OverlapSize.Y);\n\n    if (HzScrollBar != nullptr)\n        HzScrollBar->SetScrollPerc(OverlapSize.X == 0 ? 0 : FMath::Clamp(-Container->GetPosition().X, 0.f, OverlapSize.X) / OverlapSize.X);\n\n    CheckRefreshBar();\n}\n\nvoid UScrollPane::UpdateScrollBarVisible()\n{\n    if (VtScrollBar != nullptr)\n    {\n        if (ViewSize.Y <= VtScrollBar->GetMinSize() || bVScrollNone)\n            VtScrollBar->SetVisible(false);\n        else\n            UpdateScrollBarVisible2(VtScrollBar);\n    }\n\n    if (HzScrollBar != nullptr)\n    {\n        if (ViewSize.X <= HzScrollBar->GetMinSize() || bHScrollNone)\n            HzScrollBar->SetVisible(false);\n        else\n            UpdateScrollBarVisible2(HzScrollBar);\n    }\n}\n\nvoid UScrollPane::UpdateScrollBarVisible2(UGScrollBar* Bar)\n{\n    if (bScrollBarDisplayAuto)\n        FGTween::Kill(Bar, false);\n\n    if (bScrollBarDisplayAuto && !bHover && Tweening == 0 && !bDragged && !Bar->bGripDragging)\n    {\n        if (Bar->IsVisible())\n            FGTween::To(1, 0, 0.5f)\n            ->SetDelay(0.5f)\n            ->OnUpdate(FTweenDelegate::CreateStatic(&FGTweenAction::SetAlpha))\n            ->OnComplete(FTweenDelegate::CreateUObject(this, &UScrollPane::OnBarTweenComplete))\n            ->SetTarget(Bar);\n    }\n    else\n    {\n        Bar->SetAlpha(1);\n        Bar->SetVisible(true);\n    }\n}\n\nvoid UScrollPane::OnBarTweenComplete(FGTweener* Tweener)\n{\n    UGObject* bar = (UGObject*)Tweener->GetTarget();\n    bar->SetAlpha(1);\n    bar->SetVisible(false);\n}\n\nfloat UScrollPane::GetLoopPartSize(float Division, int32 Axis)\n{\n    return (ContentSize.Component(Axis) + (Axis == 0 ? ((UGList*)Owner)->GetColumnGap() : ((UGList*)Owner)->GetLineGap())) / Division;\n}\n\nbool UScrollPane::LoopCheckingCurrent()\n{\n    bool changed = false;\n    if (LoopMode == 1 && OverlapSize.X > 0)\n    {\n        if (XPos < 0.001f)\n        {\n            XPos += GetLoopPartSize(2, 0);\n            changed = true;\n        }\n        else if (XPos >= OverlapSize.X)\n        {\n            XPos -= GetLoopPartSize(2, 0);\n            changed = true;\n        }\n    }\n    else if (LoopMode == 2 && OverlapSize.Y > 0)\n    {\n        if (YPos < 0.001f)\n        {\n            YPos += GetLoopPartSize(2, 1);\n            changed = true;\n        }\n        else if (YPos >= OverlapSize.Y)\n        {\n            YPos -= GetLoopPartSize(2, 1);\n            changed = true;\n        }\n    }\n\n    if (changed)\n        Container->SetPosition(FVector2D((int32)-XPos, (int32)-YPos));\n\n    return changed;\n}\n\nvoid UScrollPane::LoopCheckingTarget(FVector2D& EndPos)\n{\n    if (LoopMode == 1)\n        LoopCheckingTarget(EndPos, 0);\n\n    if (LoopMode == 2)\n        LoopCheckingTarget(EndPos, 1);\n}\n\nvoid UScrollPane::LoopCheckingTarget(FVector2D& EndPos, int32 Axis)\n{\n    if (EndPos.Component(Axis) > 0)\n    {\n        float halfSize = GetLoopPartSize(2, Axis);\n        float tmp = TweenStart.Component(Axis) - halfSize;\n        if (tmp <= 0 && tmp >= -OverlapSize.Component(Axis))\n        {\n            EndPos.Component(Axis) = -halfSize;\n            TweenStart.Component(Axis) = tmp;\n        }\n    }\n    else if (EndPos.Component(Axis) < -OverlapSize.Component(Axis))\n    {\n        float halfSize = GetLoopPartSize(2, Axis);\n        float tmp = TweenStart.Component(Axis) + halfSize;\n        if (tmp <= 0 && tmp >= -OverlapSize.Component(Axis))\n        {\n            EndPos.Component(Axis) += halfSize;\n            TweenStart.Component(Axis) += tmp;\n        }\n    }\n}\n\nvoid UScrollPane::LoopCheckingNewPos(float& Value, int32 Axis)\n{\n    float overlapSize = OverlapSize.Component(Axis);\n    if (overlapSize == 0)\n        return;\n\n    float pos = Axis == 0 ? XPos : YPos;\n    bool changed = false;\n    if (Value < 0.001f)\n    {\n        Value += GetLoopPartSize(2, Axis);\n        if (Value > pos)\n        {\n            float v = GetLoopPartSize(6, Axis);\n            v = FMath::CeilToFloat((Value - pos) / v) * v;\n            pos = FMath::Clamp(pos + v, 0.f, overlapSize);\n            changed = true;\n        }\n    }\n    else if (Value >= overlapSize)\n    {\n        Value -= GetLoopPartSize(2, Axis);\n        if (Value < pos)\n        {\n            float v = GetLoopPartSize(6, Axis);\n            v = FMath::CeilToFloat((pos - Value) / v) * v;\n            pos = FMath::Clamp(pos - v, 0.f, overlapSize);\n            changed = true;\n        }\n    }\n\n    if (changed)\n    {\n        if (Axis == 0)\n            Container->SetX(-(int32)pos);\n        else\n            Container->SetY(-(int32)pos);\n    }\n}\n\nvoid UScrollPane::AlignPosition(FVector2D& Pos, bool bInertialScrolling)\n{\n    if (bPageMode)\n    {\n        Pos.X = AlignByPage(Pos.X, 0, bInertialScrolling);\n        Pos.Y = AlignByPage(Pos.Y, 1, bInertialScrolling);\n    }\n    else if (bSnapToItem)\n    {\n        FVector2D tmp = Owner->GetSnappingPosition(-Pos);\n        if (Pos.X < 0 && Pos.X > -OverlapSize.X)\n            Pos.X = -tmp.X;\n        if (Pos.Y < 0 && Pos.Y > -OverlapSize.Y)\n            Pos.Y = -tmp.Y;\n    }\n}\n\nfloat UScrollPane::AlignByPage(float Pos, int32 Axis, bool bInertialScrolling)\n{\n    int32 page;\n    float pageSize = PageSize.Component(Axis);\n    float overlapSize = OverlapSize.Component(Axis);\n    float contentSize = ContentSize.Component(Axis);\n\n    if (Pos > 0)\n        page = 0;\n    else if (Pos < -overlapSize)\n        page = FMath::CeilToFloat(contentSize / pageSize) - 1;\n    else\n    {\n        page = FMath::FloorToInt(-Pos / pageSize);\n        float change = bInertialScrolling ? (Pos - ContainerPos.Component(Axis)) : (Pos - Container->GetPosition().Component(Axis));\n        float testPageSize = FMath::Min(pageSize, contentSize - (page + 1) * pageSize);\n        float delta = -Pos - page * pageSize;\n\n        if (FMath::Abs(change) > pageSize)\n        {\n            if (delta > testPageSize * 0.5f)\n                page++;\n        }\n        else\n        {\n            if (delta > testPageSize * (change < 0 ? 0.3f : 0.7f))\n                page++;\n        }\n\n        Pos = -page * pageSize;\n        if (Pos < -overlapSize)\n            Pos = -overlapSize;\n    }\n\n    if (bInertialScrolling)\n    {\n        float oldPos = TweenStart.Component(Axis);\n        int32 oldPage;\n        if (oldPos > 0)\n            oldPage = 0;\n        else if (oldPos < -overlapSize)\n            oldPage = FMath::CeilToInt(contentSize / pageSize) - 1;\n        else\n            oldPage = FMath::FloorToInt(-oldPos / pageSize);\n        int32 startPage = FMath::FloorToInt(-ContainerPos.Component(Axis) / pageSize);\n        if (FMath::Abs(page - startPage) > 1 && FMath::Abs(oldPage - startPage) <= 1)\n        {\n            if (page > startPage)\n                page = startPage + 1;\n            else\n                page = startPage - 1;\n            Pos = -page * pageSize;\n        }\n    }\n\n    return Pos;\n}\n\nFVector2D UScrollPane::UpdateTargetAndDuration(const FVector2D& OrignPos)\n{\n    FVector2D ret(0, 0);\n    ret.X = UpdateTargetAndDuration(OrignPos.X, 0);\n    ret.Y = UpdateTargetAndDuration(OrignPos.Y, 1);\n    return ret;\n}\n\nfloat UScrollPane::UpdateTargetAndDuration(float Pos, int32 Axis)\n{\n    float v = Velocity.Component(Axis);\n    float duration = 0;\n\n    if (Pos > 0)\n        Pos = 0;\n    else if (Pos < -OverlapSize.Component(Axis))\n        Pos = -OverlapSize.Component(Axis);\n    else\n    {\n        float v2 = FMath::Abs(v) * VelocityScale;\n        float ratio = 0;\n        if (FPlatformMisc::DesktopTouchScreen())\n        {\n            if (v2 > 500)\n                ratio = FMath::Pow((v2 - 500) / 500, 2);\n        }\n        else\n        {\n            FVector2D winSize;\n            GWorld->GetGameViewport()->GetViewportSize(winSize);\n            v2 *= 1136.0f / FMath::Max(winSize.X, winSize.Y);\n\n            if (bPageMode)\n            {\n                if (v2 > 500)\n                    ratio = FMath::Pow((v2 - 500) / 500, 2);\n            }\n            else\n            {\n                if (v2 > 1000)\n                    ratio = FMath::Pow((v2 - 1000) / 1000, 2);\n            }\n        }\n\n        if (ratio != 0)\n        {\n            if (ratio > 1)\n                ratio = 1;\n\n            v2 *= ratio;\n            v *= ratio;\n            Velocity.Component(Axis) = v;\n\n            duration = FMath::Loge(60 / v2) / FMath::Loge(DecelerationRate) / 60;\n            float change = FMath::FloorToFloat(v * duration * 0.4f);\n            Pos += change;\n        }\n    }\n\n    if (duration < TWEEN_TIME_DEFAULT)\n        duration = TWEEN_TIME_DEFAULT;\n    TweenDuration.Component(Axis) = duration;\n\n    return Pos;\n}\n\nvoid UScrollPane::FixDuration(int32 Axis, float OldChange)\n{\n    float tweenChange = TweenChange.Component(Axis);\n    if (tweenChange == 0 || FMath::Abs(tweenChange) >= FMath::Abs(OldChange))\n        return;\n\n    float newDuration = FMath::Abs(tweenChange / OldChange) * TweenDuration.Component(Axis);\n    if (newDuration < TWEEN_TIME_DEFAULT)\n        newDuration = TWEEN_TIME_DEFAULT;\n\n    TweenDuration.Component(Axis) = newDuration;\n}\n\nvoid UScrollPane::StartTween(int32 Type)\n{\n    TweenTime.Set(0, 0);\n    Tweening = Type;\n    GWorld->GetTimerManager().SetTimer(TickTimerHandle,\n        FTimerDelegate::CreateUObject(this, &UScrollPane::TweenUpdate),\n        0.016f,\n        true);\n    UpdateScrollBarVisible();\n}\n\nvoid UScrollPane::KillTween()\n{\n    if (Tweening == 1)\n    {\n        FVector2D t = TweenStart + TweenChange;\n        Container->SetPosition(t);\n        Owner->DispatchEvent(FUIEvents::Scroll);\n    }\n\n    Tweening = 0;\n    GWorld->GetTimerManager().ClearTimer(TickTimerHandle);\n    Owner->DispatchEvent(FUIEvents::ScrollEnd);\n}\n\nvoid UScrollPane::CheckRefreshBar()\n{\n    if (Header == nullptr && Footer == nullptr)\n        return;\n\n    float pos = Container->GetPosition().Component(RefreshBarAxis);\n    if (Header != nullptr)\n    {\n        if (pos > 0)\n        {\n            Header->SetVisible(true);\n            FVector2D vec;\n\n            vec = Header->GetSize();\n            vec.Component(RefreshBarAxis) = pos;\n            Header->SetSize(vec);\n        }\n        else\n            Header->SetVisible(false);\n    }\n\n    if (Footer != nullptr)\n    {\n        float max = OverlapSize.Component(RefreshBarAxis);\n        if (pos < -max || (max == 0 && FooterLockedSize > 0))\n        {\n            Footer->SetVisible(true);\n\n            FVector2D vec;\n\n            vec = Footer->GetPosition();\n            if (max > 0)\n                vec.Component(RefreshBarAxis) = pos + ContentSize.Component(RefreshBarAxis);\n            else\n                vec.Component(RefreshBarAxis) = FMath::Max(FMath::Min(pos + ViewSize.Component(RefreshBarAxis), ViewSize.Component(RefreshBarAxis) - FooterLockedSize), ViewSize.Component(RefreshBarAxis) - ContentSize.Component(RefreshBarAxis));\n            Footer->SetPosition(vec);\n\n            vec = Footer->GetSize();\n            if (max > 0)\n                vec.Component(RefreshBarAxis) = -max - pos;\n            else\n                vec.Component(RefreshBarAxis) = ViewSize.Component(RefreshBarAxis) - Footer->GetPosition().Component(RefreshBarAxis);\n            Footer->SetSize(vec);\n        }\n        else\n            Footer->SetVisible(false);\n    }\n}\n\nvoid UScrollPane::TweenUpdate()\n{\n    float dt = GWorld->GetTimerManager().GetTimerElapsed(TickTimerHandle);\n\n    float nx = RunTween(0, dt);\n    float ny = RunTween(1, dt);\n\n    Container->SetPosition(FVector2D(nx, ny));\n\n    if (Tweening == 2)\n    {\n        if (OverlapSize.X > 0)\n            XPos = FMath::Clamp(-nx, 0.f, OverlapSize.X);\n        if (OverlapSize.Y > 0)\n            YPos = FMath::Clamp(-ny, 0.f, OverlapSize.Y);\n\n        if (bPageMode)\n            UpdatePageController();\n    }\n\n    if (TweenChange.X == 0 && TweenChange.Y == 0)\n    {\n        Tweening = 0;\n        GWorld->GetTimerManager().ClearTimer(TickTimerHandle);\n\n        LoopCheckingCurrent();\n\n        UpdateScrollBarPos();\n        UpdateScrollBarVisible();\n\n        Owner->DispatchEvent(FUIEvents::Scroll);\n        Owner->DispatchEvent(FUIEvents::ScrollEnd);\n    }\n    else\n    {\n        UpdateScrollBarPos();\n        Owner->DispatchEvent(FUIEvents::Scroll);\n    }\n}\n\nfloat UScrollPane::RunTween(int32 Axis, float DeltaTime)\n{\n    float newValue;\n    if (TweenChange.Component(Axis) != 0)\n    {\n        TweenTime.Component(Axis) += DeltaTime;\n        if (TweenTime.Component(Axis) >= TweenDuration.Component(Axis))\n        {\n            newValue = TweenStart.Component(Axis) + TweenChange.Component(Axis);\n            TweenChange.Component(Axis) = 0;\n        }\n        else\n        {\n            float ratio = sp_EaseFunc(TweenTime.Component(Axis), TweenDuration.Component(Axis));\n            newValue = TweenStart.Component(Axis) + (int32)(TweenChange.Component(Axis) * ratio);\n        }\n\n        float threshold1 = 0;\n        float threshold2 = -OverlapSize.Component(Axis);\n        if (HeaderLockedSize > 0 && RefreshBarAxis == Axis)\n            threshold1 = HeaderLockedSize;\n        if (FooterLockedSize > 0 && RefreshBarAxis == Axis)\n        {\n            float max = OverlapSize.Component(RefreshBarAxis);\n            if (max == 0)\n                max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f);\n            else\n                max += FooterLockedSize;\n            threshold2 = -max;\n        }\n\n        if (Tweening == 2 && bBouncebackEffect)\n        {\n            if ((newValue > 20 + threshold1 && TweenChange.Component(Axis) > 0) || (newValue > threshold1 && TweenChange.Component(Axis) == 0))\n            {\n                TweenTime.Component(Axis) = 0;\n                TweenDuration.Component(Axis) = TWEEN_TIME_DEFAULT;\n                TweenChange.Component(Axis) = -newValue + threshold1;\n                TweenStart.Component(Axis) = newValue;\n            }\n            else if ((newValue < threshold2 - 20 && TweenChange.Component(Axis) < 0) || (newValue < threshold2 && TweenChange.Component(Axis) == 0))\n            {\n                TweenTime.Component(Axis) = 0;\n                TweenDuration.Component(Axis) = TWEEN_TIME_DEFAULT;\n                TweenChange.Component(Axis) = threshold2 - newValue;\n                TweenStart.Component(Axis) = newValue;\n            }\n        }\n        else\n        {\n            if (newValue > threshold1)\n            {\n                newValue = threshold1;\n                TweenChange.Component(Axis) = 0;\n            }\n            else if (newValue < threshold2)\n            {\n                newValue = threshold2;\n                TweenChange.Component(Axis) = 0;\n            }\n        }\n    }\n    else\n        newValue = Container->GetPosition().Component(Axis);\n\n    return newValue;\n}\n\nvoid UScrollPane::OnTouchBegin(UEventContext* Context)\n{\n    if (!bTouchEffect)\n        return;\n\n    Context->CaptureTouch();\n    FVector2D pt = Owner->GlobalToLocal(Context->GetPointerPosition());\n\n    if (Tweening != 0)\n    {\n        KillTween();\n        Owner->GetApp()->CancelClick(Context->GetUserIndex(), Context->GetPointerIndex());\n\n        bDragged = true;\n    }\n    else\n        bDragged = false;\n\n    ContainerPos = Container->GetPosition();\n    BeginTouchPos = LastTouchPos = pt;\n    LastTouchGlobalPos = Context->GetPointerPosition();\n    bIsHoldAreaDone = false;\n    Velocity.Set(0, 0);\n    VelocityScale = 1;\n    LastMoveTime = GWorld->GetTimeSeconds();\n}\n\nvoid UScrollPane::OnTouchMove(UEventContext* Context)\n{\n    if (!bTouchEffect)\n        return;\n\n    if ((DraggingPane.IsValid() && DraggingPane.Get() != this) || UGObject::GetDraggingObject() != nullptr)\n        return;\n\n    FVector2D pt = Owner->GlobalToLocal(Context->GetPointerPosition());\n\n    int32 sensitivity;\n    if (FPlatformMisc::DesktopTouchScreen())\n        sensitivity = 8;\n    else\n        sensitivity = FUIConfig::Config.TouchScrollSensitivity;\n\n    float diff;\n    bool sv = false, sh = false;\n\n    if (ScrollType == EScrollType::Vertical)\n    {\n        if (!bIsHoldAreaDone)\n        {\n            GestureFlag |= 1;\n\n            diff = FMath::Abs(BeginTouchPos.Y - pt.Y);\n            if (diff < sensitivity)\n                return;\n\n            if ((GestureFlag & 2) != 0)\n            {\n                float diff2 = FMath::Abs(BeginTouchPos.X - pt.X);\n                if (diff < diff2)\n                    return;\n            }\n        }\n\n        sv = true;\n    }\n    else if (ScrollType == EScrollType::Horizontal)\n    {\n        if (!bIsHoldAreaDone)\n        {\n            GestureFlag |= 2;\n\n            diff = FMath::Abs(BeginTouchPos.X - pt.X);\n            if (diff < sensitivity)\n                return;\n\n            if ((GestureFlag & 1) != 0)\n            {\n                float diff2 = FMath::Abs(BeginTouchPos.Y - pt.Y);\n                if (diff < diff2)\n                    return;\n            }\n        }\n\n        sh = true;\n    }\n    else\n    {\n        GestureFlag = 3;\n\n        if (!bIsHoldAreaDone)\n        {\n            diff = FMath::Abs(BeginTouchPos.Y - pt.Y);\n            if (diff < sensitivity)\n            {\n                diff = FMath::Abs(BeginTouchPos.X - pt.X);\n                if (diff < sensitivity)\n                    return;\n            }\n        }\n\n        sv = sh = true;\n    }\n\n    FVector2D newPos = (ContainerPos + pt - BeginTouchPos).RoundToVector();\n\n    if (sv)\n    {\n        if (newPos.Y > 0)\n        {\n            if (!bBouncebackEffect)\n                Container->SetY(0);\n            else if (Header != nullptr && Header->MaxSize.Y != 0)\n                Container->SetY(((int32)FMath::Min(newPos.Y * 0.5f, Header->MaxSize.Y)));\n            else\n                Container->SetY(((int32)FMath::Min(newPos.Y * 0.5f, ViewSize.Y * PULL_RATIO)));\n        }\n        else if (newPos.Y < -OverlapSize.Y)\n        {\n            if (!bBouncebackEffect)\n                Container->SetY(-OverlapSize.Y);\n            else if (Footer != nullptr && Footer->MaxSize.Y > 0)\n                Container->SetY(((int32)FMath::Max((newPos.Y + OverlapSize.Y) * 0.5f, -Footer->MaxSize.Y) - OverlapSize.Y));\n            else\n                Container->SetY(((int32)FMath::Max((newPos.Y + OverlapSize.Y) * 0.5f, -ViewSize.Y * PULL_RATIO) - OverlapSize.Y));\n        }\n        else\n            Container->SetY(newPos.Y);\n    }\n\n    if (sh)\n    {\n        if (newPos.X > 0)\n        {\n            if (!bBouncebackEffect)\n                Container->SetX(0);\n            else if (Header != nullptr && Header->MaxSize.X != 0)\n                Container->SetX((int32)FMath::Min(newPos.X * 0.5f, Header->MaxSize.X));\n            else\n                Container->SetX((int32)FMath::Min(newPos.X * 0.5f, ViewSize.X * PULL_RATIO));\n        }\n        else if (newPos.X < 0 - OverlapSize.X)\n        {\n            if (!bBouncebackEffect)\n                Container->SetX(-OverlapSize.X);\n            else if (Footer != nullptr && Footer->MaxSize.X > 0)\n                Container->SetX((int32)FMath::Max((newPos.X + OverlapSize.X) * 0.5f, -Footer->MaxSize.X) - OverlapSize.X);\n            else\n                Container->SetX((int32)FMath::Max((newPos.X + OverlapSize.X) * 0.5f, -ViewSize.X * PULL_RATIO) - OverlapSize.X);\n        }\n        else\n            Container->SetX(newPos.X);\n    }\n\n    float deltaTime = FSlateApplication::Get().GetDeltaTime();// GWorld->GetDeltaSeconds();\n    float elapsed = GWorld->GetTimeSeconds() - LastMoveTime;\n    elapsed = elapsed * 60 - 1;\n    if (elapsed > 1)\n        Velocity *= FMath::Pow(0.833f, elapsed);\n    FVector2D deltaPosition = pt - LastTouchPos;\n    if (!sh)\n        deltaPosition.X = 0;\n    if (!sv)\n        deltaPosition.Y = 0;\n    Velocity = FMath::Lerp(Velocity, deltaPosition / deltaTime, deltaTime * 10);\n\n    FVector2D deltaGlobalPosition = LastTouchGlobalPos - Context->GetPointerPosition();\n    if (deltaPosition.X != 0)\n        VelocityScale = FMath::Abs(deltaGlobalPosition.X / deltaPosition.X);\n    else if (deltaPosition.Y != 0)\n        VelocityScale = FMath::Abs(deltaGlobalPosition.Y / deltaPosition.Y);\n\n    LastTouchPos = pt;\n    LastTouchGlobalPos = Context->GetPointerPosition();\n    LastMoveTime = GWorld->GetTimeSeconds();\n\n    if (OverlapSize.X > 0)\n        XPos = FMath::Clamp(-Container->GetPosition().X, 0.f, OverlapSize.X);\n    if (OverlapSize.Y > 0)\n        YPos = FMath::Clamp(-Container->GetPosition().Y, 0.f, OverlapSize.Y);\n\n    if (LoopMode != 0)\n    {\n        newPos = Container->GetPosition();\n        if (LoopCheckingCurrent())\n            ContainerPos += Container->GetPosition() - newPos;\n    }\n\n    DraggingPane = this;\n    bIsHoldAreaDone = true;\n    bDragged = true;\n\n    UpdateScrollBarPos();\n    UpdateScrollBarVisible();\n    if (bPageMode)\n        UpdatePageController();\n\n    Owner->DispatchEvent(FUIEvents::Scroll);\n}\n\nvoid UScrollPane::OnTouchEnd(UEventContext* Context)\n{\n    if (DraggingPane.Get() == this)\n        DraggingPane.Reset();\n\n    GestureFlag = 0;\n\n    if (!bDragged || !bTouchEffect)\n    {\n        bDragged = false;\n        return;\n    }\n\n    bDragged = false;\n    TweenStart = Container->GetPosition();\n\n    FVector2D endPos = TweenStart;\n    bool flag = false;\n    if (Container->GetPosition().X > 0)\n    {\n        endPos.X = 0;\n        flag = true;\n    }\n    else if (Container->GetPosition().X < -OverlapSize.X)\n    {\n        endPos.X = -OverlapSize.X;\n        flag = true;\n    }\n    if (Container->GetPosition().Y > 0)\n    {\n        endPos.Y = 0;\n        flag = true;\n    }\n    else if (Container->GetPosition().Y < -OverlapSize.Y)\n    {\n        endPos.Y = -OverlapSize.Y;\n        flag = true;\n    }\n\n    if (flag)\n    {\n        TweenChange = endPos - TweenStart;\n        if (TweenChange.X < -FUIConfig::Config.TouchDragSensitivity || TweenChange.Y < -FUIConfig::Config.TouchDragSensitivity)\n            Owner->DispatchEvent(FUIEvents::PullDownRelease);\n        else if (TweenChange.X > FUIConfig::Config.TouchDragSensitivity || TweenChange.Y > FUIConfig::Config.TouchDragSensitivity)\n            Owner->DispatchEvent(FUIEvents::PullUpRelease);\n\n        if (HeaderLockedSize > 0 && endPos.Component(RefreshBarAxis) == 0)\n        {\n            endPos.Component(RefreshBarAxis) = HeaderLockedSize;\n            TweenChange = endPos - TweenStart;\n        }\n        else if (FooterLockedSize > 0 && endPos.Component(RefreshBarAxis) == -OverlapSize.Component(RefreshBarAxis))\n        {\n            float max = OverlapSize.Component(RefreshBarAxis);\n            if (max == 0)\n                max = FMath::Max(ContentSize.Component(RefreshBarAxis) + FooterLockedSize - ViewSize.Component(RefreshBarAxis), 0.f);\n            else\n                max += FooterLockedSize;\n            endPos.Component(RefreshBarAxis) = -max;\n            TweenChange = endPos - TweenStart;\n        }\n\n        TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);\n    }\n    else\n    {\n        if (!bInertiaDisabled)\n        {\n            float elapsed = GWorld->GetTimeSeconds() - LastMoveTime;\n            elapsed = elapsed * 60 - 1;\n            if (elapsed > 1)\n                Velocity *= FMath::Pow(0.833f, elapsed);\n\n            endPos = UpdateTargetAndDuration(TweenStart);\n        }\n        else\n            TweenDuration.Set(TWEEN_TIME_DEFAULT, TWEEN_TIME_DEFAULT);\n        FVector2D oldChange = endPos - TweenStart;\n\n        LoopCheckingTarget(endPos);\n        if (bPageMode || bSnapToItem)\n            AlignPosition(endPos, true);\n\n        TweenChange = endPos - TweenStart;\n        if (TweenChange.X == 0 && TweenChange.Y == 0)\n        {\n            UpdateScrollBarVisible();\n            return;\n        }\n\n        if (bPageMode || bSnapToItem)\n        {\n            FixDuration(0, oldChange.X);\n            FixDuration(1, oldChange.Y);\n        }\n    }\n\n    StartTween(2);\n}\n\nvoid UScrollPane::OnMouseWheel(UEventContext* Context)\n{\n    if (!bMouseWheelEnabled)\n        return;\n\n    float delta = -Context->GetPointerEvent().GetWheelDelta();\n    if (bSnapToItem && FMath::Abs(delta) < 1)\n        delta = FMath::Sign(delta);\n\n    if (OverlapSize.X > 0 && OverlapSize.Y == 0)\n    {\n        float step = bPageMode ? PageSize.X : ScrollStep;\n        SetPosX(XPos + step * delta, false);\n    }\n    else\n    {\n        float step = bPageMode ? PageSize.Y : ScrollStep;\n        SetPosY(YPos + step * delta, false);\n    }\n}\n\nvoid UScrollPane::OnRollOver(UEventContext* Context)\n{\n    bHover = true;\n    UpdateScrollBarVisible();\n}\n\nvoid UScrollPane::OnRollOut(UEventContext* Context)\n{\n    bHover = false;\n    UpdateScrollBarVisible();\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/Transition.cpp",
    "content": "#include \"UI/Transition.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/GController.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"Tween/GPath.h\"\n\nconst int32 OPTION_IGNORE_DISPLAY_CONTROLLER = 1;\nconst int32 OPTION_AUTO_STOP_DISABLED = 2;\nconst int32 OPTION_AUTO_STOP_AT_END = 4;\n\nstruct FAniData\n{\n    int32 Frame;\n    bool bPlaying;\n    bool bFlag;\n};\n\nstruct FSoundData\n{\n    FString URL;\n    float Volume;\n};\n\nstruct FInnerTransData\n{\n    FString Name;\n    int32 PlayTimes;\n    UTransition* Instance;\n    float StopTime;\n};\n\nstruct FShakeData\n{\n    float Amplitude;\n    float Duration;\n    FVector2D LastOffset;\n    FVector2D Offset;\n};\n\nstruct FTransitionItemData\n{\n    float f1;\n    float f2;\n    float f3;\n    float f4;\n    bool b1;\n    bool b2;\n    bool b3;\n\n    FTransitionItemData();\n    FVector2D GetVec2() const;\n    void SetVec2(const FVector2D& value);\n    FVector4 GetVec4() const;\n    void SetVec4(const FVector4& value);\n    FColor GetColor() const;\n    void SetColor(const FColor& value);\n};\n\nFTransitionItemData::FTransitionItemData()\n{\n    f1 = f2 = f3 = f4 = 0;\n    b1 = b2 = true;\n    b3 = false;\n}\n\nFVector2D FTransitionItemData::GetVec2() const\n{\n    return FVector2D(f1, f2);\n}\n\nvoid FTransitionItemData::SetVec2(const FVector2D& value)\n{\n    f1 = value.X;\n    f2 = value.Y;\n}\n\nFVector4 FTransitionItemData::GetVec4() const\n{\n    return FVector4(f1, f2, f3, f4);\n}\n\nvoid FTransitionItemData::SetVec4(const FVector4& value)\n{\n    f1 = value.X;\n    f2 = value.Y;\n    f3 = value.Z;\n    f4 = value.W;\n}\n\nFColor FTransitionItemData::GetColor() const\n{\n    return FColor(f1*255.f, f2*255.f, f3*255.f, f4*255.f);\n}\n\nvoid FTransitionItemData::SetColor(const FColor& value)\n{\n    f1 = value.R / 255.f;\n    f2 = value.G / 255.f;\n    f3 = value.B / 255.f;\n    f4 = value.A / 255.f;\n}\n\nstruct FTweenConfig\n{\n    float Duration;\n    EEaseType EaseType;\n    int32 Repeat;\n    bool bYoyo;\n\n    FTransitionItemData StartData;\n    FTransitionItemData EndData;\n    TSharedPtr<FGPath> Path;\n\n    FString EndLabel;\n    FSimpleDelegate EndHook;\n\n    FTweenConfig();\n};\n\nFTweenConfig::FTweenConfig() :\n    EaseType(EEaseType::QuadOut)\n{\n}\n\nstruct FTransitionItem\n{\n    float Time;\n    FString TargetID;\n    ETransitionActionType Type;\n    TOptional<FTweenConfig> TweenConfig;\n    FString Label;\n    FSimpleDelegate Hook;\n\n    TOptional<FTransitionItemData> Data;\n    TOptional<bool> VisibleData;\n    TOptional<FAniData> AniData;\n    TOptional<FSoundData> SoundData;\n    TOptional<FInnerTransData> TransData;\n    TOptional<FShakeData> ShakeData;\n    TOptional<FString> TextData;\n\n    //running properties\n    FGTweener* Tweener;\n    UGObject* Target;\n    uint32 DisplayLockToken;\n\n    FTransitionItem(ETransitionActionType aType);\n    ~FTransitionItem();\n};\n\nFTransitionItem::FTransitionItem(ETransitionActionType InType) :\n    Time(0),\n    Type(InType),\n    Tweener(nullptr),\n    Target(nullptr),\n    DisplayLockToken(0)\n{\n    switch (InType)\n    {\n    case ETransitionActionType::XY:\n    case ETransitionActionType::Size:\n    case ETransitionActionType::Scale:\n    case ETransitionActionType::Pivot:\n    case ETransitionActionType::Skew:\n    case ETransitionActionType::Alpha:\n    case ETransitionActionType::Rotation:\n    case ETransitionActionType::Color:\n    case ETransitionActionType::ColorFilter:\n        Data.Emplace();\n        break;\n\n    case ETransitionActionType::Animation:\n        AniData.Emplace();\n        break;\n\n    case ETransitionActionType::Shake:\n        ShakeData.Emplace();\n        break;\n\n    case ETransitionActionType::Sound:\n        SoundData.Emplace();\n        break;\n\n    case ETransitionActionType::Transition:\n        TransData.Emplace();\n        break;\n\n    case ETransitionActionType::Visible:\n        VisibleData.Emplace();\n        break;\n\n    case ETransitionActionType::Text:\n    case ETransitionActionType::Icon:\n        TextData.Emplace();\n        break;\n\n    default:\n        break;\n    }\n}\n\nFTransitionItem::~FTransitionItem()\n{\n    if (Tweener != nullptr)\n        Tweener->Kill();\n}\n\nUTransition::UTransition() :\n    TotalTimes(0),\n    TotalTasks(0),\n    bPlaying(false),\n    bPaused(false),\n    Options(0),\n    bReversed(false),\n    TotalDuration(0),\n    bAutoPlay(false),\n    AutoPlayDelay(0),\n    TimeScale(1),\n    StartTime(0),\n    EndTime(0)\n{\n\n}\n\nUTransition::~UTransition()\n{\n    if (DelayHandle.IsValid())\n        FGTween::Kill(DelayHandle);\n\n    for (auto &it : Items)\n        delete it;\n}\n\nvoid UTransition::Play(int32 InTimes, float InDelay, float InStartTime, float InEndTime, bool bInReverse, FSimpleDelegate InCompleteCallback)\n{\n    Stop(true, true);\n\n    TotalTimes = InTimes;\n    bReversed = bInReverse;\n    StartTime = InStartTime;\n    EndTime = InEndTime;\n    bPlaying = true;\n    bPaused = false;\n    CompleteCallback = InCompleteCallback;\n\n    int32 cnt = Items.Num();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FTransitionItem* item = Items[i];\n        if (item->Target == nullptr)\n        {\n            if (!item->TargetID.IsEmpty())\n                item->Target = Owner->GetChildByID(item->TargetID);\n            else\n                item->Target = Owner;\n        }\n        else if (item->Target != Owner && item->Target->GetParent() != Owner) //maybe removed\n            item->Target = nullptr;\n\n        if (item->Target != nullptr && item->Type == ETransitionActionType::Transition)\n        {\n            UTransition* trans = Cast<UGComponent>(item->Target)->GetTransition(item->TransData->Name);\n            if (trans == this)\n                trans = nullptr;\n            if (trans != nullptr)\n            {\n                if (item->TransData->PlayTimes == 0) //stop\n                {\n                    int32 j;\n                    for (j = i - 1; j >= 0; j--)\n                    {\n                        FTransitionItem* item2 = Items[j];\n                        if (item2->Type == ETransitionActionType::Transition)\n                        {\n                            if (item2->TransData->Instance == trans)\n                            {\n                                item2->TransData->StopTime = item->Time - item2->Time;\n                                break;\n                            }\n                        }\n                    }\n                    if (j < 0)\n                        item->TransData->StopTime = 0;\n                    else\n                        trans = nullptr; //no need to handle stop anymore\n                }\n                else\n                    item->TransData->StopTime = -1;\n            }\n            item->TransData->Instance = trans;\n        }\n    }\n\n    if (InDelay == 0)\n        OnDelayedPlay();\n    else\n        DelayHandle = FGTween::DelayedCall(InDelay)->OnComplete(FSimpleDelegate::CreateUObject(this, &UTransition::OnDelayedPlay))->GetHandle();\n}\n\nvoid UTransition::ChangePlayTimes(int32 InTimes)\n{\n    TotalTimes = InTimes;\n}\n\nvoid UTransition::SetAutoPlay(bool bInAutoPlay, int32 InTimes, float InDelay)\n{\n    if (bAutoPlay != bInAutoPlay)\n    {\n        bAutoPlay = bInAutoPlay;\n        AutoPlayTimes = InTimes;\n        AutoPlayDelay = InDelay;\n        if (bAutoPlay)\n        {\n            if (Owner->OnStage())\n                Play(AutoPlayTimes, AutoPlayDelay);\n        }\n        else\n        {\n            if (!Owner->OnStage())\n                Stop(false, true);\n        }\n    }\n}\n\nvoid UTransition::Stop(bool bSetToComplete, bool bProcessCallback)\n{\n    if (!bPlaying)\n        return;\n\n    bPlaying = false;\n    TotalTasks = 0;\n    TotalTimes = 0;\n    FSimpleDelegate func = CompleteCallback;\n    CompleteCallback.Unbind();\n\n    int32 cnt = Items.Num();\n    if (bReversed)\n    {\n        for (int32 i = cnt - 1; i >= 0; i--)\n        {\n            FTransitionItem* item = Items[i];\n            if (item->Target == nullptr)\n                continue;\n\n            StopItem(item, bSetToComplete);\n        }\n    }\n    else\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FTransitionItem* item = Items[i];\n            if (item->Target == nullptr)\n                continue;\n\n            StopItem(item, bSetToComplete);\n        }\n    }\n    if (bProcessCallback)\n        func.ExecuteIfBound();\n}\n\nvoid UTransition::StopItem(FTransitionItem* item, bool bSetToComplete)\n{\n    if (item->DisplayLockToken != 0)\n    {\n        item->Target->ReleaseDisplayLock(item->DisplayLockToken);\n        item->DisplayLockToken = 0;\n    }\n\n    if (item->Tweener != nullptr)\n    {\n        item->Tweener->Kill(bSetToComplete);\n        item->Tweener = nullptr;\n\n        if (item->Type == ETransitionActionType::Shake && !bSetToComplete)\n        {\n            item->Target->bGearLocked = true;\n            item->Target->SetPosition(item->Target->GetPosition() - item->ShakeData->LastOffset);\n            item->Target->bGearLocked = false;\n        }\n    }\n}\n\nvoid UTransition::SetPaused(bool bInPaused)\n{\n    if (!bPlaying || bPaused == bInPaused)\n        return;\n\n    bPaused = bInPaused;\n    FGTweener* tweener = FGTween::GetTween(DelayHandle);\n    if (tweener != nullptr)\n        tweener->SetPaused(bPaused);\n\n    for (auto& item : Items)\n    {\n        if (item->Target == nullptr)\n            continue;\n\n        if (item->Type == ETransitionActionType::Transition)\n        {\n            if (item->TransData->Instance != nullptr)\n                item->TransData->Instance->SetPaused(bPaused);\n        }\n        else if (item->Type == ETransitionActionType::Animation)\n        {\n            if (bPaused)\n            {\n                item->AniData->bFlag = item->Target->GetProp<bool>(EObjectPropID::Playing);\n                item->Target->SetProp(EObjectPropID::Playing, FNVariant(false));\n            }\n            else\n                item->Target->SetProp(EObjectPropID::Playing, FNVariant(item->AniData->bFlag));\n        }\n\n        if (item->Tweener != nullptr)\n            item->Tweener->SetPaused(bPaused);\n    }\n}\n\nvoid UTransition::SetValue(const FString& InLabel, const TArray<FNVariant>& InValues)\n{\n    FTransitionItemData* Value = nullptr;\n\n    for (auto& item : Items)\n    {\n        if (item->Label == InLabel)\n        {\n            if (item->TweenConfig.IsSet())\n                Value = &item->TweenConfig->StartData;\n            else if (item->Data.IsSet())\n                Value = &item->Data.GetValue();\n        }\n        else if (item->TweenConfig.IsSet() && item->TweenConfig->EndLabel == InLabel)\n        {\n            Value = &item->TweenConfig->EndData;\n        }\n        else\n            continue;\n\n        switch (item->Type)\n        {\n        case ETransitionActionType::XY:\n        case ETransitionActionType::Size:\n        case ETransitionActionType::Pivot:\n        case ETransitionActionType::Scale:\n        case ETransitionActionType::Skew:\n        {\n            Value->b1 = true;\n            Value->b2 = true;\n            Value->f1 = InValues[0].AsFloat();\n            Value->f2 = InValues[1].AsFloat();\n            break;\n        }\n\n        case ETransitionActionType::Alpha:\n        case ETransitionActionType::Rotation:\n            Value->f1 = InValues[0].AsFloat();\n            break;\n\n        case ETransitionActionType::Color:\n        {\n            Value->SetColor(InValues[0].AsColor());\n            break;\n        }\n\n        case ETransitionActionType::Animation:\n        {\n            item->AniData->Frame = InValues[0].AsInt();\n            if (InValues.Num() > 1)\n                item->AniData->bPlaying = InValues[0].AsBool();\n            break;\n        }\n\n        case ETransitionActionType::Visible:\n            item->VisibleData = InValues[0].AsBool();\n            break;\n\n        case ETransitionActionType::Sound:\n        {\n            item->SoundData->URL = InValues[0].AsString();\n            if (InValues.Num() > 1)\n                item->SoundData->Volume = InValues[1].AsFloat();\n            break;\n        }\n\n        case ETransitionActionType::Transition:\n        {\n            item->TransData->Name = InValues[0].AsString();\n            if (InValues.Num() > 1)\n                item->TransData->PlayTimes = InValues[1].AsInt();\n            break;\n        }\n\n        case ETransitionActionType::Shake:\n        {\n            item->ShakeData->Amplitude = InValues[0].AsFloat();\n            if (InValues.Num() > 1)\n                item->ShakeData->Duration = InValues[1].AsFloat();\n            break;\n        }\n\n        case ETransitionActionType::ColorFilter:\n        {\n            Value->f1 = InValues[0].AsFloat();\n            Value->f2 = InValues[1].AsFloat();\n            Value->f3 = InValues[2].AsFloat();\n            Value->f4 = InValues[3].AsFloat();\n            break;\n        }\n\n        case ETransitionActionType::Text:\n        case ETransitionActionType::Icon:\n            item->TextData = InValues[0].AsString();\n            break;\n        default:\n            break;\n        }\n    }\n}\n\nvoid UTransition::SetHook(const FString& InLabel, FSimpleDelegate Callback)\n{\n    for (auto& item : Items)\n    {\n        if (item->Label == InLabel)\n        {\n            item->Hook = Callback;\n            break;\n        }\n        else if (item->TweenConfig.IsSet() && item->TweenConfig->EndLabel == InLabel)\n        {\n            item->TweenConfig->EndHook = Callback;\n            break;\n        }\n    }\n}\n\nvoid UTransition::ClearHooks()\n{\n    for (auto& item : Items)\n    {\n        item->Hook.Unbind();\n        if (item->TweenConfig.IsSet())\n            item->TweenConfig->EndHook.Unbind();\n    }\n}\n\nvoid UTransition::SetTarget(const FString& InLabel, UGObject* InTarget)\n{\n    for (auto& item : Items)\n    {\n        if (item->Label == InLabel)\n        {\n\n            item->TargetID = InTarget->ID;\n            item->Target = nullptr;\n        }\n    }\n}\n\nvoid UTransition::SetDuration(const FString& InLabel, float InDuration)\n{\n    for (auto& item : Items)\n    {\n        if (item->TweenConfig.IsSet() && item->Label == InLabel)\n            item->TweenConfig->Duration = InDuration;\n    }\n}\n\nfloat UTransition::GetLabelTime(const FString& InLabel) const\n{\n    for (auto& item : Items)\n    {\n        if (item->Label == InLabel)\n        {\n            if (item->TweenConfig.IsSet())\n                return item->Time + item->TweenConfig->Duration;\n            else\n                return item->Time;\n        }\n    }\n\n    return NAN;\n}\n\nvoid UTransition::SetTimeScale(float InTimeScale)\n{\n    if (TimeScale != InTimeScale)\n    {\n        TimeScale = InTimeScale;\n\n        for (auto& item : Items)\n        {\n            if (item->Tweener != nullptr)\n                item->Tweener->SetTimeScale(InTimeScale);\n            else if (item->Type == ETransitionActionType::Transition)\n            {\n                if (item->TransData->Instance != nullptr)\n                    item->TransData->Instance->SetTimeScale(InTimeScale);\n            }\n            else if (item->Type == ETransitionActionType::Animation)\n            {\n                if (item->Target != nullptr)\n                    item->Target->SetProp(EObjectPropID::TimeScale, FNVariant(InTimeScale));\n            }\n        }\n    }\n}\n\nvoid UTransition::UpdateFromRelations(const FString& TargetID, const FVector2D& Delta)\n{\n    int32 cnt = Items.Num();\n    if (cnt == 0)\n        return;\n\n    for (auto& item : Items)\n    {\n        if (item->Type == ETransitionActionType::XY && item->TargetID == TargetID)\n        {\n            if (item->TweenConfig.IsSet())\n            {\n                if (!item->TweenConfig->StartData.b3) {\n                    item->TweenConfig->StartData.f1 += Delta.X;\n                    item->TweenConfig->StartData.f2 += Delta.Y;\n                    item->TweenConfig->EndData.f1 += Delta.X;\n                    item->TweenConfig->EndData.f2 += Delta.Y;\n                }\n            }\n            else\n            {\n                if (!item->Data->b3) {\n                    item->Data->f1 += Delta.X;\n                    item->Data->f2 += Delta.Y;\n                }\n            }\n        }\n    }\n}\n\nvoid UTransition::OnOwnerAddedToStage()\n{\n    if (bAutoPlay && !bPlaying)\n        Play(AutoPlayTimes, AutoPlayDelay);\n}\n\nvoid UTransition::OnOwnerRemovedFromStage()\n{\n    if ((Options & OPTION_AUTO_STOP_DISABLED) == 0)\n        Stop((Options & OPTION_AUTO_STOP_AT_END) != 0 ? true : false, false);\n}\n\nvoid UTransition::OnDelayedPlay()\n{\n    InternalPlay();\n\n    bPlaying = TotalTasks > 0;\n    if (bPlaying)\n    {\n        if ((Options & OPTION_IGNORE_DISPLAY_CONTROLLER) != 0)\n        {\n            for (auto& item : Items)\n            {\n                if (item->Target != nullptr && item->Target != Owner)\n                    item->DisplayLockToken = item->Target->AddDisplayLock();\n            }\n        }\n    }\n    else if (CompleteCallback.IsBound())\n    {\n        FSimpleDelegate func = CompleteCallback;\n        CompleteCallback.Unbind();\n        func.Execute();\n    }\n}\n\nvoid UTransition::InternalPlay()\n{\n    OwnerBasePos = Owner->GetPosition();\n\n    TotalTasks = 0;\n\n    bool bNeedSkipAnimations = false;\n    int32 cnt = Items.Num();\n    if (!bReversed)\n    {\n        for (int32 i = 0; i < cnt; i++)\n        {\n            FTransitionItem* item = Items[i];\n            if (item->Target == nullptr)\n                continue;\n\n            if (item->Type == ETransitionActionType::Animation && StartTime != 0 && item->Time <= StartTime)\n            {\n                bNeedSkipAnimations = true;\n                item->AniData->bFlag = false;\n            }\n            else\n                PlayItem(item);\n        }\n    }\n    else\n    {\n        for (int32 i = cnt - 1; i >= 0; i--)\n        {\n            FTransitionItem* item = Items[i];\n            if (item->Target == nullptr)\n                continue;\n\n            PlayItem(item);\n        }\n    }\n\n    if (bNeedSkipAnimations)\n        SkipAnimations();\n}\n\nvoid UTransition::PlayItem(FTransitionItem* item)\n{\n    float time;\n    if (item->TweenConfig.IsSet())\n    {\n        if (bReversed)\n            time = (TotalDuration - item->Time - item->TweenConfig->Duration);\n        else\n            time = item->Time;\n\n        if (EndTime == -1 || time <= EndTime)\n        {\n            FTransitionItemData* startValue;\n            FTransitionItemData* endValue;\n\n            if (bReversed)\n            {\n                startValue = &item->TweenConfig->EndData;\n                endValue = &item->TweenConfig->StartData;\n            }\n            else\n            {\n                startValue = &item->TweenConfig->StartData;\n                endValue = &item->TweenConfig->EndData;\n            }\n\n            item->Data->b1 = startValue->b1 || endValue->b1;\n            item->Data->b2 = startValue->b2 || endValue->b2;\n\n            switch (item->Type)\n            {\n            case ETransitionActionType::XY:\n            case ETransitionActionType::Size:\n            case ETransitionActionType::Scale:\n            case ETransitionActionType::Skew:\n                item->Tweener = FGTween::To(startValue->GetVec2(), endValue->GetVec2(), item->TweenConfig->Duration);\n                break;\n\n            case ETransitionActionType::Alpha:\n            case ETransitionActionType::Rotation:\n                item->Tweener = FGTween::To(startValue->f1, endValue->f1, item->TweenConfig->Duration);\n                break;\n\n            case ETransitionActionType::Color:\n                item->Tweener = FGTween::To(startValue->GetColor(), endValue->GetColor(), item->TweenConfig->Duration);\n                break;\n\n            case ETransitionActionType::ColorFilter:\n                item->Tweener = FGTween::To(startValue->GetVec4(), endValue->GetVec4(), item->TweenConfig->Duration);\n                break;\n            default:\n                break;\n            }\n\n            item->Tweener->SetDelay(time)\n                ->SetEase(item->TweenConfig->EaseType)\n                ->SetRepeat(item->TweenConfig->Repeat, item->TweenConfig->bYoyo)\n                ->SetTimeScale(TimeScale)\n                ->SetUserData(FNVariant(item))\n                ->OnStart(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenStart))\n                ->OnUpdate(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenUpdate))\n                ->OnComplete(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenComplete));\n\n            if (EndTime >= 0)\n                item->Tweener->SetBreakpoint(EndTime - time);\n\n            TotalTasks++;\n        }\n    }\n    else if (item->Type == ETransitionActionType::Shake)\n    {\n        if (bReversed)\n            time = (TotalDuration - item->Time - item->ShakeData->Duration);\n        else\n            time = item->Time;\n\n        if (EndTime == -1 || time <= EndTime)\n        {\n            item->ShakeData->LastOffset.Set(0, 0);\n            item->ShakeData->Offset.Set(0, 0);\n            item->Tweener = FGTween::Shake(FVector2D::ZeroVector, item->ShakeData->Amplitude, item->ShakeData->Duration)\n                ->SetDelay(time)\n                ->SetTimeScale(TimeScale)\n                ->SetUserData(FNVariant(item))\n                ->OnStart(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenStart))\n                ->OnUpdate(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenUpdate))\n                ->OnComplete(FTweenDelegate::CreateUObject(this, &UTransition::OnTweenComplete));\n\n            if (EndTime >= 0)\n                item->Tweener->SetBreakpoint(EndTime - item->Time);\n\n            TotalTasks++;\n        }\n    }\n    else\n    {\n        if (bReversed)\n            time = (TotalDuration - item->Time);\n        else\n            time = item->Time;\n\n        if (time <= StartTime)\n        {\n            ApplyValue(item);\n            CallHook(item, false);\n        }\n        else if (EndTime == -1 || time <= EndTime)\n        {\n            TotalTasks++;\n            item->Tweener = FGTween::DelayedCall(time)\n                ->SetTimeScale(TimeScale)\n                ->SetUserData(FNVariant(item))\n                ->OnComplete(FTweenDelegate::CreateUObject(this, &UTransition::OnDelayedPlayItem));\n        }\n    }\n\n    if (item->Tweener != nullptr)\n        item->Tweener->Seek(StartTime);\n}\n\nvoid UTransition::SkipAnimations()\n{\n    int32 frame;\n    float playStartTime;\n    float playTotalTime;\n    UGObject* target;\n\n    int32 cnt = Items.Num();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        FTransitionItem* item = Items[i];\n        if (item->Type != ETransitionActionType::Animation || item->Time > StartTime)\n            continue;\n\n        if (item->AniData->bFlag)\n            continue;\n\n        target = item->Target;\n        frame = target->GetProp<int32>(EObjectPropID::Frame);\n        playStartTime = target->GetProp<bool>(EObjectPropID::Playing) ? 0 : -1;\n        playTotalTime = 0;\n\n        for (int32 j = i; j < cnt; j++)\n        {\n            item = Items[j];\n            if (item->Type != ETransitionActionType::Animation || item->Target != target || item->Time > StartTime)\n                continue;\n\n            item->AniData->bFlag = true;\n\n            if (item->AniData->Frame != -1)\n            {\n                frame = item->AniData->Frame;\n                if (item->AniData->bPlaying)\n                    playStartTime = item->Time;\n                else\n                    playStartTime = -1;\n                playTotalTime = 0;\n            }\n            else\n            {\n                if (item->AniData->bPlaying)\n                {\n                    if (playStartTime < 0)\n                        playStartTime = item->Time;\n                }\n                else\n                {\n                    if (playStartTime >= 0)\n                        playTotalTime += (item->Time - playStartTime);\n                    playStartTime = -1;\n                }\n            }\n\n            CallHook(item, false);\n        }\n\n        if (playStartTime >= 0)\n            playTotalTime += (StartTime - playStartTime);\n\n        target->SetProp(EObjectPropID::Playing, FNVariant(playStartTime >= 0));\n        target->SetProp(EObjectPropID::Frame, FNVariant(frame));\n        if (playTotalTime > 0)\n            target->SetProp(EObjectPropID::DeltaTime, FNVariant(playTotalTime));\n    }\n}\n\nvoid UTransition::OnDelayedPlayItem(FGTweener* Tweener)\n{\n    FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As<void*>();\n    item->Tweener = nullptr;\n    TotalTasks--;\n\n    ApplyValue(item);\n    CallHook(item, false);\n\n    CheckAllComplete();\n}\n\nvoid UTransition::OnTweenStart(FGTweener* Tweener)\n{\n    FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As<void*>();\n\n    if (item->Type == ETransitionActionType::XY || item->Type == ETransitionActionType::Size)\n    {\n        FTransitionItemData* startValue;\n        FTransitionItemData* endValue;\n\n        if (bReversed)\n        {\n            startValue = &item->TweenConfig->EndData;\n            endValue = &item->TweenConfig->StartData;\n        }\n        else\n        {\n            startValue = &item->TweenConfig->StartData;\n            endValue = &item->TweenConfig->EndData;\n        }\n\n        if (item->Type == ETransitionActionType::XY)\n        {\n            if (item->Target != Owner)\n            {\n                if (!startValue->b1)\n                    Tweener->StartValue.X = item->Target->GetX();\n                else if (startValue->b3) //percent\n                    Tweener->StartValue.X = startValue->f1 * Owner->GetWidth();\n\n                if (!startValue->b2)\n                    Tweener->StartValue.Y = item->Target->GetY();\n                else if (startValue->b3) //percent\n                    Tweener->StartValue.Y = startValue->f2 * Owner->GetHeight();\n\n                if (!endValue->b1)\n                    Tweener->EndValue.X = Tweener->StartValue.X;\n                else if (endValue->b3)\n                    Tweener->EndValue.X = endValue->f1 * Owner->GetWidth();\n\n                if (!endValue->b2)\n                    Tweener->EndValue.Y = Tweener->StartValue.Y;\n                else if (endValue->b3)\n                    Tweener->EndValue.Y = endValue->f2 * Owner->GetHeight();\n            }\n            else\n            {\n                if (!startValue->b1)\n                    Tweener->StartValue.X = item->Target->GetX() - OwnerBasePos.X;\n                if (!startValue->b2)\n                    Tweener->StartValue.Y = item->Target->GetY() - OwnerBasePos.Y;\n\n                if (!endValue->b1)\n                    Tweener->EndValue.X = Tweener->StartValue.X;\n                if (!endValue->b2)\n                    Tweener->EndValue.Y = Tweener->StartValue.Y;\n            }\n        }\n        else\n        {\n            if (!startValue->b1)\n                Tweener->StartValue.X = item->Target->GetWidth();\n            if (!startValue->b2)\n                Tweener->StartValue.Y = item->Target->GetHeight();\n\n            if (!endValue->b1)\n                Tweener->EndValue.X = Tweener->StartValue.X;\n            if (!endValue->b2)\n                Tweener->EndValue.Y = Tweener->StartValue.Y;\n        }\n\n        if (item->TweenConfig->Path.IsValid())\n        {\n            item->Data->b1 = item->Data->b2 = true;\n            Tweener->SetPath(item->TweenConfig->Path);\n        }\n    }\n\n    CallHook(item, false);\n}\n\nvoid UTransition::OnTweenUpdate(FGTweener* Tweener)\n{\n    FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As<void*>();\n\n    switch (item->Type)\n    {\n    case ETransitionActionType::XY:\n    case ETransitionActionType::Size:\n    case ETransitionActionType::Scale:\n    case ETransitionActionType::Skew:\n        if (item->TweenConfig->Path.IsValid())\n            item->Data->SetVec2(Tweener->Value.GetVec2() + Tweener->StartValue.GetVec2());\n        else\n            item->Data->SetVec2(Tweener->Value.GetVec2());\n        break;\n\n    case ETransitionActionType::Alpha:\n    case ETransitionActionType::Rotation:\n        item->Data->f1 = Tweener->Value.X;\n        break;\n\n    case ETransitionActionType::Color:\n        item->Data->SetColor(Tweener->Value.GetColor());\n        break;\n\n    case ETransitionActionType::ColorFilter:\n        item->Data->SetVec4(Tweener->Value.GetVec4());\n        break;\n\n    case ETransitionActionType::Shake:\n        item->ShakeData->Offset = Tweener->DeltaValue.GetVec2();\n        break;\n    default:\n        break;\n    }\n    ApplyValue(item);\n}\n\nvoid UTransition::OnTweenComplete(FGTweener* Tweener)\n{\n    FTransitionItem* item = (FTransitionItem*)Tweener->GetUserData().As<void*>();\n    item->Tweener = nullptr;\n    TotalTasks--;\n\n    if (Tweener->AllCompleted())\n        CallHook(item, true);\n\n    CheckAllComplete();\n}\n\nvoid UTransition::OnPlayTransCompleted(FTransitionItem* item)\n{\n    TotalTasks--;\n\n    CheckAllComplete();\n}\n\nvoid UTransition::CallHook(FTransitionItem* item, bool bTweenEnd)\n{\n    if (bTweenEnd)\n    {\n        if (item->TweenConfig.IsSet() && item->TweenConfig->EndHook.IsBound())\n            item->TweenConfig->EndHook.Execute();\n    }\n    else\n    {\n        if (item->Time >= StartTime && item->Hook.IsBound())\n            item->Hook.Execute();\n    }\n}\n\nvoid UTransition::CheckAllComplete()\n{\n    if (bPlaying && TotalTasks == 0)\n    {\n        if (TotalTimes < 0)\n        {\n            InternalPlay();\n        }\n        else\n        {\n            TotalTimes--;\n            if (TotalTimes > 0)\n                InternalPlay();\n            else\n            {\n                bPlaying = false;\n\n                for (auto& item : Items)\n                {\n                    if (item->Target != nullptr && item->DisplayLockToken != 0)\n                    {\n                        item->Target->ReleaseDisplayLock(item->DisplayLockToken);\n                        item->DisplayLockToken = 0;\n                    }\n                }\n\n                if (CompleteCallback.IsBound())\n                {\n                    FSimpleDelegate func = CompleteCallback;\n                    CompleteCallback.Unbind();\n                    func.Execute();\n                }\n            }\n        }\n    }\n}\n\nvoid UTransition::ApplyValue(FTransitionItem* item)\n{\n    item->Target->bGearLocked = true;\n\n    switch (item->Type)\n    {\n    case ETransitionActionType::XY:\n    {\n        if (item->Target == Owner)\n        {\n            if (item->Data->b1 && item->Data->b2)\n                item->Target->SetPosition(item->Data->GetVec2() + OwnerBasePos);\n            else if (item->Data->b1)\n                item->Target->SetX(item->Data->f1 + OwnerBasePos.X);\n            else\n                item->Target->SetY(item->Data->f2 + OwnerBasePos.Y);\n        }\n        else\n        {\n            if (item->Data->b3) //position in percent\n            {\n                if (item->Data->b1 && item->Data->b2)\n                    item->Target->SetPosition(item->Data->GetVec2() * Owner->GetSize());\n                else if (item->Data->b1)\n                    item->Target->SetX(item->Data->f1 * Owner->GetWidth());\n                else if (item->Data->b2)\n                    item->Target->SetY(item->Data->f2 * Owner->GetHeight());\n            }\n            else\n            {\n                if (item->Data->b1 && item->Data->b2)\n                    item->Target->SetPosition(item->Data->GetVec2());\n                else if (item->Data->b1)\n                    item->Target->SetX(item->Data->f1);\n                else if (item->Data->b2)\n                    item->Target->SetY(item->Data->f2);\n            }\n        }\n    }\n    break;\n\n    case ETransitionActionType::Size:\n    {\n        if (!item->Data->b1)\n            item->Data->f1 = item->Target->GetWidth();\n        if (!item->Data->b2)\n            item->Data->f2 = item->Target->GetHeight();\n        item->Target->SetSize(item->Data->GetVec2());\n    }\n    break;\n\n    case ETransitionActionType::Pivot:\n        item->Target->SetPivot(item->Data->GetVec2(), item->Target->IsPivotAsAnchor());\n        break;\n\n    case ETransitionActionType::Alpha:\n        item->Target->SetAlpha(item->Data->f1);\n        break;\n\n    case ETransitionActionType::Rotation:\n        item->Target->SetRotation(item->Data->f1);\n        break;\n\n    case ETransitionActionType::Scale:\n        item->Target->SetScale(item->Data->GetVec2());\n        break;\n\n    case ETransitionActionType::Skew:\n        item->Target->SetSkew(item->Data->GetVec2());\n        break;\n\n    case ETransitionActionType::Color:\n        item->Target->SetProp(EObjectPropID::Color, FNVariant(item->Data->GetColor()));\n        break;\n\n    case ETransitionActionType::Animation:\n    {\n        if (item->AniData->Frame >= 0)\n            item->Target->SetProp(EObjectPropID::Frame, FNVariant(item->AniData->Frame));\n        item->Target->SetProp(EObjectPropID::Playing, FNVariant(item->AniData->bPlaying));\n        item->Target->SetProp(EObjectPropID::TimeScale, FNVariant(TimeScale));\n        break;\n    }\n\n    case ETransitionActionType::Visible:\n        item->Target->SetVisible(item->VisibleData.GetValue());\n        break;\n\n    case ETransitionActionType::Shake:\n    {\n        item->Target->SetPosition(item->Target->GetPosition() - item->ShakeData->LastOffset + item->ShakeData->Offset);\n        item->ShakeData->LastOffset = item->ShakeData->Offset;\n        break;\n    }\n\n    case ETransitionActionType::Transition:\n        if (bPlaying)\n        {\n            if (item->TransData->Instance != nullptr)\n            {\n                TotalTasks++;\n\n                float playStartTime = StartTime > item->Time ? (StartTime - item->Time) : 0;\n                float playEndTime = EndTime >= 0 ? (EndTime - item->Time) : -1;\n                if (item->TransData->StopTime >= 0 && (playEndTime < 0 || playEndTime > item->TransData->StopTime))\n                    playEndTime = item->TransData->StopTime;\n                item->TransData->Instance->SetTimeScale(TimeScale);\n                item->TransData->Instance->Play(item->TransData->PlayTimes, 0, playStartTime, playEndTime, bReversed,\n                    FSimpleDelegate::CreateUObject(this, &UTransition::OnPlayTransCompleted, item));\n            }\n        }\n        break;\n\n    case ETransitionActionType::Sound:\n        if (bPlaying && item->Time >= StartTime)\n        {\n            if (!item->SoundData->URL.IsEmpty())\n                Owner->GetApp()->PlaySound(item->SoundData->URL, item->SoundData->Volume);\n            break;\n        }\n\n    case ETransitionActionType::ColorFilter:\n        break;\n\n    case ETransitionActionType::Text:\n        item->Target->SetText(item->TextData.GetValue());\n        break;\n\n    case ETransitionActionType::Icon:\n        item->Target->SetIcon(item->TextData.GetValue());\n        break;\n    default:\n        break;\n    }\n\n    item->Target->bGearLocked = false;\n}\n\nvoid UTransition::Setup(FByteBuffer* Buffer)\n{\n    Owner = Cast<UGComponent>(GetOuter());\n\n    Name = Buffer->ReadS();\n    Options = Buffer->ReadInt();\n    bAutoPlay = Buffer->ReadBool();\n    AutoPlayTimes = Buffer->ReadInt();\n    AutoPlayDelay = Buffer->ReadFloat();\n\n    int32 cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        int32 dataLen = Buffer->ReadShort();\n        int32 curPos = Buffer->GetPos();\n\n        Buffer->Seek(curPos, 0);\n\n        Items.Add(new FTransitionItem((ETransitionActionType)Buffer->ReadByte()));\n        FTransitionItem* item = Items.Last();\n\n        item->Time = Buffer->ReadFloat();\n        int32 TargetID = Buffer->ReadShort();\n        if (TargetID < 0)\n            item->TargetID = G_EMPTY_STRING;\n        else\n            item->TargetID = Owner->GetChildAt(TargetID)->ID;\n        item->Label = Buffer->ReadS();\n\n        if (Buffer->ReadBool())\n        {\n            Buffer->Seek(curPos, 1);\n\n            item->TweenConfig.Emplace();\n            item->TweenConfig->Duration = Buffer->ReadFloat();\n            if (item->Time + item->TweenConfig->Duration > TotalDuration)\n                TotalDuration = item->Time + item->TweenConfig->Duration;\n            item->TweenConfig->EaseType = (EEaseType)Buffer->ReadByte();\n            item->TweenConfig->Repeat = Buffer->ReadInt();\n            item->TweenConfig->bYoyo = Buffer->ReadBool();\n            item->TweenConfig->EndLabel = Buffer->ReadS();\n\n            Buffer->Seek(curPos, 2);\n\n            DecodeValue(item, Buffer, &item->TweenConfig->StartData);\n\n            Buffer->Seek(curPos, 3);\n\n            DecodeValue(item, Buffer, &item->TweenConfig->EndData);\n\n            if (Buffer->Version >= 2)\n            {\n                int32 pathLen = Buffer->ReadInt();\n                if (pathLen > 0)\n                {\n                    item->TweenConfig->Path = MakeShareable(new FGPath());\n                    TArray<FGPathPoint> pts;\n\n                    FVector v0(ForceInit), v1(ForceInit), v2(ForceInit);\n\n                    for (int32 j = 0; j < pathLen; j++)\n                    {\n                        FGPathPoint::ECurveType curveType = (FGPathPoint::ECurveType)Buffer->ReadByte();\n                        switch (curveType)\n                        {\n                        case FGPathPoint::ECurveType::Bezier:\n                            v0.X = Buffer->ReadFloat();\n                            v0.Y = Buffer->ReadFloat();\n                            v1.X = Buffer->ReadFloat();\n                            v1.Y = Buffer->ReadFloat();\n                            pts.Add(FGPathPoint(v0, v1));\n                            break;\n\n                        case FGPathPoint::ECurveType::CubicBezier:\n                            v0.X = Buffer->ReadFloat();\n                            v0.Y = Buffer->ReadFloat();\n                            v1.X = Buffer->ReadFloat();\n                            v1.Y = Buffer->ReadFloat();\n                            v2.X = Buffer->ReadFloat();\n                            v2.Y = Buffer->ReadFloat();\n                            pts.Add(FGPathPoint(v0, v1, v2));\n                            break;\n\n                        default:\n                            v0.X = Buffer->ReadFloat();\n                            v0.Y = Buffer->ReadFloat();\n                            pts.Add(FGPathPoint(v0, curveType));\n                            break;\n                        }\n                    }\n\n                    item->TweenConfig->Path->Create(pts.GetData(), pts.Num());\n                }\n            }\n        }\n        else\n        {\n            if (item->Time > TotalDuration)\n                TotalDuration = item->Time;\n\n            Buffer->Seek(curPos, 2);\n\n            DecodeValue(item, Buffer, item->Data.IsSet() ? &item->Data.GetValue() : nullptr);\n        }\n\n        Buffer->SetPos(curPos + dataLen);\n    }\n}\n\nvoid UTransition::DecodeValue(FTransitionItem* item, FByteBuffer* Buffer, FTransitionItemData* Value)\n{\n    switch (item->Type)\n    {\n    case ETransitionActionType::XY:\n    case ETransitionActionType::Size:\n    case ETransitionActionType::Pivot:\n    case ETransitionActionType::Skew:\n    {\n        Value->b1 = Buffer->ReadBool();\n        Value->b2 = Buffer->ReadBool();\n        Value->f1 = Buffer->ReadFloat();\n        Value->f2 = Buffer->ReadFloat();\n\n        if (Buffer->Version >= 2 && item->Type == ETransitionActionType::XY)\n            Value->b3 = Buffer->ReadBool(); //percent\n        break;\n    }\n\n    case ETransitionActionType::Alpha:\n    case ETransitionActionType::Rotation:\n        Value->f1 = Buffer->ReadFloat();\n        break;\n\n    case ETransitionActionType::Scale:\n    {\n        Value->f1 = Buffer->ReadFloat();\n        Value->f2 = Buffer->ReadFloat();\n        break;\n    }\n\n    case ETransitionActionType::Color:\n        Value->SetColor(Buffer->ReadColor());\n        break;\n\n    case ETransitionActionType::Animation:\n    {\n        item->AniData->bPlaying = Buffer->ReadBool();\n        item->AniData->Frame = Buffer->ReadInt();\n        break;\n    }\n\n    case ETransitionActionType::Visible:\n        item->VisibleData = Buffer->ReadBool();\n        break;\n\n    case ETransitionActionType::Sound:\n    {\n        item->SoundData->URL = Buffer->ReadS();\n        item->SoundData->Volume = Buffer->ReadFloat();\n        break;\n    }\n\n    case ETransitionActionType::Transition:\n    {\n        item->TransData->Name = Buffer->ReadS();\n        item->TransData->PlayTimes = Buffer->ReadInt();\n        break;\n    }\n\n    case ETransitionActionType::Shake:\n    {\n        item->ShakeData->Amplitude = Buffer->ReadFloat();\n        item->ShakeData->Duration = Buffer->ReadFloat();\n        break;\n    }\n\n    case ETransitionActionType::ColorFilter:\n    {\n        Value->f1 = Buffer->ReadFloat();\n        Value->f2 = Buffer->ReadFloat();\n        Value->f3 = Buffer->ReadFloat();\n        Value->f4 = Buffer->ReadFloat();\n        break;\n    }\n\n    case ETransitionActionType::Text:\n    case ETransitionActionType::Icon:\n        item->TextData = Buffer->ReadS();\n        break;\n\n    default:\n        break;\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/TranslationHelper.cpp",
    "content": "#include \"UI/TranslationHelper.h\"\n\nTMap<FString, TMap<FString, FString>> FTranslationHelper::Strings;\n\nvoid FTranslationHelper::LoadFromXML(const FString XmlString)\n{\n\n}\n\nvoid FTranslationHelper::TranslateComponent(const TSharedPtr<FPackageItem>& Item)\n{\n\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/UIConfig.cpp",
    "content": "#include \"UI/UIConfig.h\"\n#include \"FairyApplication.h\"\n\nFUIConfig FUIConfig::Config;\n\nFUIConfig::FUIConfig() :\n    ButtonSoundVolumeScale(1),\n    DefaultScrollStep(25),\n    DefaultScrollDecelerationRate(0.967f),\n    DefaultScrollTouchEffect(true),\n    DefaultScrollBounceEffect(true),\n    DefaultScrollBarDisplay(EScrollBarDisplayType::Default),\n    TouchDragSensitivity(10),\n    ClickDragSensitivity(2),\n    TouchScrollSensitivity(20),\n    DefaultComboBoxVisibleItemCount(10),\n    ModalLayerColor(0, 0, 0, 120),\n    BringWindowToFrontOnClick(true)\n{\n}"
  },
  {
    "path": "Source/FairyGUI/Private/UI/UIObjectFactory.cpp",
    "content": "#include \"UI/UIObjectFactory.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/PackageItem.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/GImage.h\"\n#include \"UI/GMovieClip.h\"\n#include \"UI/GTextField.h\"\n#include \"UI/GRichTextField.h\"\n#include \"UI/GTextInput.h\"\n#include \"UI/GGraph.h\"\n#include \"UI/GLoader.h\"\n#include \"UI/GLoader3D.h\"\n#include \"UI/GGroup.h\"\n#include \"UI/GLabel.h\"\n#include \"UI/GButton.h\"\n#include \"UI/GComboBox.h\"\n#include \"UI/GProgressBar.h\"\n#include \"UI/GSlider.h\"\n#include \"UI/GScrollBar.h\"\n#include \"UI/GList.h\"\n#include \"UI/GTree.h\"\n\nTMap<FString, FGComponentCreator> FUIObjectFactory::PackageItemExtensions;\nTSubclassOf<UGLoader> FUIObjectFactory::LoaderExtension;\n\nvoid FUIObjectFactory::SetExtension(const FString& URL, FGComponentCreator Creator)\n{\n    if (URL.IsEmpty())\n    {\n        UE_LOG(LogFairyGUI, Warning, TEXT(\"Invaild url: %s\"), *URL);\n        return;\n    }\n\n    TSharedPtr<FPackageItem> PackageItem = UUIPackage::GetItemByURL(URL);\n    if (PackageItem.IsValid())\n        PackageItem->ExtensionCreator = Creator;\n\n    PackageItemExtensions.Add(URL, Creator);\n}\n\nvoid FUIObjectFactory::SetExtension(const FString& URL, TSubclassOf<UGComponent> ClassType)\n{\n    SetExtension(URL, FGComponentCreator::CreateLambda([ClassType](UObject* Outer) {\n        return ::NewObject<UGComponent>(Outer, ClassType);\n    }));\n}\n\nUGObject* FUIObjectFactory::NewObject(const TSharedPtr<FPackageItem>& PackageItem, UObject* Outer)\n{\n    UGObject* obj = nullptr;\n    if (PackageItem->ExtensionCreator.IsBound())\n        obj = PackageItem->ExtensionCreator.Execute(Outer);\n    else\n        obj = NewObject(PackageItem->ObjectType, Outer);\n    if (obj != nullptr)\n        obj->PackageItem = PackageItem;\n\n    return obj;\n}\n\nUGObject* FUIObjectFactory::NewObject(EObjectType Type, UObject* Outer)\n{\n    switch (Type)\n    {\n    case EObjectType::Image:\n        return ::NewObject<UGImage>(Outer);\n\n    case EObjectType::MovieClip:\n        return ::NewObject<UGMovieClip>(Outer);\n\n    case EObjectType::Component:\n        return ::NewObject<UGComponent>(Outer);\n\n    case EObjectType::Text:\n        return ::NewObject<UGTextField>(Outer);\n\n    case EObjectType::RichText:\n        return ::NewObject<UGRichTextField>(Outer);\n\n    case EObjectType::InputText:\n        return ::NewObject<UGTextInput>(Outer);\n\n    case EObjectType::Group:\n        return ::NewObject<UGGroup>(Outer);\n\n    case EObjectType::List:\n        return ::NewObject<UGList>(Outer);\n\n    case EObjectType::Graph:\n        return ::NewObject<UGGraph>(Outer);\n\n    case EObjectType::Loader:\n        if (LoaderExtension != nullptr)\n            return ::NewObject<UGLoader>(Outer, LoaderExtension);\n        else\n            return ::NewObject<UGLoader>(Outer);\n\n    case EObjectType::Button:\n        return ::NewObject<UGButton>(Outer);\n\n    case EObjectType::Label:\n        return ::NewObject<UGLabel>(Outer);\n\n    case EObjectType::ProgressBar:\n        return ::NewObject<UGProgressBar>(Outer);\n\n    case EObjectType::Slider:\n        return ::NewObject<UGSlider>(Outer);\n\n    case EObjectType::ScrollBar:\n        return ::NewObject<UGScrollBar>(Outer);\n\n    case EObjectType::ComboBox:\n        return ::NewObject<UGComboBox>(Outer);\n\n    case EObjectType::Tree:\n        return ::NewObject<UGTree>(Outer);\n\n    case EObjectType::Loader3D:\n        return ::NewObject<UGLoader3D>(Outer);\n\n    default:\n        return nullptr;\n    }\n}\n\nvoid FUIObjectFactory::ResolvePackageItemExtension(const TSharedPtr<FPackageItem>& PackageItem)\n{\n    auto it = PackageItemExtensions.Find(\"ui://\" + PackageItem->Owner->GetID() + PackageItem->ID);\n    if (it != nullptr)\n    {\n        PackageItem->ExtensionCreator = *it;\n        return;\n    }\n    it = PackageItemExtensions.Find(\"ui://\" + PackageItem->Owner->GetName() + \"/\" + PackageItem->Name);\n    if (it != nullptr)\n    {\n        PackageItem->ExtensionCreator = *it;\n        return;\n    }\n    PackageItem->ExtensionCreator = nullptr;\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UI/UIPackage.cpp",
    "content": "#include \"UI/UIPackage.h\"\n#include \"Sound/SoundBase.h\"\n#include \"UIPackageAsset.h\"\n#include \"UI/PackageItem.h\"\n#include \"UI/GObject.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/SMovieClip.h\"\n#include \"Widgets/BitmapFont.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"UI/UIObjectFactory.h\"\n\nint32 UUIPackage::Constructing = 0;\n\nstruct FAtlasSprite\n{\n    FAtlasSprite() :\n        Rect(ForceInit),\n        OriginalSize(ForceInit),\n        Offset(ForceInit),\n        bRotated(false)\n    {\n    }\n    TSharedPtr<FPackageItem> Atlas;\n    FBox2D Rect;\n    FVector2D OriginalSize;\n    FVector2D Offset;\n    bool bRotated;\n};\n\nconst FString& UUIPackage::GetBranch()\n{\n    return UUIPackageStatic::Get().Branch;\n}\n\nvoid UUIPackage::SetBranch(const FString& InBranch)\n{\n    UUIPackageStatic::Get().Branch = InBranch;\n    bool empty = InBranch.IsEmpty();\n    for (auto& it : UUIPackageStatic::Get().PackageInstByID)\n    {\n        UUIPackage*& Pkg = it.Value;\n        if (empty)\n            Pkg->BranchIndex = -1;\n        else if (Pkg->Branches.Num() > 0)\n            Pkg->BranchIndex = Pkg->Branches.Find(InBranch);\n    }\n}\n\nFString UUIPackage::GetVar(const FString& VarKey)\n{\n    FString* Value = UUIPackageStatic::Get().Vars.Find(VarKey);\n    if (Value != nullptr)\n        return *Value;\n    else\n        return G_EMPTY_STRING;\n}\n\nvoid UUIPackage::SetVar(const FString& VarKey, const FString& VarValue)\n{\n    UUIPackageStatic::Get().Vars.Add(VarKey, VarValue);\n}\n\nUUIPackage* UUIPackage::AddPackage(const TCHAR* InAssetPath, UObject* WorldContextObject)\n{\n    UUIPackageAsset* PackageAsset = Cast<UUIPackageAsset>(StaticLoadObject(UUIPackageAsset::StaticClass(), nullptr, InAssetPath));\n    verifyf(PackageAsset != nullptr, TEXT(\"Asset not found %s\"), InAssetPath);\n\n    return AddPackage(PackageAsset, WorldContextObject);\n}\n\nUUIPackage* UUIPackage::AddPackage(UUIPackageAsset* InAsset, UObject* WorldContextObject)\n{\n    verifyf(WorldContextObject != nullptr, TEXT(\"Null WorldContextObject?\"));\n\n    UWorld* World = WorldContextObject->GetWorld();\n    verifyf(World != nullptr, TEXT(\"Null World?\"));\n    verifyf(World->IsGameWorld(), TEXT(\"Not a Game World?\"));\n\n    UUIPackage* Pkg = UUIPackageStatic::Get().PackageInstByID.FindRef(InAsset->GetPathName());\n    if (Pkg != nullptr)\n    {\n        if (Pkg->RefWorlds.Contains(World->GetUniqueID()))\n        {\n            UE_LOG(LogFairyGUI, Warning, TEXT(\"Package already addedd\"));\n        }\n        else\n            Pkg->RefWorlds.Add(World->GetUniqueID());\n        return Pkg;\n    }\n\n    FByteBuffer Buffer(InAsset->Data.GetData(), 0, InAsset->Data.Num(), false);\n\n    Pkg = NewObject<UUIPackage>();\n    Pkg->RefWorlds.Add(World->GetUniqueID());\n    Pkg->Asset = InAsset;\n    Pkg->AssetPath = InAsset->GetPathName();\n    Pkg->Load(&Buffer);\n\n    UUIPackageStatic::Get().PackageList.Add(Pkg);\n    UUIPackageStatic::Get().PackageInstByID.Add(Pkg->ID, Pkg);\n    UUIPackageStatic::Get().PackageInstByID.Add(Pkg->AssetPath, Pkg);\n    UUIPackageStatic::Get().PackageInstByName.Add(Pkg->Name, Pkg);\n\n    return Pkg;\n}\n\nvoid UUIPackage::RemovePackage(const FString& IDOrName, UObject* WorldContextObject)\n{\n    verifyf(WorldContextObject != nullptr, TEXT(\"Null WorldContextObject?\"));\n\n    UUIPackage* Pkg = GetPackageByName(IDOrName);\n    if (Pkg == nullptr)\n        Pkg = GetPackageByID(IDOrName);\n\n    if (Pkg != nullptr)\n    {\n        UWorld* World = WorldContextObject->GetWorld();\n        verifyf(World != nullptr, TEXT(\"Null World?\"));\n        verifyf(World->IsGameWorld(), TEXT(\"Not a Game World?\"));\n        Pkg->RefWorlds.Remove(World->GetUniqueID());\n\n        if (Pkg->RefWorlds.Num() > 0)\n            return;\n\n        UUIPackageStatic::Get().PackageList.Remove(Pkg);\n        UUIPackageStatic::Get().PackageInstByID.Remove(Pkg->ID);\n        UUIPackageStatic::Get().PackageInstByID.Remove(Pkg->AssetPath);\n        UUIPackageStatic::Get().PackageInstByName.Remove(Pkg->Name);\n    }\n    else\n        UE_LOG(LogFairyGUI, Error, TEXT(\"invalid package name or id: %s\"), *IDOrName);\n}\n\nvoid UUIPackage::RemoveAllPackages()\n{\n    UUIPackageStatic::Get().PackageList.Reset();\n    UUIPackageStatic::Get().PackageInstByID.Reset();\n    UUIPackageStatic::Get().PackageInstByName.Reset();\n}\n\nUUIPackage* UUIPackage::GetPackageByID(const FString& PackageID)\n{\n    auto it = UUIPackageStatic::Get().PackageInstByID.Find(PackageID);\n    if (it != nullptr)\n        return *it;\n    else\n        return nullptr;\n}\n\nUUIPackage* UUIPackage::GetPackageByName(const FString& PackageName)\n{\n    auto it = UUIPackageStatic::Get().PackageInstByName.Find(PackageName);\n    if (it != nullptr)\n        return *it;\n    else\n        return nullptr;\n}\n\nUGObject* UUIPackage::CreateObject(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject, TSubclassOf<UGObject> ClassType)\n{\n    UUIPackage* pkg = UUIPackage::GetPackageByName(PackageName);\n    if (pkg)\n        return pkg->CreateObject(ResourceName, WorldContextObject);\n    else\n        return nullptr;\n}\n\nUGObject* UUIPackage::CreateObjectFromURL(const FString& URL, UObject* WorldContextObject, TSubclassOf<UGObject> ClassType)\n{\n    TSharedPtr<FPackageItem> pii = UUIPackage::GetItemByURL(URL);\n    if (pii.IsValid())\n        return pii->Owner->CreateObject(pii, WorldContextObject);\n    else\n        return nullptr;\n}\n\nFString UUIPackage::GetItemURL(const FString& PackageName, const FString& ResourceName)\n{\n    UUIPackage* pkg = GetPackageByName(PackageName);\n    if (pkg != nullptr)\n    {\n        TSharedPtr<FPackageItem> pii = pkg->GetItemByName(ResourceName);\n        if (pii.IsValid())\n            return \"ui://\" + pkg->GetID() + pii->ID;\n    }\n    return \"\";\n}\n\nTSharedPtr<FPackageItem> UUIPackage::GetItemByURL(const FString& URL)\n{\n    if (URL.IsEmpty())\n        return nullptr;\n\n    int32 pos1;\n    if (!URL.FindChar('/', pos1))\n        return nullptr;\n\n    int32 pos2 = URL.Find(\"/\", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1 + 2);\n    if (pos2 == -1) {\n        if (URL.Len() > 13)\n        {\n            FString pkgId = URL.Mid(5, 8);\n            UUIPackage* pkg = GetPackageByID(pkgId);\n            if (pkg != nullptr)\n            {\n                FString srcId = URL.Mid(13);\n                return pkg->GetItem(srcId);\n            }\n        }\n    }\n    else\n    {\n        FString pkgName = URL.Mid(pos1 + 2, pos2 - pos1 - 2);\n        UUIPackage* pkg = GetPackageByName(pkgName);\n        if (pkg != nullptr)\n        {\n            FString srcName = URL.Mid(pos2 + 1);\n            return pkg->GetItemByName(srcName);\n        }\n    }\n\n    return nullptr;\n}\n\nFString UUIPackage::NormalizeURL(const FString& URL)\n{\n    if (URL.IsEmpty())\n        return URL;\n\n    int32 pos1;\n    if (!URL.FindChar('/', pos1))\n        return URL;\n\n    int32 pos2 = URL.Find(\"/\", ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1 + 2);\n    if (pos2 == -1)\n        return URL;\n    else\n    {\n        FString pkgName = URL.Mid(pos1 + 2, pos2 - pos1 - 2);\n        FString srcName = URL.Mid(pos2 + 1);\n        return GetItemURL(pkgName, srcName);\n    }\n}\n\nUUIPackage::UUIPackage()\n{\n\n}\n\nUUIPackage::~UUIPackage()\n{\n    for (auto& it : Sprites)\n        delete it.Value;\n}\n\nTSharedPtr<FPackageItem> UUIPackage::GetItem(const FString& ItemID) const\n{\n    auto it = ItemsByID.Find(ItemID);\n    if (it != nullptr)\n        return *it;\n    else\n        return nullptr;\n}\n\nTSharedPtr<FPackageItem> UUIPackage::GetItemByName(const FString& ResourceName)\n{\n    auto it = ItemsByName.Find(ResourceName);\n    if (it != nullptr)\n        return *it;\n    else\n        return nullptr;\n}\n\nUGObject* UUIPackage::CreateObject(const FString& ResourceName, UObject* WorldContextObject)\n{\n    TSharedPtr<FPackageItem> item = GetItemByName(ResourceName);\n    verifyf(item.IsValid(), TEXT(\"FairyGUI: resource not found - %s in  %s\"), *ResourceName, *Name);\n\n    return CreateObject(item, WorldContextObject);\n}\n\nUGObject* UUIPackage::CreateObject(const TSharedPtr<FPackageItem>& Item, UObject* WorldContextObject)\n{\n    UGObject* g = FUIObjectFactory::NewObject(Item, WorldContextObject);\n    if (g == nullptr)\n        return nullptr;\n\n    Constructing++;\n    g->ConstructFromResource();\n    Constructing--;\n    return g;\n}\n\nvoid UUIPackage::RegisterFont(const FString& FontFace, UObject* Font)\n{\n    UUIPackageStatic::Get().Fonts.Add(FontFace, Font);\n}\n\nvoid UUIPackage::Load(FByteBuffer* Buffer)\n{\n    if (Buffer->ReadUint() != 0x46475549)\n    {\n        UE_LOG(LogFairyGUI, Error, TEXT(\"not valid package format in %d '%s'\"), Buffer->ReadUint(), *AssetPath);\n        return;\n    }\n\n    Buffer->Version = Buffer->ReadInt();\n    bool ver2 = Buffer->Version >= 2;\n    Buffer->ReadBool(); //compressed\n    ID = Buffer->ReadString();\n    Name = Buffer->ReadString();\n    Buffer->Skip(20);\n    int32 indexTablePos = Buffer->GetPos();\n    int32 cnt;\n\n    Buffer->Seek(indexTablePos, 4);\n\n    cnt = Buffer->ReadInt();\n    TArray<FString>* StringTable = new TArray<FString>();\n    StringTable->SetNum(cnt, true);\n    for (int32 i = 0; i < cnt; i++)\n    {\n        (*StringTable)[i] = Buffer->ReadString();\n    }\n    Buffer->StringTable = MakeShareable(StringTable);\n\n    Buffer->Seek(indexTablePos, 0);\n    cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        TMap<FString, FString> info;\n        info.Add(\"id\", Buffer->ReadS());\n        info.Add(\"name\", Buffer->ReadS());\n\n        Dependencies.Push(info);\n    }\n\n    bool branchIncluded = false;\n    if (ver2)\n    {\n        cnt = Buffer->ReadShort();\n        if (cnt > 0)\n        {\n            Buffer->ReadSArray(Branches, cnt);\n            if (!UUIPackageStatic::Get().Branch.IsEmpty())\n                BranchIndex = Branches.Find(UUIPackageStatic::Get().Branch);\n        }\n\n        branchIncluded = cnt > 0;\n    }\n\n    Buffer->Seek(indexTablePos, 1);\n\n    FString path = FPaths::GetPath(AssetPath);\n    FString fileName = FPaths::GetBaseFilename(AssetPath);\n\n    cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        int32 nextPos = Buffer->ReadInt();\n        nextPos += Buffer->GetPos();\n\n        TSharedPtr<FPackageItem> pii = MakeShared<FPackageItem>();\n        pii->Owner = this;\n        pii->Type = (EPackageItemType)Buffer->ReadByte();\n        pii->ID = Buffer->ReadS();\n        pii->Name = Buffer->ReadS();\n        Buffer->Skip(2); //path\n        pii->File = Buffer->ReadS();\n        Buffer->ReadBool(); //exported\n        pii->Size.X = Buffer->ReadInt();\n        pii->Size.Y = Buffer->ReadInt();\n\n        switch (pii->Type)\n        {\n        case EPackageItemType::Image:\n        {\n            pii->ObjectType = EObjectType::Image;\n            int32 scaleOption = Buffer->ReadByte();\n            if (scaleOption == 1)\n            {\n                FBox2D scale9Grid(ForceInit);\n                scale9Grid.Min.X = Buffer->ReadInt();\n                scale9Grid.Min.Y = Buffer->ReadInt();\n                scale9Grid.Max.X = scale9Grid.Min.X + Buffer->ReadInt();\n                scale9Grid.Max.Y = scale9Grid.Min.Y + Buffer->ReadInt();\n                pii->Scale9Grid = scale9Grid;\n                pii->TileGridIndice = Buffer->ReadInt();\n            }\n            else if (scaleOption == 2)\n                pii->bScaleByTile = true;\n\n            Buffer->ReadBool(); //smoothing\n            break;\n        }\n\n        case EPackageItemType::MovieClip:\n        {\n            Buffer->ReadBool(); //smoothing\n            pii->ObjectType = EObjectType::MovieClip;\n            pii->RawData = Buffer->ReadBuffer(false);\n            break;\n        }\n\n        case EPackageItemType::Font:\n        {\n            pii->RawData = Buffer->ReadBuffer(false);\n            break;\n        }\n\n        case EPackageItemType::Component:\n        {\n            int32 extension = Buffer->ReadByte();\n            if (extension > 0)\n                pii->ObjectType = (EObjectType)extension;\n            else\n                pii->ObjectType = EObjectType::Component;\n            pii->RawData = Buffer->ReadBuffer(false);\n\n            FUIObjectFactory::ResolvePackageItemExtension(pii);\n            break;\n        }\n\n        case EPackageItemType::Atlas:\n        case EPackageItemType::Sound:\n        case EPackageItemType::Misc:\n        {\n            FString file = fileName + \"_\" + FPaths::GetBaseFilename(pii->File);\n            pii->File = path + \"/\" + file + \".\" + file;\n            break;\n        }\n\n        case EPackageItemType::Spine:\n        case EPackageItemType::DragonBones:\n        {\n            pii->File = path + pii->File;\n            break;\n        }\n\n        default:\n            break;\n        }\n\n        if (ver2)\n        {\n            FString str = Buffer->ReadS(); //branch\n            if (!str.IsEmpty())\n                pii->Name = str + \"/\" + pii->Name;\n\n            int32 branchCnt = Buffer->ReadUbyte();\n            if (branchCnt > 0)\n            {\n                if (branchIncluded)\n                {\n                    pii->Branches.Emplace();\n                    Buffer->ReadSArray(pii->Branches.GetValue(), branchCnt);\n                }\n                else\n                    ItemsByID.Add(Buffer->ReadS(), pii);\n            }\n\n            int32 highResCnt = Buffer->ReadUbyte();\n            if (highResCnt > 0)\n            {\n                pii->HighResolution.Emplace();\n                Buffer->ReadSArray(pii->HighResolution.GetValue(), highResCnt);\n            }\n        }\n\n        Items.Push(pii);\n        ItemsByID.Add(pii->ID, pii);\n        if (!pii->Name.IsEmpty())\n            ItemsByName.Add(pii->Name, pii);\n\n        Buffer->SetPos(nextPos);\n    }\n\n    Buffer->Seek(indexTablePos, 2);\n\n    cnt = Buffer->ReadShort();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        const FString& itemId = Buffer->ReadS();\n        const TSharedPtr<FPackageItem>& pii = ItemsByID[Buffer->ReadS()];\n\n        FAtlasSprite* sprite = new FAtlasSprite();\n        sprite->Atlas = pii;\n        sprite->Rect.Min.X = Buffer->ReadInt();\n        sprite->Rect.Min.Y = Buffer->ReadInt();\n        sprite->Rect.Max.X = sprite->Rect.Min.X + Buffer->ReadInt();\n        sprite->Rect.Max.Y = sprite->Rect.Min.Y + Buffer->ReadInt();\n        sprite->bRotated = Buffer->ReadBool();\n        if (ver2 && Buffer->ReadBool())\n        {\n            sprite->Offset.X = Buffer->ReadInt();\n            sprite->Offset.Y = Buffer->ReadInt();\n            sprite->OriginalSize.X = Buffer->ReadInt();\n            sprite->OriginalSize.Y = Buffer->ReadInt();\n        }\n        else if (sprite->bRotated)\n        {\n            sprite->Offset.Set(0, 0);\n            sprite->OriginalSize.X = sprite->Rect.GetSize().Y;\n            sprite->OriginalSize.Y = sprite->Rect.GetSize().X;\n        }\n        else\n        {\n            sprite->Offset.Set(0, 0);\n            sprite->OriginalSize = sprite->Rect.GetSize();\n        }\n        Sprites.Add(itemId, sprite);\n\n        Buffer->SetPos(nextPos);\n    }\n\n    if (Buffer->Seek(indexTablePos, 3))\n    {\n        cnt = Buffer->ReadShort();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            int32 nextPos = Buffer->ReadInt();\n            nextPos += Buffer->GetPos();\n\n            TSharedPtr<FPackageItem> pii = ItemsByID.FindRef(Buffer->ReadS());\n            if (pii.IsValid() && pii->Type == EPackageItemType::Image)\n            {\n                pii->PixelHitTestData = MakeShareable(new FPixelHitTestData());\n                pii->PixelHitTestData->Load(Buffer);\n            }\n\n            Buffer->SetPos(nextPos);\n        }\n    }\n}\n\nvoid* UUIPackage::GetItemAsset(const TSharedPtr<FPackageItem>& Item)\n{\n    switch (Item->Type)\n    {\n    case EPackageItemType::Image:\n        if (Item->Texture == nullptr)\n            LoadImage(Item);\n        return Item->Texture;\n\n    case EPackageItemType::Atlas:\n        if (Item->Texture == nullptr)\n            LoadAtlas(Item);\n        return Item->Texture;\n\n    case EPackageItemType::Font:\n        if (Item->BitmapFont == nullptr)\n            LoadFont(Item);\n        return Item->BitmapFont.Get();\n\n    case EPackageItemType::MovieClip:\n        if (!Item->MovieClipData.IsValid())\n            LoadMovieClip(Item);\n        return Item->MovieClipData.Get();\n\n    case EPackageItemType::Sound:\n        if (!Item->Sound.IsValid())\n            LoadSound(Item);\n        return Item->Sound.Get();\n\n    default:\n        return nullptr;\n    }\n}\n\nvoid UUIPackage::LoadAtlas(const TSharedPtr<FPackageItem>& Item)\n{\n    UObject* Texture = StaticLoadObject(UTexture2D::StaticClass(), this, *Item->File);\n    Item->Texture = NewObject<UNTexture>(this);\n    Item->Texture->Init(Cast<UTexture2D>(Texture));\n}\n\nvoid UUIPackage::LoadImage(const TSharedPtr<FPackageItem>& Item)\n{\n    FAtlasSprite* sprite = Sprites.FindRef(Item->ID);\n    if (sprite != nullptr)\n    {\n        UNTexture* atlas = (UNTexture*)GetItemAsset(sprite->Atlas);\n        if (atlas->GetSize() == sprite->Rect.GetSize())\n            Item->Texture = atlas;\n        else\n        {\n            Item->Texture = NewObject<UNTexture>(this);\n            Item->Texture->Init(atlas, sprite->Rect, sprite->bRotated, sprite->OriginalSize, sprite->Offset);\n        }\n    }\n}\n\nvoid UUIPackage::LoadMovieClip(const TSharedPtr<FPackageItem>& Item)\n{\n    TSharedPtr<FMovieClipData> Data = MakeShared<FMovieClipData>();\n    Item->MovieClipData = Data;\n    FByteBuffer* Buffer = Item->RawData.Get();\n\n    Buffer->Seek(0, 0);\n\n    Data->Interval = Buffer->ReadInt() / 1000.0f;\n    Data->bSwing = Buffer->ReadBool();\n    Data->RepeatDelay = Buffer->ReadInt() / 1000.0f;\n\n    Buffer->Seek(0, 1);\n\n    int32 frameCount = Buffer->ReadShort();\n    Data->Frames.Reserve(frameCount);\n\n    FAtlasSprite* sprite;\n\n    for (int32 i = 0; i < frameCount; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        FMovieClipData::Frame Frame;\n\n        FBox2D FrameRect;\n        FrameRect.Min.X = Buffer->ReadInt();\n        FrameRect.Min.Y = Buffer->ReadInt();\n        FrameRect.Max.X = FrameRect.Min.X + Buffer->ReadInt();\n        FrameRect.Max.Y = FrameRect.Min.Y + Buffer->ReadInt();\n        Frame.AddDelay = Buffer->ReadInt() / 1000.0f;\n        const FString& spriteId = Buffer->ReadS();\n\n        if (!spriteId.IsEmpty() && (sprite = Sprites.FindRef(spriteId)) != nullptr)\n        {\n            Frame.Texture = NewObject<UNTexture>(this);\n            Frame.Texture->Init((UNTexture*)GetItemAsset(sprite->Atlas), sprite->Rect, sprite->bRotated, Item->Size, FrameRect.Min);\n        }\n\n        Data->Frames.Add(MoveTemp(Frame));\n\n        Buffer->SetPos(nextPos);\n    }\n\n    Item->RawData.Reset();\n}\n\nvoid UUIPackage::LoadFont(const TSharedPtr<FPackageItem>& Item)\n{\n    TSharedPtr<FBitmapFont> BitmapFont = MakeShared<FBitmapFont>();\n    Item->BitmapFont = BitmapFont;\n    FByteBuffer* Buffer = Item->RawData.Get();\n\n    Buffer->Seek(0, 0);\n\n    bool bTTF = Buffer->ReadBool();\n    BitmapFont->bCanTint = Buffer->ReadBool();\n    BitmapFont->bResizable = Buffer->ReadBool();\n    BitmapFont->bHasChannel = Buffer->ReadBool(); //hasChannel\n    BitmapFont->FontSize = Buffer->ReadInt();\n    int32 XAdvance = Buffer->ReadInt();\n    int32 LineHeight = Buffer->ReadInt();\n\n    FVector2D GlyphTexCoords(0, 0);\n    FVector2D GlyphOffset(0, 0);\n    FVector2D GlyphSize(0, 0);\n\n    const FAtlasSprite* MainSprite = nullptr;\n    if (bTTF && (MainSprite = Sprites.FindRef(Item->ID)) != nullptr)\n        BitmapFont->Texture = (UNTexture*)GetItemAsset(MainSprite->Atlas);\n\n    Buffer->Seek(0, 1);\n\n    int32 cnt = Buffer->ReadInt();\n    for (int32 i = 0; i < cnt; i++)\n    {\n        int32 nextPos = Buffer->ReadShort();\n        nextPos += Buffer->GetPos();\n\n        FBitmapFont::FGlyph Glyph;\n\n        TCHAR ch = Buffer->ReadUshort();\n        const FString& img = Buffer->ReadS();\n        GlyphTexCoords.X = Buffer->ReadInt();\n        GlyphTexCoords.Y = Buffer->ReadInt();\n        GlyphOffset.X = Buffer->ReadInt();\n        GlyphOffset.Y = Buffer->ReadInt();\n        GlyphSize.X = Buffer->ReadInt();\n        GlyphSize.Y = Buffer->ReadInt();\n        Glyph.XAdvance = Buffer->ReadInt();\n        Glyph.Channel = Buffer->ReadByte();\n\n        if (bTTF)\n        {\n            FVector2D TexCoords = MainSprite->Rect.Min + GlyphTexCoords;\n            Glyph.UVRect = FBox2D(TexCoords / BitmapFont->Texture->GetSize(), (TexCoords + GlyphSize) / BitmapFont->Texture->GetSize());\n            Glyph.Offset = GlyphOffset;\n            Glyph.Size = GlyphSize;\n            Glyph.LineHeight = LineHeight;\n        }\n        else\n        {\n            TSharedPtr<FPackageItem> CharImg = GetItem(img);\n            if (CharImg.IsValid())\n            {\n                CharImg = CharImg->GetBranch();\n                GlyphSize = CharImg->Size;\n                CharImg = CharImg->GetHighResolution();\n                GetItemAsset(CharImg);\n                Glyph.UVRect = CharImg->Texture->UVRect;\n\n                FVector2D TexScale = GlyphSize / CharImg->Size;\n\n                Glyph.Offset = GlyphOffset + CharImg->Texture->Offset * TexScale;\n                Glyph.Size = CharImg->Size * TexScale;\n\n                if (BitmapFont->Texture == nullptr)\n                    BitmapFont->Texture = CharImg->Texture->Root;\n            }\n\n            if (BitmapFont->FontSize == 0)\n                BitmapFont->FontSize = (int32)GlyphSize.Y;\n\n            if (Glyph.XAdvance == 0)\n            {\n                if (XAdvance == 0)\n                    Glyph.XAdvance = GlyphOffset.X + GlyphSize.X;\n                else\n                    Glyph.XAdvance = XAdvance;\n            }\n\n            Glyph.LineHeight = GlyphOffset.Y < 0 ? GlyphSize.Y : (GlyphOffset.Y + GlyphSize.Y);\n            if (Glyph.LineHeight < BitmapFont->FontSize)\n                Glyph.LineHeight = BitmapFont->FontSize;\n        }\n\n        BitmapFont->Glyphs.Add(ch, Glyph);\n        Buffer->SetPos(nextPos);\n    }\n\n    Item->RawData.Reset();\n}\n\nvoid UUIPackage::LoadSound(const TSharedPtr<FPackageItem>& Item)\n{\n    TSharedPtr<FSlateSound> Sound = MakeShared<FSlateSound>();\n    Item->Sound = Sound;\n\n    UObject* SoundObject = StaticLoadObject(USoundBase::StaticClass(), this, *Item->File);\n    Sound->SetResourceObject(SoundObject);\n}\n\nUUIPackageStatic* UUIPackageStatic::Singleton = nullptr;\n\nUUIPackageStatic& UUIPackageStatic::Get()\n{\n    if (Singleton == nullptr)\n    {\n        Singleton = NewObject<UUIPackageStatic>();\n        Singleton->AddToRoot();\n    }\n    return *Singleton;\n}\n\nvoid UUIPackageStatic::Destroy()\n{\n    if (Singleton != nullptr)\n    {\n        Singleton->RemoveFromRoot();\n        Singleton = nullptr;\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/UIPackageAsset.cpp",
    "content": "#include \"UIPackageAsset.h\"\n#include \"EditorFramework/AssetImportData.h\"\n\n#if WITH_EDITORONLY_DATA\nvoid UUIPackageAsset::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const\n{\n    if (AssetImportData)\n    {\n        OutTags.Add(FAssetRegistryTag(SourceFileTagName(),\n            AssetImportData->GetSourceData().ToJson(),\n            FAssetRegistryTag::TT_Hidden));\n#if WITH_EDITOR\n        AssetImportData->AppendAssetRegistryTags(OutTags);\n#endif\n    }\n\n    Super::GetAssetRegistryTags(OutTags);\n}\n#endif"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/ByteBuffer.cpp",
    "content": "#include \"Utils/ByteBuffer.h\"\n\nFByteBuffer::FByteBuffer(const uint8* InBuffer, int32 InOffset, int32 InLen, bool bInTransferOwnerShip)\n    : bLittleEndian(false),\n    Version(0),\n    Buffer(InBuffer),\n    Offset(InOffset),\n    Length(InLen),\n    Position(0),\n    bOwnsBuffer(bInTransferOwnerShip)\n{\n}\n\nFByteBuffer::~FByteBuffer()\n{\n    if (bOwnsBuffer && Buffer != nullptr)\n        FMemory::Free((void *)Buffer);\n}\n\nint32 FByteBuffer::GetBytesAvailable() const\n{\n    return Length - Position;\n}\n\nint8 FByteBuffer::ReadByte()\n{\n    signed char val = Buffer[Offset + Position];\n    if (val > 127)\n        val = val - 255;\n    Position += 1;\n    return val;\n}\n\nuint8 FByteBuffer::ReadUbyte()\n{\n    unsigned char val = Buffer[Offset + Position];\n    Position += 1;\n    return val;\n}\n\nbool FByteBuffer::ReadBool()\n{\n    return ReadByte() == 1;\n}\n\nint16 FByteBuffer::ReadShort()\n{\n    int32 startIndex = Offset + Position;\n    Position += 2;\n    uint8* pbyte = (uint8*)(Buffer + startIndex);\n    if (bLittleEndian)\n        return (int16)((*pbyte) | (*(pbyte + 1) << 8));\n    else\n        return (int16)((*pbyte << 8) | (*(pbyte + 1)));\n}\n\nuint16 FByteBuffer::ReadUshort()\n{\n    return (uint16)ReadShort();\n}\n\nint32 FByteBuffer::ReadInt()\n{\n    int32 startIndex = Offset + Position;\n    Position += 4;\n    uint8* pbyte = (uint8*)(Buffer + startIndex);\n    if (bLittleEndian)\n        return (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24);\n    else\n        return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));\n}\n\nuint32 FByteBuffer::ReadUint()\n{\n    return (uint32)ReadInt();\n}\n\nfloat FByteBuffer::ReadFloat()\n{\n    int32 val = ReadInt();\n    return *(float*)&val;\n}\n\nFString FByteBuffer::ReadString()\n{\n    int32 len = ReadUshort();\n    return ReadString(len);\n}\n\nFString FByteBuffer::ReadString(int32 InLen)\n{\n    uint8* value = (uint8*)FMemory::Malloc(InLen + 1);\n\n    value[InLen] = '\\0';\n    FMemory::Memcpy(value, Buffer + Position, InLen);\n    Position += InLen;\n\n    FString str = UTF8_TO_TCHAR(value);\n    FMemory::Free(value);\n\n    return str;\n}\n\nconst FString& FByteBuffer::ReadS()\n{\n    uint16 index = ReadUshort();\n    if (index == 65534 || index == 65533)\n        return G_EMPTY_STRING;\n    else\n        return (*StringTable)[index];\n}\n\nbool FByteBuffer::ReadS(FString& OutString)\n{\n    uint16 index = ReadUshort();\n    if (index == 65534) //null\n        return false;\n    else if (index == 65533)\n    {\n        OutString.Reset();\n        return true;\n    }\n    else\n    {\n        OutString = (*StringTable)[index];\n        return true;\n    }\n}\n\nconst FString* FByteBuffer::ReadSP()\n{\n    uint16 index = ReadUshort();\n    if (index == 65534) //null\n        return nullptr;\n    else if (index == 65533)\n        return &G_EMPTY_STRING;\n    else\n        return &(*StringTable)[index];\n}\n\nvoid FByteBuffer::ReadSArray(TArray<FString>& OutArray, int32 InCount)\n{\n    for (int32 i = 0; i < InCount; i++)\n        OutArray.Push(ReadS());\n}\n\nvoid FByteBuffer::WriteS(const FString& InString)\n{\n    uint16 index = ReadUshort();\n    if (index != 65534 && index != 65533)\n        (*StringTable)[index] = InString;\n}\n\nFColor FByteBuffer::ReadColor()\n{\n    int32 startIndex = Offset + Position;\n    uint8 r = Buffer[startIndex];\n    uint8 g = Buffer[startIndex + 1];\n    uint8 b = Buffer[startIndex + 2];\n    uint8 a = Buffer[startIndex + 3];\n    Position += 4;\n\n    return FColor(r, g, b, a);\n}\n\nTSharedPtr<FByteBuffer> FByteBuffer::ReadBuffer(bool bCloneBuffer)\n{\n    int32 count = ReadInt();\n    FByteBuffer* ba;\n    if (bCloneBuffer)\n    {\n        uint8* p = (uint8*)FMemory::Malloc(count);\n        memcpy(p, Buffer + Position, count);\n        ba = new FByteBuffer(p, 0, count, true);\n    }\n    else\n        ba = new FByteBuffer(Buffer, Position, count, false);\n    ba->StringTable = StringTable;\n    ba->Version = Version;\n    Position += count;\n    return MakeShareable(ba);\n}\n\nbool FByteBuffer::Seek(int32 IndexTablePos, int32 BlockIndex)\n{\n    int32 tmp = Position;\n    Position = IndexTablePos;\n    int32 segCount = Buffer[Offset + Position++];\n    if (BlockIndex < segCount)\n    {\n        bool useShort = Buffer[Offset + Position++] == 1;\n        int32 newPos;\n        if (useShort)\n        {\n            Position += 2 * BlockIndex;\n            newPos = ReadShort();\n        }\n        else\n        {\n            Position += 4 * BlockIndex;\n            newPos = ReadInt();\n        }\n\n        if (newPos > 0)\n        {\n            Position = IndexTablePos + newPos;\n            return true;\n        }\n        else\n        {\n            Position = tmp;\n            return false;\n        }\n    }\n    else\n    {\n        Position = tmp;\n        return false;\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/HTMLElement.cpp",
    "content": "#include \"Utils/HTMLElement.h\"\n"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/HTMLParser.cpp",
    "content": "#include \"Utils/HTMLParser.h\"\n#include \"Utils/XMLIterator.h\"\n\nenum class SupportedTagNames {\n    INVALID, B, I, U, STRIKE, SUB, SUP, FONT, BR, IMG, A, INPUT, SELECT, P, UI, DIV, LI, HTML, BODY, HEAD, STYLE, SCRIPT, FORM\n};\n\nFHTMLParser FHTMLParser::DefaultParser;\nFHTMLParseOptions FHTMLParser::DefaultParseOptions;\n\nFHTMLParser::FHTMLParser()\n{\n}\n\nvoid FHTMLParser::Parse(const FString& InText, const FNTextFormat& InFormat, TArray<FHTMLElement>& OutElements, const FHTMLParseOptions& InParseOptions)\n{\n    ParseOptions = InParseOptions;\n    Elements = &OutElements;\n    TextFormatStack.Reset();\n    (FNTextFormat&)Format = InFormat;\n    Format.bColorChanged = false;\n    int32 skipText = 0;\n    bool ignoreWhiteSpace = ParseOptions.bIgnoreWhiteSpace;\n    bool skipNextCR = false;\n    FString text;\n\n    static const TMap<FString, SupportedTagNames> TagConstMap = {\n        { \"b\", SupportedTagNames::B },\n        { \"i\", SupportedTagNames::I },\n        { \"u\", SupportedTagNames::U },\n        { \"strike\", SupportedTagNames::STRIKE },\n        { \"sub\", SupportedTagNames::SUP },\n        { \"font\", SupportedTagNames::FONT },\n        { \"br\", SupportedTagNames::BR },\n        { \"img\", SupportedTagNames::IMG },\n        { \"a\", SupportedTagNames::A },\n        { \"input\", SupportedTagNames::INPUT },\n        { \"select\", SupportedTagNames::SELECT },\n        { \"p\", SupportedTagNames::P },\n        { \"ui\", SupportedTagNames::UI },\n        { \"div\", SupportedTagNames::DIV },\n        { \"li\", SupportedTagNames::LI },\n        { \"html\", SupportedTagNames::HTML },\n        { \"body\", SupportedTagNames::BODY },\n        { \"head\", SupportedTagNames::HEAD },\n        { \"style\", SupportedTagNames::STYLE },\n        { \"script\", SupportedTagNames::SCRIPT },\n        { \"form\", SupportedTagNames::FORM },\n    };\n\n    FXMLIterator XMLIterator;\n    XMLIterator.Begin(InText, true);\n    while (XMLIterator.NextTag())\n    {\n        if (skipText == 0)\n        {\n            text = XMLIterator.GetText(ignoreWhiteSpace);\n            if (text.Len() > 0)\n            {\n                if (skipNextCR && text[0] == '\\n')\n                    text = text.Mid(1);\n                AppendText(text);\n            }\n        }\n\n        skipNextCR = false;\n        switch (TagConstMap.FindRef(XMLIterator.TagName))\n        {\n        case SupportedTagNames::B:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n                Format.bBold = true;\n            }\n            else\n                PopTextFormat();\n            break;\n\n        case SupportedTagNames::I:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n                Format.bItalic = true;\n            }\n            else\n                PopTextFormat();\n            break;\n\n        case SupportedTagNames::U:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n                Format.bUnderline = true;\n            }\n            else\n                PopTextFormat();\n            break;\n\n        case SupportedTagNames::STRIKE:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n                //Format.strikethrough = true;\n            }\n            else\n                PopTextFormat();\n            break;\n\n        case SupportedTagNames::SUB:\n            break;\n\n        case SupportedTagNames::SUP:\n            break;\n\n        case SupportedTagNames::FONT:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n\n                XMLIterator.ParseAttributes();\n                Format.Size = XMLIterator.Attributes.GetInt(\"size\", Format.Size);\n                const FString& color = XMLIterator.Attributes.Get(\"color\");\n                if (color.Len() > 0)\n                {\n                    Format.Color = FColor::FromHex(color);\n                    Format.bColorChanged = true;\n                }\n            }\n            else if (XMLIterator.TagType == EXMLTagType::End)\n                PopTextFormat();\n            break;\n\n        case SupportedTagNames::BR:\n            AppendText(\"\\n\");\n            break;\n\n        case SupportedTagNames::IMG:\n            if (XMLIterator.TagType == EXMLTagType::Start || XMLIterator.TagType == EXMLTagType::Void)\n            {\n                XMLIterator.ParseAttributes();\n\n                FHTMLElement element;\n                element.Type = EHTMLElementType::Image;\n                element.Attributes.Append(XMLIterator.Attributes);\n                element.Name = element.Attributes.Get(\"name\");\n                element.Format.Align = Format.Align;\n                Elements->Add(MoveTemp(element));\n            }\n            break;\n\n        case SupportedTagNames::A:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n\n                Format.bUnderline = Format.bUnderline || ParseOptions.bLinkUnderline;\n                if (!Format.bColorChanged && ParseOptions.LinkColor.A != 0)\n                    Format.Color = ParseOptions.LinkColor;\n\n                FHTMLElement element;\n                element.Type = EHTMLElementType::Link;\n                XMLIterator.ParseAttributes();\n                element.Attributes.Append(XMLIterator.Attributes);\n                element.Name = element.Attributes.Get(\"name\");\n                element.Format.Align = Format.Align;\n                Elements->Add(MoveTemp(element));\n            }\n            else if (XMLIterator.TagType == EXMLTagType::End)\n            {\n                PopTextFormat();\n\n                FHTMLElement element;\n                element.Type = EHTMLElementType::LinkEnd;\n                Elements->Add(MoveTemp(element));\n            }\n            break;\n\n        case SupportedTagNames::INPUT:\n        {\n            FHTMLElement element;\n            element.Type = EHTMLElementType::Input;\n            XMLIterator.ParseAttributes();\n            element.Attributes.Append(XMLIterator.Attributes);\n            element.Name = element.Attributes.Get(\"name\");\n            element.Format = Format;\n            Elements->Add(element);\n        }\n        break;\n\n        case SupportedTagNames::SELECT:\n        {\n            if (XMLIterator.TagType == EXMLTagType::Start || XMLIterator.TagType == EXMLTagType::Void)\n            {\n                FHTMLElement element;\n                element.Type = EHTMLElementType::Select;\n                XMLIterator.ParseAttributes();\n                if (XMLIterator.TagType == EXMLTagType::Start)\n                {\n                    FString Items, Values;\n                    while (XMLIterator.NextTag())\n                    {\n                        if (XMLIterator.TagName == \"select\")\n                            break;\n\n                        if (XMLIterator.TagName == \"option\")\n                        {\n                            if (XMLIterator.TagType == EXMLTagType::Start || XMLIterator.TagType == EXMLTagType::Void)\n                            {\n                                if (!Values.IsEmpty())\n                                    Values.AppendChar(',');\n                                Values.Append(XMLIterator.Attributes.Get(\"value\"));\n                            }\n                            else\n                            {\n                                if (!Items.IsEmpty())\n                                    Items.AppendChar(',');\n                                Items.Append(XMLIterator.GetText());\n                            }\n                        }\n                    }\n                    element.Attributes.Add(\"items\", Items);\n                    element.Attributes.Add(\"values\", Values);\n                }\n                element.Name = element.Attributes.Get(\"name\");\n                element.Format = Format;\n                Elements->Add(element);\n            }\n        }\n        break;\n\n        case SupportedTagNames::P:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                PushTextFormat();\n                const FString& align = XMLIterator.Attributes.Get(\"align\");\n                if (align == \"center\")\n                    Format.Align = EAlignType::Center;\n                else if (align == \"right\")\n                    Format.Align = EAlignType::Right;\n\n                if (!IsNewLine())\n                    AppendText(\"\\n\");\n            }\n            else if (XMLIterator.TagType == EXMLTagType::End)\n            {\n                AppendText(\"\\n\");\n                skipNextCR = true;\n\n                PopTextFormat();\n            }\n            break;\n\n        case SupportedTagNames::UI:\n        case SupportedTagNames::DIV:\n        case SupportedTagNames::LI:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n            {\n                if (!IsNewLine())\n                    AppendText(\"\\n\");\n            }\n            else\n            {\n                AppendText(\"\\n\");\n                skipNextCR = true;\n            }\n            break;\n\n        case SupportedTagNames::HTML:\n        case SupportedTagNames::BODY:\n            //full html\n            ignoreWhiteSpace = true;\n            break;\n\n        case SupportedTagNames::HEAD:\n        case SupportedTagNames::STYLE:\n        case SupportedTagNames::SCRIPT:\n        case SupportedTagNames::FORM:\n            if (XMLIterator.TagType == EXMLTagType::Start)\n                skipText++;\n            else if (XMLIterator.TagType == EXMLTagType::End)\n                skipText--;\n            break;\n        }\n    }\n\n    if (skipText == 0)\n    {\n        text = XMLIterator.GetText(ignoreWhiteSpace);\n        if (text.Len() > 0)\n        {\n            if (skipNextCR && text[0] == '\\n')\n                text = text.Mid(1);\n            AppendText(text);\n        }\n    }\n}\n\nvoid FHTMLParser::PushTextFormat()\n{\n    TextFormatStack.Add(Format);\n}\n\nvoid FHTMLParser::PopTextFormat()\n{\n    Format = TextFormatStack.Pop();\n}\n\nbool FHTMLParser::IsNewLine()\n{\n    if (Elements->Num() > 0)\n    {\n        const FHTMLElement& element = Elements->Last();\n        if (element.Type == EHTMLElementType::Text)\n            return element.Text.EndsWith(\"\\n\");\n        else\n            return false;\n    }\n\n    return true;\n}\n\nvoid FHTMLParser::AppendText(const FString& Text)\n{\n    if (Elements->Num() > 0)\n    {\n        FHTMLElement& element = Elements->Last();\n        if (element.Type == EHTMLElementType::Text && element.Format.EqualStyle(Format))\n        {\n            element.Text.Append(Text);\n            return;\n        }\n    }\n\n    {\n        FHTMLElement element;\n        element.Type = EHTMLElementType::Text;\n        element.Text = Text;\n        element.Format = Format;\n        Elements->Add(element);\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/NVariant.cpp",
    "content": "#include \"Utils/NVariant.h\"\n\nconst FNVariant FNVariant::Null;\n\nFNVariant::FNVariant()\n{\n}\n\nFNVariant::~FNVariant()\n{\n}\n\nFNVariant::FNVariant(const FNVariant& other)\n{\n    *this = other;\n}\n\nFNVariant::FNVariant(FNVariant&& other)\n{\n    *this = MoveTemp(other);\n}\n\nFNVariant::FNVariant(bool bValue)\n{\n    TheUnion.SetSubtype<bool>(bValue);\n}\n\nFNVariant::FNVariant(int32 Value)\n{\n    TheUnion.SetSubtype<int32>(Value);\n}\n\nFNVariant::FNVariant(float Value)\n{\n    TheUnion.SetSubtype<float>(Value);\n}\n\nFNVariant::FNVariant(const FString& Value)\n{\n    TheUnion.SetSubtype<FString>(Value);\n}\n\nFNVariant::FNVariant(const FColor& Value)\n{\n    TheUnion.SetSubtype<FColor>(Value);\n}\n\nFNVariant::FNVariant(void* Value)\n{\n    TheUnion.SetSubtype<void*>(Value);\n}\n\nFNVariant& FNVariant::operator= (const FNVariant& other)\n{\n    if (this != &other)\n        TheUnion = other.TheUnion;\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (FNVariant&& other)\n{\n    if (this != &other)\n        TheUnion = other.TheUnion;\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (bool bValue)\n{\n    TheUnion.SetSubtype<bool>(bValue);\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (int32 Value)\n{\n    TheUnion.SetSubtype<int32>(Value);\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (float Value)\n{\n    TheUnion.SetSubtype<float>(Value);\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (const FString& Value)\n{\n    TheUnion.SetSubtype<FString>(Value);\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (const FColor& Value)\n{\n    TheUnion.SetSubtype<FColor>(Value);\n    return *this;\n}\n\nFNVariant& FNVariant::operator= (void* Value)\n{\n    TheUnion.SetSubtype<void*>(Value);\n    return *this;\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/UBBParser.cpp",
    "content": "#include \"Utils/UBBParser.h\"\n\nextern const FString FAIRYGUI_API G_EMPTY_STRING;\n\nFUBBParser FUBBParser::DefaultParser;\n\nconst FString LEFT_BRACKET = \"[\";\nconst FString RIGHT_BRACKET = \"]\";\n\nFUBBParser::FUBBParser() :\n    DefaultImgWidth(0),\n    DefaultImgHeight(0),\n    Source(nullptr),\n    ReadPos(0)\n{\n    Handlers.Add(\"url\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_URL));\n    Handlers.Add(\"img\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_IMG));\n    Handlers.Add(\"b\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple));\n    Handlers.Add(\"i\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple));\n    Handlers.Add(\"u\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple));\n    Handlers.Add(\"sup\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple));\n    Handlers.Add(\"sub\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_Simple));\n    Handlers.Add(\"color\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_COLOR));\n    Handlers.Add(\"font\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_FONT));\n    Handlers.Add(\"size\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_SIZE));\n    Handlers.Add(\"align\", FTagHandler::CreateRaw(this, &FUBBParser::OnTag_ALIGN));\n}\n\nFUBBParser::~FUBBParser()\n{\n\n}\n\nFString FUBBParser::Parse(const FString& Text, bool bRemove)\n{\n    Source = &Text;\n    ReadPos = 0;\n    LastColor.Reset();\n    LastFontSize.Reset();\n\n    int32 pos1 = 0, pos2, pos3;\n    bool bEnd;\n    FString tag, attr;\n    FString buffer;\n\n    while ((pos2 = Text.Find(LEFT_BRACKET, ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1)) != -1)\n    {\n        if (pos2 > 0 && Text[pos2 - 1] == '\\\\')\n        {\n            buffer.Append(*Text + pos1, pos2 - pos1 - 1);\n            buffer.Append(LEFT_BRACKET);\n            pos1 = pos2 + 1;\n            continue;\n        }\n\n        buffer.Append(*Text + pos1, pos2 - pos1);\n        pos1 = pos2;\n        pos2 = Text.Find(RIGHT_BRACKET, ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1);\n        if (pos2 == -1)\n            break;\n\n        if (pos2 == pos1 + 1)\n        {\n            buffer.Append(*Text + pos1, 2);\n            pos1 = pos2 + 1;\n            continue;\n        }\n\n        bEnd = Text[pos1 + 1] == '/';\n        pos3 = bEnd ? pos1 + 2 : pos1 + 1;\n        tag = Text.Mid(pos3, pos2 - pos3);\n        ReadPos = pos2 + 1;\n        attr.Reset();\n        if (tag.FindChar('=', pos3))\n        {\n            attr = tag.Mid(pos3 + 1);\n            tag = tag.Mid(0, pos3);\n        }\n        tag = tag.ToLower();\n        FTagHandler* func = Handlers.Find(tag);\n        if (func != nullptr)\n        {\n            FString repl = (*func).Execute(tag, bEnd, attr);\n            if(!bRemove)\n                buffer.Append(repl);\n        }\n        else if (DefaultTagHandler.IsBound())\n        {\n            FString value;\n            if (DefaultTagHandler.Execute(tag, bEnd, attr, value))\n            {\n                if (!bRemove)\n                    buffer.Append(value);\n            }\n            else\n                buffer.Append(*Text + pos1, pos2 - pos1 + 1);\n        }\n        else\n        {\n            buffer.Append(*Text + pos1, pos2 - pos1 + 1);\n        }\n        pos1 = ReadPos;\n    }\n\n    if (buffer.Len() == 0)\n        return Text;\n    else\n    {\n        if (pos1 < Text.Len())\n            buffer.Append(*Text + pos1, Text.Len() - pos1);\n\n        return buffer;\n    }\n}\n\nFString FUBBParser::GetTagText(bool bRemove)\n{\n    int32 pos1 = ReadPos;\n    int32 pos2;\n    FString buffer;\n    while ((pos2 = Source->Find(LEFT_BRACKET, ESearchCase::CaseSensitive, ESearchDir::FromStart, pos1)) != -1)\n    {\n        if ((*Source)[pos2 - 1] == '\\\\')\n        {\n            buffer.Append(**Source + pos1, pos2 - pos1 - 1);\n            buffer.Append(LEFT_BRACKET);\n            pos1 = pos2 + 1;\n        }\n        else\n        {\n            buffer.Append(**Source + pos1, pos2 - pos1);\n            break;\n        }\n    }\n    if (pos2 == -1)\n        return G_EMPTY_STRING;\n\n    if (bRemove)\n        ReadPos = pos2;\n\n    return buffer;\n}\n\nFString FUBBParser::OnTag_URL(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    if (!bEnd)\n    {\n        if (!Attr.IsEmpty())\n            return \"<a href=\\\"\" + Attr + \"\\\" target=\\\"_blank\\\">\";\n        else\n        {\n            FString Href = GetTagText(false);\n            return \"<a href=\\\"\" + Href + \"\\\" target=\\\"_blank\\\">\";\n        }\n    }\n    else\n        return\"</a>\";\n}\n\nFString FUBBParser::OnTag_IMG(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    if (!bEnd)\n    {\n        FString src = GetTagText(true);\n        if (src.IsEmpty())\n            return src;\n\n        if (DefaultImgWidth != 0)\n            return \"<img src=\\\"\" + src + \"\\\" width=\\\"\" + FString::FromInt(DefaultImgWidth) + \"\\\" height=\\\"\" + FString::FromInt(DefaultImgHeight) + \"\\\"/>\";\n        else\n            return \"<img src=\\\"\" + src + \"\\\"/>\";\n    }\n    else\n        return G_EMPTY_STRING;\n}\n\nFString FUBBParser::OnTag_Simple(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    return bEnd ? (\"</\" + TagName + \">\") : (\"<\" + TagName + \">\");\n}\n\nFString FUBBParser::OnTag_COLOR(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    if (!bEnd) {\n        LastColor = Attr;\n        return \"<font color=\\\"\" + Attr + \"\\\">\";\n    }\n    else\n        return \"</font>\";\n}\n\nFString FUBBParser::OnTag_FONT(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    if (!bEnd)\n        return \"<font face=\\\"\" + Attr + \"\\\">\";\n    else\n        return \"</font>\";\n}\n\nFString FUBBParser::OnTag_SIZE(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    if (!bEnd) {\n        LastFontSize = Attr;\n        return \"<font size=\\\"\" + Attr + \"\\\">\";\n    }\n    else\n        return \"</font>\";\n}\n\nFString FUBBParser::OnTag_ALIGN(const FString& TagName, bool bEnd, const FString& Attr)\n{\n    if (!bEnd)\n        return  \"<p align=\\\"\" + Attr + \"\\\">\";\n    else\n        return \"</p>\";\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/XMLAttributes.cpp",
    "content": "#include \"Utils/XMLAttributes.h\"\n\nextern const FString FAIRYGUI_API G_EMPTY_STRING;\n\nconst FString& FXMLAttributes::Get(const FString& AttrName, const FString& DefaultValue)\n{\n    FString* Result = Find(AttrName);\n    if (Result != nullptr)\n        return *Result;\n    else\n        return DefaultValue;\n}\n\nint32 FXMLAttributes::GetInt(const FString& AttrName, int32 DefaultValue)\n{\n    const FString& Value = Get(AttrName);\n    if (Value.Len() == 0)\n        return DefaultValue;\n\n    return FCString::Atoi(*Value);\n}\n\nfloat FXMLAttributes::GetFloat(const FString& AttrName, float DefaultValue)\n{\n    const FString& Value = Get(AttrName);\n    if (Value.Len() == 0)\n        return DefaultValue;\n\n    return FCString::Atof(*Value);\n}\n\nbool FXMLAttributes::GetBool(const FString& AttrName, bool DefaultValue)\n{\n    const FString& Value = Get(AttrName);\n    if (Value.Len() == 0)\n        return DefaultValue;\n\n    return Value.ToBool();\n}\n\nFColor FXMLAttributes::GetColor(const FString& AttrName, const FColor& DefaultValue)\n{\n    const FString& Value = Get(AttrName);\n    if (Value.Len() == 0)\n        return DefaultValue;\n\n    return FColor::FromHex(Value);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Utils/XMLIterator.cpp",
    "content": "#include \"Utils/XMLIterator.h\"\n\nextern const FString FAIRYGUI_API G_EMPTY_STRING;\n\nconst TCHAR* CDATA_START = TEXT(\"<![CDATA[\");\nconst TCHAR* CDATA_END = TEXT(\"]]>\");\nconst TCHAR* COMMENT_START = TEXT(\"<!--\");\nconst TCHAR* COMMENT_END = TEXT(\"-->\");\nconst TCHAR* SYMBOL_LT = TEXT(\"<\");\nconst TCHAR* SYMBOL_AMP = TEXT(\"&\");\n\nvoid FXMLIterator::Begin(const FString& InText, bool bInLowerCaseName)\n{\n    Source = &InText;\n    SourceLen = Source->Len();\n    bLowerCaseName = bInLowerCaseName;\n    ParsePos = 0;\n    LastTagEnd = 0;\n    TagPos = 0;\n    TagLength = 0;\n    TagName.Reset();\n}\n\nbool FXMLIterator::NextTag()\n{\n    int32 pos;\n    TCHAR c;\n    TagType = EXMLTagType::Start;\n    FString buffer;\n    LastTagEnd = ParsePos;\n    bAttrParsed = false;\n    LastTagName = TagName;\n    const FString& Text = *Source;\n\n    while ((pos = Text.Find(SYMBOL_LT, ESearchCase::IgnoreCase, ESearchDir::FromStart, ParsePos)) != -1)\n    {\n        ParsePos = pos;\n        pos++;\n\n        if (pos == SourceLen)\n            break;\n\n        c = Text[pos];\n        if (c == '!')\n        {\n            if (SourceLen > pos + 7 && Text.Mid(pos - 1, 9) == CDATA_START)\n            {\n                pos = Text.Find(CDATA_END, ESearchCase::IgnoreCase, ESearchDir::FromStart, pos);\n                TagType = EXMLTagType::CDATA;\n                TagName.Reset();\n                TagPos = ParsePos;\n                if (pos == -1)\n                    TagLength = SourceLen - ParsePos;\n                else\n                    TagLength = pos + 3 - ParsePos;\n                ParsePos += TagLength;\n                return true;\n            }\n            else if (SourceLen > pos + 2 && Text.Mid(pos - 1, 4) == COMMENT_START)\n            {\n                pos = Text.Find(COMMENT_END, ESearchCase::IgnoreCase, ESearchDir::FromStart, pos);\n                TagType = EXMLTagType::Comment;\n                TagName.Reset();\n                TagPos = ParsePos;\n                if (pos == -1)\n                    TagLength = SourceLen - ParsePos;\n                else\n                    TagLength = pos + 3 - ParsePos;\n                ParsePos += TagLength;\n                return true;\n            }\n            else\n            {\n                pos++;\n                TagType = EXMLTagType::Instruction;\n            }\n        }\n        else if (c == '/')\n        {\n            pos++;\n            TagType = EXMLTagType::End;\n        }\n        else if (c == '?')\n        {\n            pos++;\n            TagType = EXMLTagType::Instruction;\n        }\n\n        for (; pos < SourceLen; pos++)\n        {\n            c = Text[pos];\n            if (FChar::IsWhitespace(c) || c == '>' || c == '/')\n                break;\n        }\n        if (pos == SourceLen)\n            break;\n\n        buffer.Append(*Text + ParsePos + 1, pos - ParsePos - 1);\n        if (buffer.Len() > 0 && buffer[0] == '/')\n            buffer.RemoveAt(0, 1);\n\n        bool singleQuoted = false, doubleQuoted = false;\n        int32 possibleEnd = -1;\n        for (; pos < SourceLen; pos++)\n        {\n            c = Text[pos];\n            if (c == '\"')\n            {\n                if (!singleQuoted)\n                    doubleQuoted = !doubleQuoted;\n            }\n            else if (c == '\\'')\n            {\n                if (!doubleQuoted)\n                    singleQuoted = !singleQuoted;\n            }\n\n            if (c == '>')\n            {\n                if (!(singleQuoted || doubleQuoted))\n                {\n                    possibleEnd = -1;\n                    break;\n                }\n\n                possibleEnd = pos;\n            }\n            else if (c == '<')\n                break;\n        }\n        if (possibleEnd != -1)\n            pos = possibleEnd;\n\n        if (pos == SourceLen)\n            break;\n\n        if (Text[pos - 1] == '/')\n            TagType = EXMLTagType::Void;\n\n        TagName = buffer;\n        if (bLowerCaseName)\n            TagName = TagName.ToLower();\n        TagPos = ParsePos;\n        TagLength = pos + 1 - ParsePos;\n        ParsePos += TagLength;\n\n        return true;\n    }\n\n    TagPos = SourceLen;\n    TagLength = 0;\n    TagName.Reset();\n    return false;\n}\n\nFString FXMLIterator::GetTagSource() const\n{\n    return (*Source).Mid(TagPos, TagLength);\n}\n\nFString FXMLIterator::GetRawText(bool bTrim) const\n{\n    if (LastTagEnd == TagPos)\n        return G_EMPTY_STRING;\n\n    if (bTrim)\n    {\n        int32 i = LastTagEnd;\n        for (; i < TagPos; i++)\n        {\n            char c = (*Source)[i];\n            if (!FChar::IsWhitespace(c))\n                break;\n        }\n\n        if (i == TagPos)\n            return G_EMPTY_STRING;\n        else\n            return (*Source).Mid(i, TagPos - i).TrimEnd();\n    }\n    else\n        return (*Source).Mid(LastTagEnd, TagPos - LastTagEnd);\n}\n\nFString FXMLIterator::GetText(bool bTrim) const\n{\n    if (LastTagEnd == TagPos)\n        return G_EMPTY_STRING;\n\n    if (bTrim)\n    {\n        int32 i = LastTagEnd;\n        for (; i < TagPos; i++)\n        {\n            char c = (*Source)[i];\n            if (!FChar::IsWhitespace(c))\n                break;\n        }\n\n        if (i == TagPos)\n            return G_EMPTY_STRING;\n        else\n            return DecodeString((*Source).Mid(i, TagPos - i).TrimEnd());\n    }\n    else\n        return DecodeString((*Source).Mid(LastTagEnd, TagPos - LastTagEnd));\n}\n\nvoid FXMLIterator::ParseAttributes()\n{\n    if (bAttrParsed)\n        return;\n\n    bAttrParsed = true;\n\n    FString attrName;\n    int32 valueStart;\n    int32 valueEnd;\n    bool waitValue = false;\n    int32 quoted;\n    FString buffer;\n    int32 i = TagPos;\n    int32 attrEnd = TagPos + TagLength;\n\n    if (i < attrEnd && (*Source)[i] == '<')\n    {\n        for (; i < attrEnd; i++)\n        {\n            TCHAR c = (*Source)[i];\n            if (FChar::IsWhitespace(c) || c == '>' || c == '/')\n                break;\n        }\n    }\n\n    for (; i < attrEnd; i++)\n    {\n        char c = (*Source)[i];\n        if (c == '=')\n        {\n            valueStart = -1;\n            valueEnd = -1;\n            quoted = 0;\n            for (int32 j = i + 1; j < attrEnd; j++)\n            {\n                char c2 = (*Source)[j];\n                if (FChar::IsWhitespace(c2))\n                {\n                    if (valueStart != -1 && quoted == 0)\n                    {\n                        valueEnd = j - 1;\n                        break;\n                    }\n                }\n                else if (c2 == '>')\n                {\n                    if (quoted == 0)\n                    {\n                        valueEnd = j - 1;\n                        break;\n                    }\n                }\n                else if (c2 == '\"')\n                {\n                    if (valueStart != -1)\n                    {\n                        if (quoted != 1)\n                        {\n                            valueEnd = j - 1;\n                            break;\n                        }\n                    }\n                    else\n                    {\n                        quoted = 2;\n                        valueStart = j + 1;\n                    }\n                }\n                else if (c2 == '\\'')\n                {\n                    if (valueStart != -1)\n                    {\n                        if (quoted != 2)\n                        {\n                            valueEnd = j - 1;\n                            break;\n                        }\n                    }\n                    else\n                    {\n                        quoted = 1;\n                        valueStart = j + 1;\n                    }\n                }\n                else if (valueStart == -1)\n                {\n                    valueStart = j;\n                }\n            }\n\n            if (valueStart != -1 && valueEnd != -1)\n            {\n                attrName = buffer;\n                if (bLowerCaseName)\n                    attrName = attrName.ToLower();\n                buffer.Reset();\n                Attributes.Add(attrName, DecodeString((*Source).Mid(valueStart, valueEnd - valueStart + 1)));\n                i = valueEnd + 1;\n            }\n            else\n                break;\n        }\n        else if (!FChar::IsWhitespace(c))\n        {\n            if (waitValue || c == '/' || c == '>')\n            {\n                if (buffer.Len() > 0)\n                {\n                    attrName = buffer;\n                    if (bLowerCaseName)\n                        attrName = attrName.ToLower();\n                    Attributes.Add(attrName, G_EMPTY_STRING);\n                    buffer.Reset();\n                }\n\n                waitValue = false;\n            }\n\n            if (c != '/' && c != '>')\n                buffer.AppendChar(c);\n        }\n        else\n        {\n            if (buffer.Len() > 0)\n                waitValue = true;\n        }\n    }\n}\n\nFString FXMLIterator::DecodeString(const FString& InSource)\n{\n    int32 len = InSource.Len();\n    int32 pos1 = 0, pos2 = 0;\n    FString result;\n\n    while (true)\n    {\n        pos2 = InSource.Find(SYMBOL_AMP, ESearchCase::IgnoreCase, ESearchDir::FromStart, pos1);\n        if (pos2 == -1)\n        {\n            result.Append(InSource.Mid(pos1));\n            break;\n        }\n        result.Append(InSource.Mid(pos1, pos2 - pos1));\n\n        pos1 = pos2 + 1;\n        pos2 = pos1;\n        int32 end = FMath::Min(len, pos2 + 10);\n        for (; pos2 < end; pos2++)\n        {\n            if (InSource[pos2] == ';')\n                break;\n        }\n        if (pos2 < end && pos2 > pos1)\n        {\n            FString entity = InSource.Mid(pos1, pos2 - pos1);\n            if (entity[0] == '#')\n            {\n                if (entity.Len() > 1)\n                {\n                    uint32 u;\n                    if (entity[1] == 'x')\n                        u = FParse::HexNumber(*entity.Mid(2));\n                    else\n                        u = FParse::HexNumber(*entity.Mid(1));\n                    result.AppendChar((TCHAR)u);\n                    pos1 = pos2 + 1;\n                }\n                else\n                    result.AppendChar('&');\n            }\n            else\n            {\n                static const TMap<FString, TCHAR> EscapeCharacters = {\n                    { \"amp\", '&' },\n                    { \"quot\", '\"'},\n                    { \"lt\", '<' },\n                    { \"gt\", '>'},\n                };\n\n                TCHAR c = EscapeCharacters.FindRef(entity);\n                if (c != 0)\n                {\n                    result.AppendChar(c);\n                    pos1 = pos2 + 1;\n                }\n                else\n                    result.AppendChar('&');\n            }\n        }\n        else\n        {\n            result.AppendChar('&');\n        }\n    }\n\n    return result;\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/BitmapFont.cpp",
    "content": "#include \"Widgets/BitmapFont.h\"\n\nvoid FBitmapFont::AddReferencedObjects(FReferenceCollector& Collector)\n{\n    if (Texture != nullptr)\n        Collector.AddReferencedObject(Texture);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/BitmapFontRun.cpp",
    "content": "#include \"Widgets/BitmapFontRun.h\"\n#include \"Styling/StyleDefaults.h\"\n#include \"Rendering/DrawElements.h\"\n#include \"Framework/Application/SlateApplication.h\"\n#include \"Framework/Text/DefaultLayoutBlock.h\"\n#include \"Framework/Text/RunUtils.h\"\n\nTSharedRef< FBitmapFontRun > FBitmapFontRun::Create(const TSharedRef< const FString >& InText, const TSharedRef<FBitmapFont>& InFont, const FTextRange& InRange)\n{\n    return MakeShareable(new FBitmapFontRun(InText, InFont, InRange));\n}\n\nFBitmapFontRun::FBitmapFontRun(const TSharedRef< const FString >& InText, const TSharedRef<FBitmapFont>& InFont, const FTextRange& InRange)\n    : Text(InText)\n    , Range(InRange)\n    , Font(InFont)\n{\n    Glyph = Font->Glyphs.Find(Text.Get()[Range.BeginIndex]);\n    if (Glyph != nullptr)\n    {\n        Brush.SetResourceObject(Font->Texture->NativeTexture);\n        Brush.SetImageSize(Glyph->Size);\n        Brush.SetUVRegion(Glyph->UVRect);\n    }\n}\n\nFBitmapFontRun::~FBitmapFontRun()\n{\n}\n\nconst TArray< TSharedRef<SWidget> >& FBitmapFontRun::GetChildren()\n{\n    static TArray< TSharedRef<SWidget> > NoChildren;\n    return NoChildren;\n}\n\nvoid FBitmapFontRun::ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n    // no widgets\n}\n\nint32 FBitmapFontRun::GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint) const\n{\n    // An image should always contain a single character (a breaking space)\n    check(Range.Len() == 1);\n\n    const FVector2D& BlockOffset = Block->GetLocationOffset();\n    const FVector2D& BlockSize = Block->GetSize();\n\n    const float Left = BlockOffset.X;\n    const float Top = BlockOffset.Y;\n    const float Right = BlockOffset.X + BlockSize.X;\n    const float Bottom = BlockOffset.Y + BlockSize.Y;\n\n    const bool ContainsPoint = Location.X >= Left && Location.X < Right && Location.Y >= Top && Location.Y < Bottom;\n\n    if (!ContainsPoint)\n    {\n        return INDEX_NONE;\n    }\n\n    const float ScaledImageSize = Glyph->XAdvance * Scale;\n    const int32 Index = (Location.X <= (Left + (ScaledImageSize * 0.5f))) ? Range.BeginIndex : Range.EndIndex;\n\n    if (OutHitPoint)\n    {\n        const FTextRange BlockRange = Block->GetTextRange();\n        const FLayoutBlockTextContext BlockTextContext = Block->GetTextContext();\n\n        // The block for an image will always detect a LTR reading direction, so use the base direction (of the line) for the image hit-point detection\n        *OutHitPoint = RunUtils::CalculateTextHitPoint(Index, BlockRange, BlockTextContext.BaseDirection);\n    }\n\n    return Index;\n}\n\nFVector2D FBitmapFontRun::GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const\n{\n    return Block->GetLocationOffset();\n}\n\nint32 FBitmapFontRun::OnPaint(const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    if (Glyph == nullptr)\n        return LayerId;\n\n    // The block size and offset values are pre-scaled, so we need to account for that when converting the block offsets into paint geometry\n    const float InverseScale = Inverse(AllottedGeometry.Scale);\n\n    FLinearColor FinalColorAndOpacity;\n    if (Font->bCanTint)\n        FinalColorAndOpacity = InWidgetStyle.GetColorAndOpacityTint() * DefaultStyle.ColorAndOpacity.GetSpecifiedColor();\n    else\n        FinalColorAndOpacity = InWidgetStyle.GetColorAndOpacityTint();\n    const ESlateDrawEffect DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;\n    FSlateDrawElement::MakeBox(\n        OutDrawElements,\n        ++LayerId,\n        AllottedGeometry.ToPaintGeometry(Glyph->Size, FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset()) + Glyph->Offset)),\n        &Brush,\n        DrawEffects,\n        FinalColorAndOpacity\n    );\n\n    return LayerId;\n}\n\nTSharedRef< ILayoutBlock > FBitmapFontRun::CreateBlock(int32 BeginIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer)\n{\n    return FDefaultLayoutBlock::Create(SharedThis(this), FTextRange(BeginIndex, EndIndex), Size, TextContext, Renderer);\n}\n\nint8 FBitmapFontRun::GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const\n{\n    return 0;\n}\n\nFVector2D FBitmapFontRun::Measure(int32 BeginIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const\n{\n    if (Glyph == nullptr || (EndIndex - BeginIndex == 0))\n    {\n        return FVector2D(0, GetMaxHeight(Scale));\n    }\n\n    return FVector2D(Glyph->XAdvance, Glyph->LineHeight) * Scale;\n}\n\nint16 FBitmapFontRun::GetMaxHeight(float Scale) const\n{\n    if (Glyph == nullptr)\n        return 0;\n    else\n        return Glyph->LineHeight * Scale;\n}\n\nint16 FBitmapFontRun::GetBaseLine(float Scale) const\n{\n    return Scale;\n}\n\nFTextRange FBitmapFontRun::GetTextRange() const\n{\n    return Range;\n}\n\nvoid FBitmapFontRun::SetTextRange(const FTextRange& Value)\n{\n    Range = Value;\n}\n\nvoid FBitmapFontRun::Move(const TSharedRef<FString>& NewText, const FTextRange& NewRange)\n{\n    Text = NewText;\n    Range = NewRange;\n}\n\nTSharedRef<IRun> FBitmapFontRun::Clone() const\n{\n    TSharedRef<FBitmapFontRun> NewRun = FBitmapFontRun::Create(Text, Font, Range);\n\n    return NewRun;\n}\n\nvoid FBitmapFontRun::AppendTextTo(FString& AppendToText) const\n{\n    AppendToText.Append(**Text + Range.BeginIndex, Range.Len());\n}\n\nvoid FBitmapFontRun::AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const\n{\n    check(Range.BeginIndex <= PartialRange.BeginIndex);\n    check(Range.EndIndex >= PartialRange.EndIndex);\n\n    AppendToText.Append(**Text + PartialRange.BeginIndex, PartialRange.Len());\n}\n\nconst FRunInfo& FBitmapFontRun::GetRunInfo() const\n{\n    static FRunInfo RunInfo;\n    return RunInfo;\n}\n\nERunAttributes FBitmapFontRun::GetRunAttributes() const\n{\n    return ERunAttributes::None;\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/HitTest.cpp",
    "content": "#include \"Widgets/HitTest.h\"\n#include \"Utils/ByteBuffer.h\"\n#include \"UI/GObject.h\"\n\nvoid FPixelHitTestData::Load(FByteBuffer* Buffer)\n{\n    Buffer->Skip(4);\n    PixelWidth = Buffer->ReadInt();\n    Scale = 1.0f / Buffer->ReadByte();\n    int32 PixelsLength = Buffer->ReadInt();\n    Pixels.Append(Buffer->GetBuffer() + Buffer->GetPos(), PixelsLength);\n}\n\nFPixelHitTest::FPixelHitTest(const TSharedPtr<FPixelHitTestData>& InData, int32 InOffsetX, int32 InOffsetY) :\n    OffsetX(InOffsetX),\n    OffsetY(InOffsetY),\n    Data(InData)\n{\n}\n\nFPixelHitTest::~FPixelHitTest()\n{\n\n}\n\nbool FPixelHitTest::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const\n{\n    int32 x = FMath::FloorToInt((LocalPoint.X / LayoutScaleMultiplier.X - OffsetX) * Data->Scale);\n    int32 y = FMath::FloorToInt((LocalPoint.Y / LayoutScaleMultiplier.Y - OffsetY) * Data->Scale);\n    if (x < 0 || y < 0 || x >= Data->PixelWidth)\n        return false;\n\n    int32 pos = y * Data->PixelWidth + x;\n    int32 pos2 = pos / 8;\n    int32 pos3 = pos % 8;\n\n    if (pos2 >= 0 && pos2 < Data->Pixels.Num())\n        return ((Data->Pixels[pos2] >> pos3) & 0x1) > 0;\n    else\n        return false;\n}\n\nFChildHitTest::FChildHitTest(UGObject* InObj) :Obj(InObj)\n{\n}\n\nFChildHitTest::~FChildHitTest()\n{\n}\n\nbool FChildHitTest::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const\n{\n    if (!Obj.IsValid() || Obj->GetParent() == nullptr)\n        return false;\n\n    IHitTest* HitArea = Obj->GetHitArea();\n    if (HitArea == nullptr)\n        return false;\n\n    FVector2D NewPoint = LocalPoint + Obj->GetPosition();\n    FBox2D NewRect = FBox2D(FVector2D::ZeroVector, Obj->GetSize());\n    if (!NewRect.IsInside(NewPoint))\n        return false;\n\n    FVector2D NewMultiplier = Obj->GetSize() / Obj->SourceSize;\n    if (NewMultiplier.ContainsNaN())\n        NewMultiplier.Set(1, 1);\n\n    return HitArea->HitTest(NewRect, NewMultiplier, NewPoint);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/LoaderRun.cpp",
    "content": "#include \"Widgets/LoaderRun.h\"\n#include \"Styling/StyleDefaults.h\"\n#include \"Rendering/DrawElements.h\"\n#include \"Framework/Application/SlateApplication.h\"\n#include \"Framework/Text/DefaultLayoutBlock.h\"\n#include \"Framework/Text/RunUtils.h\"\n#include \"FairyApplication.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/PackageItem.h\"\n#include \"UI/GLoader.h\"\n\nTSharedRef< FLoaderRun > FLoaderRun::Create(UFairyApplication* App, const FHTMLElement& InHTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange)\n{\n    return MakeShareable(new FLoaderRun(App, InHTMLElement, InText, InRange));\n}\n\nFLoaderRun::FLoaderRun(UFairyApplication* App, const FHTMLElement& InHTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange)\n    : Children()\n    , HTMLElement(InHTMLElement)\n    , Text(InText)\n    , Range(InRange)\n{\n    Loader = NewObject<UGLoader>(App);\n    Children.Add(Loader->GetDisplayObject());\n\n    FVector2D SourceSize(0, 0);\n    const FString& Src = HTMLElement.Attributes.Get(\"src\");\n    if (Src.Len() > 0)\n    {\n        TSharedPtr<FPackageItem> pii = UUIPackage::GetItemByURL(Src);\n        if (pii.IsValid())\n            SourceSize = pii->Size;\n    }\n\n    Loader->SetURL(Src);\n\n    SourceSize.X = HTMLElement.Attributes.GetInt(\"width\", SourceSize.X);\n    SourceSize.Y = HTMLElement.Attributes.GetInt(\"height\", SourceSize.Y);\n\n    if (SourceSize.X == 0)\n        SourceSize.X = 5;\n    if (SourceSize.Y == 0)\n        SourceSize.Y = 5;\n    Loader->SetSize(SourceSize);\n}\n\nFLoaderRun::~FLoaderRun()\n{\n}\n\nconst TArray< TSharedRef<SWidget> >& FLoaderRun::GetChildren()\n{\n    return Children;\n}\n\nvoid FLoaderRun::ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n    const float InverseScale = Inverse(AllottedGeometry.Scale);\n\n    ArrangedChildren.AddWidget(\n        AllottedGeometry.MakeChild(Children[0], TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset())))\n    );\n}\n\nint32 FLoaderRun::GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint) const\n{\n    // An image should always contain a single character (a breaking space)\n    check(Range.Len() == 1);\n\n    const FVector2D& BlockOffset = Block->GetLocationOffset();\n    const FVector2D& BlockSize = Block->GetSize();\n\n    const float Left = BlockOffset.X;\n    const float Top = BlockOffset.Y;\n    const float Right = BlockOffset.X + BlockSize.X;\n    const float Bottom = BlockOffset.Y + BlockSize.Y;\n\n    const bool ContainsPoint = Location.X >= Left && Location.X < Right && Location.Y >= Top && Location.Y < Bottom;\n\n    if (!ContainsPoint)\n    {\n        return INDEX_NONE;\n    }\n\n    const FVector2D ScaledImageSize = Loader->GetSize() * Scale;\n    const int32 Index = (Location.X <= (Left + (ScaledImageSize.X * 0.5f))) ? Range.BeginIndex : Range.EndIndex;\n\n    if (OutHitPoint)\n    {\n        const FTextRange BlockRange = Block->GetTextRange();\n        const FLayoutBlockTextContext BlockTextContext = Block->GetTextContext();\n\n        // The block for an image will always detect a LTR reading direction, so use the base direction (of the line) for the image hit-point detection\n        *OutHitPoint = RunUtils::CalculateTextHitPoint(Index, BlockRange, BlockTextContext.BaseDirection);\n    }\n\n    return Index;\n}\n\nFVector2D FLoaderRun::GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const\n{\n    return Block->GetLocationOffset();\n}\n\nint32 FLoaderRun::OnPaint(const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    const float InverseScale = Inverse(AllottedGeometry.Scale);\n    const FGeometry WidgetGeometry = AllottedGeometry.MakeChild(TransformVector(InverseScale, Block->GetSize()), FSlateLayoutTransform(TransformPoint(InverseScale, Block->GetLocationOffset())));\n    return Children[0]->Paint(Args, WidgetGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);\n}\n\nTSharedRef< ILayoutBlock > FLoaderRun::CreateBlock(int32 BeginIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer)\n{\n    return FDefaultLayoutBlock::Create(SharedThis(this), FTextRange(BeginIndex, EndIndex), Size, TextContext, Renderer);\n}\n\nint8 FLoaderRun::GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const\n{\n    return 0;\n}\n\nFVector2D FLoaderRun::Measure(int32 BeginIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const\n{\n    if (EndIndex - BeginIndex == 0)\n    {\n        return FVector2D(0, GetMaxHeight(Scale));\n    }\n\n    return (Loader->GetSize() + FVector2D(2, 0)) * Scale;\n}\n\nint16 FLoaderRun::GetMaxHeight(float Scale) const\n{\n    return Loader->GetSize().Y * Scale;\n}\n\nint16 FLoaderRun::GetBaseLine(float Scale) const\n{\n    return -Loader->GetSize().Y * 0.2f * Scale;\n}\n\nFTextRange FLoaderRun::GetTextRange() const\n{\n    return Range;\n}\n\nvoid FLoaderRun::SetTextRange(const FTextRange& Value)\n{\n    Range = Value;\n}\n\nvoid FLoaderRun::Move(const TSharedRef<FString>& NewText, const FTextRange& NewRange)\n{\n    Text = NewText;\n    Range = NewRange;\n}\n\nTSharedRef<IRun> FLoaderRun::Clone() const\n{\n    TSharedRef<FLoaderRun> NewRun = FLoaderRun::Create(Loader->GetApp(), HTMLElement, Text, Range);\n\n    return NewRun;\n}\n\nvoid FLoaderRun::AppendTextTo(FString& AppendToText) const\n{\n    AppendToText.Append(**Text + Range.BeginIndex, Range.Len());\n}\n\nvoid FLoaderRun::AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const\n{\n    check(Range.BeginIndex <= PartialRange.BeginIndex);\n    check(Range.EndIndex >= PartialRange.EndIndex);\n\n    AppendToText.Append(**Text + PartialRange.BeginIndex, PartialRange.Len());\n}\n\nconst FRunInfo& FLoaderRun::GetRunInfo() const\n{\n    static FRunInfo RunInfo;\n    return RunInfo;\n}\n\nERunAttributes FLoaderRun::GetRunAttributes() const\n{\n    return ERunAttributes::None;\n}\n\nvoid FLoaderRun::AddReferencedObjects(FReferenceCollector& Collector)\n{\n    Collector.AddReferencedObject(Loader);\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/EllipseMesh.cpp",
    "content": "#include \"Widgets/Mesh/EllipseMesh.h\"\n\nFEllipseMesh::FEllipseMesh() :\n    LineWidth(0),\n    LineColor(FColor::Black),\n    StartDegree(0),\n    EndDegreee(360)\n{\n}\n\nvoid FEllipseMesh::OnPopulateMesh(FVertexHelper& Helper)\n{\n    static SlateIndex SECTOR_CENTER_TRIANGLES[] = {\n        0, 4, 1,\n        0, 3, 4,\n        0, 2, 3,\n        0, 8, 5,\n        0, 7, 8,\n        0, 6, 7,\n        6, 5, 2,\n        2, 1, 6\n    };\n\n    const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect;\n    const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor;\n\n    float sectionStart = FMath::Clamp<float>(StartDegree, 0, 360);\n    float sectionEnd = FMath::Clamp<float>(EndDegreee, 0, 360);\n    bool clipped = sectionStart > 0 || sectionEnd < 360;\n    sectionStart = FMath::DegreesToRadians(sectionStart);\n    sectionEnd = FMath::DegreesToRadians(sectionEnd);\n    const FColor& centerColor2 = CenterColor.IsSet() ? CenterColor.GetValue() : color;\n\n    FVector2D radius = rect.GetSize() * 0.5f;\n    int32 sides = FMath::CeilToInt(PI * (radius.X + radius.Y) / 4);\n    sides = FMath::Clamp<int32>(sides, 40, 800);\n    float angleDelta = 2 * PI / sides;\n    float angle = 0;\n    float lineAngle = 0;\n\n    if (LineWidth > 0 && clipped)\n    {\n        lineAngle = LineWidth / radius.GetMax();\n        sectionStart += lineAngle;\n        sectionEnd -= lineAngle;\n    }\n\n    int32 vpos = Helper.GetVertexCount();\n    FVector2D center = rect.Min + radius;\n    Helper.AddVertex(center, centerColor2);\n    for (int32 i = 0; i < sides; i++)\n    {\n        if (angle < sectionStart)\n            angle = sectionStart;\n        else if (angle > sectionEnd)\n            angle = sectionEnd;\n        FVector2D vec(FMath::Cos(angle) * (radius.X - LineWidth) + center.X, FMath::Sin(angle) * (radius.Y - LineWidth) + center.Y);\n        Helper.AddVertex(vec, color);\n        if (LineWidth > 0)\n        {\n            Helper.AddVertex(vec, LineColor);\n            Helper.AddVertex(FVector2D(FMath::Cos(angle) * radius.X + center.X, FMath::Sin(angle) * radius.Y + center.Y), LineColor);\n        }\n        angle += angleDelta;\n    }\n\n    if (LineWidth > 0)\n    {\n        int32 cnt = sides * 3;\n        for (int32 i = 0; i < cnt; i += 3)\n        {\n            if (i != cnt - 3)\n            {\n                Helper.AddTriangle(0, i + 1, i + 4);\n                Helper.AddTriangle(i + 5, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, i + 6, i + 5);\n            }\n            else if (!clipped)\n            {\n                Helper.AddTriangle(0, i + 1, 1);\n                Helper.AddTriangle(2, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, 3, 2);\n            }\n            else\n            {\n                Helper.AddTriangle(0, i + 1, i + 1);\n                Helper.AddTriangle(i + 2, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, i + 3, i + 2);\n            }\n        }\n    }\n    else\n    {\n        for (int32 i = 0; i < sides; i++)\n        {\n            if (i != sides - 1)\n                Helper.AddTriangle(0, i + 1, i + 2);\n            else if (!clipped)\n                Helper.AddTriangle(0, i + 1, 1);\n            else\n                Helper.AddTriangle(0, i + 1, i + 1);\n        }\n    }\n\n    if (LineWidth > 0 && clipped)\n    {\n        Helper.AddVertex(FVector2D(radius.X, radius.Y), LineColor);\n        float centerRadius = LineWidth * 0.5f;\n\n        sectionStart -= lineAngle;\n        angle = sectionStart + lineAngle * 0.5f + PI * 0.5f;\n        Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor);\n        angle -= PI;\n        Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor);\n        Helper.AddVertex(FVector2D(FMath::Cos(sectionStart) * radius.X + radius.X, FMath::Sin(sectionStart) * radius.Y + radius.Y), LineColor);\n        Helper.AddVertex(Helper.GetPosition(vpos + 3), LineColor);\n\n        sectionEnd += lineAngle;\n        angle = sectionEnd - lineAngle * 0.5f + PI * 0.5f;\n        Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor);\n        angle -= PI;\n        Helper.AddVertex(FVector2D(FMath::Cos(angle) * centerRadius + radius.X, FMath::Sin(angle) * centerRadius + radius.Y), LineColor);\n        Helper.AddVertex(Helper.GetPosition(vpos + sides * 3), LineColor);\n        Helper.AddVertex(FVector2D(FMath::Cos(sectionEnd) * radius.X + radius.X, FMath::Sin(sectionEnd) * radius.Y + radius.Y), LineColor);\n\n        Helper.AddTriangles(SECTOR_CENTER_TRIANGLES, 24, sides * 3 + 1);\n    }\n}\n\nbool FEllipseMesh::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const\n{\n    FVector2D Radius = ContentRect.GetSize() * 0.5f;\n    FVector2D Pos = LocalPoint - Radius - ContentRect.Min;\n    if (FMath::Pow(Pos.X / Radius.X, 2) + FMath::Pow(Pos.Y / Radius.Y, 2) < 1)\n    {\n        if (StartDegree != 0 || EndDegreee != 360)\n        {\n            float deg = FMath::RadiansToDegrees(FMath::Atan2(Pos.Y, Pos.X));\n            if (deg < 0)\n                deg += 360;\n            return deg >= StartDegree && deg <= EndDegreee;\n        }\n        else\n            return true;\n    }\n\n    return false;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/FillMesh.cpp",
    "content": "#include \"Widgets/Mesh/FillMesh.h\"\n\nstatic void FillHorizontal(FVertexHelper& Helper, FBox2D VertRect, int32 Origin, float Amount)\n{\n    float a = VertRect.GetSize().X * Amount;\n    if ((EOriginHorizontal)Origin == EOriginHorizontal::Right || (EOriginVertical)Origin == EOriginVertical::Bottom)\n        VertRect.Min.X += (VertRect.GetSize().X - a);\n    else\n        VertRect.Max.X = VertRect.Min.X + a;\n\n    Helper.AddQuad(VertRect);\n    Helper.AddTriangles();\n}\n\nstatic void FillVertical(FVertexHelper& Helper, FBox2D VertRect, int32 Origin, float Amount)\n{\n    float a = VertRect.GetSize().Y * Amount;\n    if ((EOriginHorizontal)Origin == EOriginHorizontal::Right || (EOriginVertical)Origin == EOriginVertical::Bottom)\n        VertRect.Min.Y += (VertRect.GetSize().Y - a);\n    else\n        VertRect.Max.Y = VertRect.Min.Y + a;\n\n    Helper.AddQuad(VertRect);\n    Helper.AddTriangles();\n}\n\n//4 vertex\nstatic void FillRadial90(FVertexHelper& Helper, FBox2D VertRect, EOrigin90 Origin, float Amount, bool bClockwise)\n{\n    bool flipX = Origin == EOrigin90::TopRight || Origin == EOrigin90::BottomRight;\n    bool flipY = Origin == EOrigin90::BottomLeft || Origin == EOrigin90::BottomRight;\n    if (flipX != flipY)\n        bClockwise = !bClockwise;\n\n    float ratio = bClockwise ? Amount : (1 - Amount);\n    float tan = FMath::Tan(PI * 0.5f * ratio);\n    bool thresold = false;\n    if (ratio != 1)\n        thresold = (VertRect.GetSize().Y / VertRect.GetSize().X - tan) > 0;\n    if (!bClockwise)\n        thresold = !thresold;\n    float x = VertRect.Min.X + (ratio == 0 ? FLT_MAX : (VertRect.GetSize().Y / tan));\n    float y = VertRect.Min.Y + (ratio == 1 ? FLT_MAX : (VertRect.GetSize().X * tan));\n    float x2 = x;\n    float y2 = y;\n    if (flipX)\n        x2 = VertRect.GetSize().X - x;\n    if (flipY)\n        y2 = VertRect.GetSize().Y - y;\n    float xMin = flipX ? (VertRect.GetSize().X - VertRect.Min.X) : VertRect.Min.X;\n    float yMin = flipY ? (VertRect.GetSize().Y - VertRect.Min.Y) : VertRect.Min.Y;\n    float xMax = flipX ? -VertRect.Min.X : VertRect.Max.X;\n    float yMax = flipY ? -VertRect.Min.Y : VertRect.Max.Y;\n\n    Helper.AddVertex(FVector2D(xMin, yMin));\n\n    if (bClockwise)\n        Helper.AddVertex(FVector2D(xMax, yMin));\n\n    if (y > VertRect.Max.Y)\n    {\n        if (thresold)\n            Helper.AddVertex(FVector2D(x2, yMax));\n        else\n            Helper.AddVertex(FVector2D(xMax, yMax));\n    }\n    else\n        Helper.AddVertex(FVector2D(xMax, y2));\n\n    if (x > VertRect.Max.X)\n    {\n        if (thresold)\n            Helper.AddVertex(FVector2D(xMax, y2));\n        else\n            Helper.AddVertex(FVector2D(xMax, yMax));\n    }\n    else\n        Helper.AddVertex(FVector2D(x2, yMax));\n\n    if (!bClockwise)\n        Helper.AddVertex(FVector2D(xMin, yMax));\n\n    if (flipX == flipY)\n    {\n        Helper.AddTriangle(0, 1, 2);\n        Helper.AddTriangle(0, 2, 3);\n    }\n    else\n    {\n        Helper.AddTriangle(2, 1, 0);\n        Helper.AddTriangle(3, 2, 0);\n    }\n}\n\n#define LEFT_BOX(Rect) FBox2D(Rect.Min, Rect.Max - FVector2D(Rect.GetSize().X * 0.5f, 0))\n#define RIGHT_BOX(Rect) FBox2D(Rect.Min + FVector2D(Rect.GetSize().X * 0.5f, 0), Rect.Max)\n#define TOP_BOX(Rect) FBox2D(Rect.Min, Rect.Max - FVector2D(0, Rect.GetSize().Y * 0.5f))\n#define BOTTOM_BOX(Rect) FBox2D(Rect.Min + FVector2D(0, Rect.GetSize().Y * 0.5f), Rect.Max)\n\n#define LEFT_BOX_CW bClockwise?LEFT_BOX(VertRect):RIGHT_BOX(VertRect)\n#define RIGHT_BOX_CW bClockwise?RIGHT_BOX(VertRect):LEFT_BOX(VertRect)\n#define TOP_BOX_CW bClockwise?TOP_BOX(VertRect):BOTTOM_BOX(VertRect)\n#define BOTTOM_BOX_CW bClockwise?BOTTOM_BOX(VertRect):TOP_BOX(VertRect)\n\n//8 vertex\nstatic void FillRadial180(FVertexHelper& Helper, FBox2D VertRect, EOrigin180 Origin, float Amount, bool bClockwise)\n{\n    switch (Origin)\n    {\n    case EOrigin180::Top:\n        if (Amount <= 0.5f)\n        {\n            FillRadial90(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin90::TopLeft : EOrigin90::TopRight, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial90(Helper, LEFT_BOX_CW, bClockwise ? EOrigin90::TopRight : EOrigin90::TopLeft, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(RIGHT_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n\n    case EOrigin180::Bottom:\n        if (Amount <= 0.5f)\n        {\n            FillRadial90(Helper, LEFT_BOX_CW, bClockwise ? EOrigin90::BottomRight : EOrigin90::BottomLeft, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial90(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin90::BottomLeft : EOrigin90::BottomRight, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(LEFT_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n\n    case EOrigin180::Left:\n        if (Amount <= 0.5f)\n        {\n            FillRadial90(Helper, TOP_BOX_CW, bClockwise ? EOrigin90::BottomLeft : EOrigin90::TopLeft, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial90(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin90::TopLeft : EOrigin90::BottomLeft, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(TOP_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n\n    case EOrigin180::Right:\n        if (Amount <= 0.5f)\n        {\n            FillRadial90(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin90::TopRight : EOrigin90::BottomRight, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial90(Helper, TOP_BOX_CW, bClockwise ? EOrigin90::BottomRight : EOrigin90::TopRight, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(BOTTOM_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n    }\n}\n\n//12 vertex\nstatic void FillRadial360(FVertexHelper& Helper, FBox2D VertRect, EOrigin360 Origin, float Amount, bool bClockwise)\n{\n    switch (Origin)\n    {\n    case EOrigin360::Top:\n        if (Amount < 0.5f)\n        {\n            FillRadial180(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin180::Left : EOrigin180::Right, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial180(Helper, LEFT_BOX_CW, bClockwise ? EOrigin180::Right : EOrigin180::Left, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(RIGHT_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n\n        break;\n\n    case EOrigin360::Bottom:\n        if (Amount < 0.5f)\n        {\n            FillRadial180(Helper, LEFT_BOX_CW, bClockwise ? EOrigin180::Right : EOrigin180::Left, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial180(Helper, RIGHT_BOX_CW, bClockwise ? EOrigin180::Left : EOrigin180::Right, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(LEFT_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n\n    case EOrigin360::Left:\n        if (Amount < 0.5f)\n        {\n            FillRadial180(Helper, TOP_BOX_CW, bClockwise ? EOrigin180::Bottom : EOrigin180::Top, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial180(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin180::Top : EOrigin180::Bottom, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(TOP_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n\n    case EOrigin360::Right:\n        if (Amount < 0.5f)\n        {\n            FillRadial180(Helper, BOTTOM_BOX_CW, bClockwise ? EOrigin180::Top : EOrigin180::Bottom, Amount / 0.5f, bClockwise);\n        }\n        else\n        {\n            FillRadial180(Helper, TOP_BOX_CW, bClockwise ? EOrigin180::Bottom : EOrigin180::Top, (Amount - 0.5f) / 0.5f, bClockwise);\n\n            Helper.AddQuad(BOTTOM_BOX_CW);\n            Helper.AddTriangles(-4);\n        }\n        break;\n    }\n}\n\nFFillMesh::FFillMesh() :\n    Method(EFillMethod::None),\n    Origin(0),\n    bClockwise(true),\n    Amount(1)\n{\n}\n\nvoid FFillMesh::OnPopulateMesh(FVertexHelper& Helper)\n{\n    const float clampedAmount = FMath::Clamp<float>(Amount, 0, 1);\n    switch (Method)\n    {\n    case EFillMethod::Horizontal:\n        FillHorizontal(Helper, Helper.ContentRect, Origin, clampedAmount);\n        break;\n\n    case EFillMethod::Vertical:\n        FillVertical(Helper, Helper.ContentRect, Origin, clampedAmount);\n        break;\n\n    case EFillMethod::Radial90:\n        FillRadial90(Helper, Helper.ContentRect, (EOrigin90)Origin, clampedAmount, bClockwise);\n        break;\n\n    case EFillMethod::Radial180:\n        FillRadial180(Helper, Helper.ContentRect, (EOrigin180)Origin, clampedAmount, bClockwise);\n        break;\n\n    case EFillMethod::Radial360:\n        FillRadial360(Helper, Helper.ContentRect, (EOrigin360)Origin, clampedAmount, bClockwise);\n        break;\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/MeshFactory.cpp",
    "content": "#include \"Widgets/Mesh/MeshFactory.h\"\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/PolygonMesh.cpp",
    "content": "#include \"Widgets/Mesh/PolygonMesh.h\"\n\nFPolygonMesh::FPolygonMesh() :\n    LineWidth(0),\n    LineColor(FColor::Black),\n    bUsePercentPositions(false)\n{\n}\n\nvoid FPolygonMesh::OnPopulateMesh(FVertexHelper& Helper)\n{\n    int32 numVertices = Points.Num();\n    if (numVertices < 3)\n        return;\n\n    const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor;\n\n    FVector2D Size = Helper.ContentRect.GetSize();\n    bool useTexcoords = Texcoords.Num() >= numVertices;\n    for (int32 i = 0; i < numVertices; i++)\n    {\n        FVector2D vec = Points[i];\n        if (bUsePercentPositions)\n            vec *= Size;\n\n        if (useTexcoords)\n        {\n            FVector2D uv = FMath::Lerp(Helper.UVRect.Min, Helper.UVRect.Max, Texcoords[i]);\n            Helper.AddVertex(vec, color, uv);\n        }\n        else\n            Helper.AddVertex(vec, color);\n    }\n\n    // Algorithm \"Ear clipping method\" described here:\n    // -> https://en.wikipedia.org/wiki/Polygon_triangulation\n    //\n    // Implementation inspired by:\n    // -> http://polyk.ivank.net\n    // -> Starling\n\n    TArray<int32> RestIndices;\n    for (int32 i = 0; i < numVertices; ++i)\n        RestIndices.Add(i);\n\n    int32 restIndexPos = 0;\n    int32 numRestIndices = numVertices;\n\n    while (numRestIndices > 3)\n    {\n        bool earFound = false;\n        int32 i0 = RestIndices[restIndexPos % numRestIndices];\n        int32 i1 = RestIndices[(restIndexPos + 1) % numRestIndices];\n        int32 i2 = RestIndices[(restIndexPos + 2) % numRestIndices];\n\n        const FVector2D& a = Points[i0];\n        const FVector2D& b = Points[i1];\n        const FVector2D& c = Points[i2];\n\n        if ((a.Y - b.Y) * (c.X - b.X) + (b.X - a.X) * (c.Y - b.Y) >= 0)\n        {\n            earFound = true;\n            for (int32 i = 3; i < numRestIndices; ++i)\n            {\n                int32 otherIndex = RestIndices[(restIndexPos + i) % numRestIndices];\n                const FVector2D& p = Points[otherIndex];\n\n                if (IsPointInTriangle(p, a, b, c))\n                {\n                    earFound = false;\n                    break;\n                }\n            }\n        }\n\n        if (earFound)\n        {\n            Helper.AddTriangle(i0, i1, i2);\n            RestIndices.RemoveAt((restIndexPos + 1) % numRestIndices);\n\n            numRestIndices--;\n            restIndexPos = 0;\n        }\n        else\n        {\n            restIndexPos++;\n            if (restIndexPos == numRestIndices) break; // no more ears\n        }\n    }\n    Helper.AddTriangle(RestIndices[0], RestIndices[1], RestIndices[2]);\n\n    if (Colors.IsSet())\n        Helper.RepeatColors(Colors.GetValue().GetData(), Colors.GetValue().Num(), 0, Helper.GetVertexCount());\n\n    if (LineWidth > 0)\n        DrawOutline(Helper);\n}\n\nvoid FPolygonMesh::DrawOutline(FVertexHelper& Helper)\n{\n    int32 numVertices = Points.Num();\n    int32 k = Helper.GetVertexCount();\n    int32 start = k - numVertices;\n    for (int32 i = 0; i < numVertices; i++)\n    {\n        const FVector2D& p0 = Helper.Vertices[start + i].Position;\n        FVector2D p1;\n        if (i < numVertices - 1)\n            p1 = Helper.Vertices[start + i + 1].Position;\n        else\n            p1 = Helper.Vertices[start].Position;\n\n        FVector2D widthVector(p1.Y - p0.Y, p0.X - p1.X);\n        widthVector.Normalize();\n\n        Helper.AddVertex(p0 - widthVector * LineWidth * 0.5f, LineColor);\n        Helper.AddVertex(p0 + widthVector * LineWidth * 0.5f, LineColor);\n        Helper.AddVertex(p1 - widthVector * LineWidth * 0.5f, LineColor);\n        Helper.AddVertex(p1 + widthVector * LineWidth * 0.5f, LineColor);\n\n        k += 4;\n        Helper.AddTriangle(k - 4, k - 3, k - 1);\n        Helper.AddTriangle(k - 4, k - 1, k - 2);\n\n        //joint\n        if (i != 0)\n        {\n            Helper.AddTriangle(k - 6, k - 5, k - 3);\n            Helper.AddTriangle(k - 6, k - 3, k - 4);\n        }\n        if (i == numVertices - 1)\n        {\n            start += numVertices;\n            Helper.AddTriangle(k - 2, k - 1, start + 1);\n            Helper.AddTriangle(k - 2, start + 1, start);\n        }\n    }\n}\n\nbool FPolygonMesh::IsPointInTriangle(const FVector2D& p, const FVector2D& a, const FVector2D& b, const FVector2D& c)\n{\n    // From Starling\n    // This algorithm is described well in this article:\n    // http://www.blackpawn.com/texts/pointinpoly/default.html\n\n    float v0x = c.X - a.X;\n    float v0y = c.Y - a.Y;\n    float v1x = b.X - a.X;\n    float v1y = b.Y - a.Y;\n    float v2x = p.X - a.X;\n    float v2y = p.Y - a.Y;\n\n    float dot00 = v0x * v0x + v0y * v0y;\n    float dot01 = v0x * v1x + v0y * v1y;\n    float dot02 = v0x * v2x + v0y * v2y;\n    float dot11 = v1x * v1x + v1y * v1y;\n    float dot12 = v1x * v2x + v1y * v2y;\n\n    float invDen = 1.0f / (dot00 * dot11 - dot01 * dot01);\n    float u = (dot11 * dot02 - dot01 * dot12) * invDen;\n    float v = (dot00 * dot12 - dot01 * dot02) * invDen;\n\n    return (u >= 0) && (v >= 0) && (u + v < 1);\n}\n\nbool FPolygonMesh::HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const\n{\n    // Algorithm & implementation thankfully taken from:\n    // -> http://alienryderflex.com/polygon/\n    // inspired by Starling\n    int32 len = Points.Num();\n    int32 i;\n    int32 j = len - 1;\n    bool oddNodes = false;\n    FVector2D ContentSize = ContentRect.GetSize();\n\n    for (i = 0; i < len; ++i)\n    {\n        FVector2D vi = Points[i];\n        FVector2D vj = Points[j];\n        if (bUsePercentPositions)\n        {\n            vi *= ContentSize;\n            vj *= ContentSize;\n        }\n\n        if (((vi.Y < LocalPoint.Y && vj.Y >= LocalPoint.Y) || (vj.Y < LocalPoint.Y && vi.Y >= LocalPoint.Y)) && (vi.X <= LocalPoint.X || vj.X <= LocalPoint.X))\n        {\n            if (vi.X + (LocalPoint.Y - vi.Y) / (vj.Y - vi.Y) * (vj.X - vi.X) < LocalPoint.X)\n                oddNodes = !oddNodes;\n        }\n\n        j = i;\n    }\n\n    return oddNodes;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/RectMesh.cpp",
    "content": "#include \"Widgets/Mesh/RectMesh.h\"\n\nFRectMesh::FRectMesh() :\n    LineWidth(0),\n    LineColor(FColor::Black)\n{\n}\n\nvoid FRectMesh::OnPopulateMesh(FVertexHelper& Helper)\n{\n    const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect;\n    const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor;\n    if (LineWidth == 0)\n    {\n        if (color.A != 0)//optimized\n            Helper.AddQuad(rect, color);\n    }\n    else\n    {\n        FBox2D part;\n        FVector2D Position;\n\n        //left,right\n        part = FBox2D(rect.Min, rect.Min + FVector2D(LineWidth, rect.GetSize().Y));\n        Helper.AddQuad(part, LineColor);\n        Position = FVector2D(rect.Max.X - LineWidth, rect.Min.Y);\n        part = FBox2D(Position, Position + FVector2D(LineWidth, rect.GetSize().Y));\n        Helper.AddQuad(part, LineColor);\n\n        //top, bottom\n        Position = FVector2D(rect.Min.X + LineWidth, rect.Min.Y);\n        part = FBox2D(Position, Position + FVector2D(rect.GetSize().X - LineWidth * 2, LineWidth));\n        Helper.AddQuad(part, LineColor);\n        Position = FVector2D(rect.Min.X + LineWidth, rect.Max.Y - LineWidth);\n        part = FBox2D(Position, Position + FVector2D(rect.GetSize().X - LineWidth * 2, LineWidth));\n        Helper.AddQuad(part, LineColor);\n\n        //middle\n        if (color.A != 0)//optimized\n        {\n            part = FBox2D(rect.Min + LineWidth, rect.Max - LineWidth);\n            if (part.GetSize().GetMin() > 0)\n                Helper.AddQuad(part, color);\n        }\n    }\n\n    if (Colors.IsSet())\n        Helper.RepeatColors(Colors.GetValue().GetData(), Colors.GetValue().Num(), 0, Helper.GetVertexCount());\n\n    Helper.AddTriangles();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/RegularPolygonMesh.cpp",
    "content": "#include \"Widgets/Mesh/RegularPolygonMesh.h\"\n\nFRegularPolygonMesh::FRegularPolygonMesh() :\n    Sides(3),\n    LineWidth(0),\n    LineColor(FColor::Black),\n    Rotation(0)\n{\n}\n\nvoid FRegularPolygonMesh::OnPopulateMesh(FVertexHelper& Helper)\n{\n    if (Distances.Num() > 0)\n        verifyf(Distances.Num() >= Sides, TEXT(\"Distances.Length<Sides\"));\n\n    const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect;\n    const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor;\n\n    float angleDelta = 2 * PI / Sides;\n    float angle = FMath::DegreesToRadians(Rotation);\n    float radius = rect.GetSize().GetMin() *0.5f;\n\n    FVector2D center = FVector2D(radius, radius) + rect.Min;\n    Helper.AddVertex(center, CenterColor.IsSet() ? CenterColor.GetValue() : color);\n    for (int32 i = 0; i < Sides; i++)\n    {\n        float r = radius;\n        if (Distances.Num() > 0)\n            r *= Distances[i];\n        FVector2D vec = center + FVector2D(FMath::Cos(angle) * (r - LineWidth),\n            FMath::Sin(angle) * (r - LineWidth));\n        Helper.AddVertex(vec, color);\n        if (LineWidth > 0)\n        {\n            Helper.AddVertex(vec, LineColor);\n\n            vec = FVector2D(FMath::Cos(angle) * r + center.X,\n                FMath::Sin(angle) * r + center.Y);\n            Helper.AddVertex(vec, LineColor);\n        }\n        angle += angleDelta;\n    }\n\n    if (LineWidth > 0)\n    {\n        int32 tmp = Sides * 3;\n        for (int32 i = 0; i < tmp; i += 3)\n        {\n            if (i != tmp - 3)\n            {\n                Helper.AddTriangle(0, i + 1, i + 4);\n                Helper.AddTriangle(i + 5, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, i + 6, i + 5);\n            }\n            else\n            {\n                Helper.AddTriangle(0, i + 1, 1);\n                Helper.AddTriangle(2, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, 3, 2);\n            }\n        }\n    }\n    else\n    {\n        for (int32 i = 0; i < Sides; i++)\n            Helper.AddTriangle(0, i + 1, (i == Sides - 1) ? 1 : i + 2);\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/RoundedMesh.cpp",
    "content": "#include \"Widgets/Mesh/RoundedRectMesh.h\"\n\nFRoundedRectMesh::FRoundedRectMesh() :\n    LineWidth(0),\n    LineColor(FColor::Black),\n    TopLeftRadius(0),\n    TopRightRadius(0),\n    BottomLeftRadius(0),\n    BottomRightRadius(0)\n{\n}\n\nvoid FRoundedRectMesh::OnPopulateMesh(FVertexHelper& Helper)\n{\n    const FBox2D& rect = DrawRect.IsSet() ? DrawRect.GetValue() : Helper.ContentRect;\n    const FColor& color = FillColor.IsSet() ? FillColor.GetValue() : Helper.VertexColor;\n\n    FVector2D radius = rect.GetSize() * 0.5f;\n    float cornerMaxRadius = radius.GetMin();\n    FVector2D center = radius + rect.Min;\n\n    Helper.AddVertex(center, color);\n\n    int32 cnt = Helper.GetVertexCount();\n    for (int32 i = 0; i < 4; i++)\n    {\n        float cornerRadius = 0;\n        switch (i)\n        {\n        case 0:\n            cornerRadius = BottomRightRadius;\n            break;\n\n        case 1:\n            cornerRadius = BottomLeftRadius;\n            break;\n\n        case 2:\n            cornerRadius = TopLeftRadius;\n            break;\n\n        case 3:\n            cornerRadius = TopRightRadius;\n            break;\n        }\n        cornerRadius = FMath::Min(cornerMaxRadius, cornerRadius);\n\n        FVector2D offset = rect.Min;\n\n        if (i == 0 || i == 3)\n            offset.X = rect.Max.X - cornerRadius * 2;\n        if (i == 0 || i == 1)\n            offset.Y = rect.Max.Y - cornerRadius * 2;\n\n        if (cornerRadius != 0)\n        {\n            int32 partNumSides = FMath::Max(1, FMath::CeilToInt(PI * cornerRadius / 8)) + 1;\n            float angleDelta = PI / 2 / partNumSides;\n            float angle = PI / 2 * i;\n            float startAngle = angle;\n\n            for (int32 j = 1; j <= partNumSides; j++)\n            {\n                if (j == partNumSides)\n                    angle = startAngle + PI / 2;\n                FVector2D v1(offset.X + FMath::Cos(angle) * (cornerRadius - LineWidth) + cornerRadius,\n                    offset.Y + FMath::Sin(angle) * (cornerRadius - LineWidth) + cornerRadius);\n                Helper.AddVertex(v1, color);\n                if (LineWidth != 0)\n                {\n                    Helper.AddVertex(v1, LineColor);\n                    Helper.AddVertex(FVector2D(offset.X + FMath::Cos(angle) * cornerRadius + cornerRadius,\n                        offset.Y + FMath::Sin(angle) * cornerRadius + cornerRadius), LineColor);\n                }\n                angle += angleDelta;\n            }\n        }\n        else\n        {\n            FVector2D v1 = offset;\n            if (LineWidth != 0)\n            {\n                if (i == 0 || i == 3)\n                    offset.X -= LineWidth;\n                else\n                    offset.X += LineWidth;\n                if (i == 0 || i == 1)\n                    offset.Y -= LineWidth;\n                else\n                    offset.Y += LineWidth;\n                Helper.AddVertex(offset, color);\n                Helper.AddVertex(offset, LineColor);\n                Helper.AddVertex(v1, LineColor);\n            }\n            else\n                Helper.AddVertex(v1, color);\n        }\n    }\n    cnt = Helper.GetVertexCount() - cnt;\n\n    if (LineWidth > 0)\n    {\n        for (int32 i = 0; i < cnt; i += 3)\n        {\n            if (i != cnt - 3)\n            {\n                Helper.AddTriangle(0, i + 1, i + 4);\n                Helper.AddTriangle(i + 5, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, i + 6, i + 5);\n            }\n            else\n            {\n                Helper.AddTriangle(0, i + 1, 1);\n                Helper.AddTriangle(2, i + 2, i + 3);\n                Helper.AddTriangle(i + 3, 3, 2);\n            }\n        }\n    }\n    else\n    {\n        for (int32 i = 0; i < cnt; i++)\n            Helper.AddTriangle(0, i + 1, (i == cnt - 1) ? 1 : i + 2);\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/Mesh/VertexHelper.cpp",
    "content": "#include \"Widgets/Mesh/VertexHelper.h\"\n\nFVertexHelper::FVertexHelper() :\n    ContentRect(ForceInit),\n    UVRect(ForceInit),\n    VertexColor(FColor::White)\n{\n}\n\nvoid FVertexHelper::Clear()\n{\n    Vertices.Reset();\n}\n\nint32 FVertexHelper::GetVertexCount() const\n{\n    return Vertices.Num();\n}\n\nvoid FVertexHelper::AddVertex(const FVector2D& Position)\n{\n    AddVertex(Position, VertexColor);\n}\n\nvoid FVertexHelper::AddVertex(const FVector2D& Position, const FColor& Color)\n{\n    AddVertex(Position, Color, FMath::Lerp(UVRect.Min, UVRect.Max, (Position - ContentRect.Min) / ContentRect.GetSize()));\n}\n\nvoid FVertexHelper::AddVertex(const FVector2D& Position, const FColor& Color, const FVector2D& TexCoords)\n{\n    FSlateVertex Vertex;\n    Vertex.Position = Position;\n    Vertex.Color = Color;\n    Vertex.TexCoords[0] = TexCoords.X;\n    Vertex.TexCoords[1] = TexCoords.Y;\n    Vertex.TexCoords[2] = 1;\n    Vertex.TexCoords[3] = 1;\n    Vertex.MaterialTexCoords[0] = TexCoords.X;\n    Vertex.MaterialTexCoords[1] = TexCoords.Y;\n    Vertices.Add(Vertex);\n}\n\nvoid FVertexHelper::AddQuad(const FBox2D& VertRect)\n{\n    AddQuad(VertRect, VertexColor);\n}\n\nvoid FVertexHelper::AddQuad(const FBox2D& VertRect, const FColor& Color)\n{\n    AddVertex(FVector2D(VertRect.Min.X, VertRect.Max.Y), Color);\n    AddVertex(FVector2D(VertRect.Min.X, VertRect.Min.Y), Color);\n    AddVertex(FVector2D(VertRect.Max.X, VertRect.Min.Y), Color);\n    AddVertex(FVector2D(VertRect.Max.X, VertRect.Max.Y), Color);\n}\n\nvoid FVertexHelper::AddQuad(const FBox2D& VertRect, const FColor& Color, const FBox2D& InUVRect)\n{\n    AddVertex(FVector2D(VertRect.Min.X, VertRect.Max.Y), Color, FVector2D(InUVRect.Min.X, InUVRect.Max.Y));\n    AddVertex(FVector2D(VertRect.Min.X, VertRect.Min.Y), Color, FVector2D(InUVRect.Min.X, InUVRect.Min.Y));\n    AddVertex(FVector2D(VertRect.Max.X, VertRect.Min.Y), Color, FVector2D(InUVRect.Max.X, InUVRect.Min.Y));\n    AddVertex(FVector2D(VertRect.Max.X, VertRect.Max.Y), Color, FVector2D(InUVRect.Max.X, InUVRect.Max.Y));\n}\n\nvoid FVertexHelper::RepeatColors(FColor* Colors, int32 ColorCount, int32 StartIndex, int32 Count)\n{\n    int32 len = FMath::Min(StartIndex + Count, Vertices.Num());\n    int32 k = 0;\n    for (int32 i = StartIndex; i < len; i++)\n    {\n        Vertices[i].Color = Colors[(k++) % ColorCount];\n    }\n}\n\nvoid FVertexHelper::AddTriangle(SlateIndex idx0, SlateIndex idx1, SlateIndex idx2)\n{\n    Triangles.Add(idx0);\n    Triangles.Add(idx1);\n    Triangles.Add(idx2);\n}\n\nvoid FVertexHelper::AddTriangles(const SlateIndex* Indice, int32 IndiceLength, int32 StartVertexIndex)\n{\n    if (StartVertexIndex != 0)\n    {\n        if (StartVertexIndex < 0)\n            StartVertexIndex = Vertices.Num() + StartVertexIndex;\n\n        for (int32 i = 0; i < IndiceLength; i++)\n            Triangles.Add(Indice[i] + StartVertexIndex);\n    }\n    else\n    {\n        Triangles.Append(Indice, IndiceLength);\n    }\n}\n\nvoid FVertexHelper::AddTriangles(int32 StartVertexIndex)\n{\n    int32 cnt = Vertices.Num();\n    if (StartVertexIndex < 0)\n        StartVertexIndex = cnt + StartVertexIndex;\n\n    for (int32 i = StartVertexIndex; i < cnt; i += 4)\n    {\n        Triangles.Add(i);\n        Triangles.Add(i + 1);\n        Triangles.Add(i + 2);\n\n        Triangles.Add(i + 2);\n        Triangles.Add(i + 3);\n        Triangles.Add(i);\n    }\n}\n\nconst FVector2D& FVertexHelper::GetPosition(int32 Index)\n{\n    if (Index < 0)\n        Index = Vertices.Num() + Index;\n\n    return Vertices[Index].Position;\n}\n\nFVector2D FVertexHelper::GetUVAtPosition(const FVector2D& Position, bool bUsePercent)\n{\n    if (bUsePercent)\n        return FMath::Lerp(UVRect.Min, UVRect.Max, Position);\n    else\n        return FMath::Lerp(UVRect.Min, UVRect.Max, (Position - ContentRect.Min) / ContentRect.GetSize());\n}\n\nvoid FVertexHelper::Append(const FVertexHelper& VertexHelper)\n{\n    Vertices += VertexHelper.Vertices;\n    Triangles += VertexHelper.Triangles;\n}\n\nvoid FVertexHelper::Insert(const FVertexHelper& VertexHelper)\n{\n    Vertices.Insert(VertexHelper.Vertices.GetData(), VertexHelper.Vertices.Num(), 0);\n    Triangles.Insert(VertexHelper.Triangles.GetData(), VertexHelper.Triangles.Num(), 0);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/NGraphics.cpp",
    "content": "#include \"Widgets/NGraphics.h\"\n\nFNGraphics::FNGraphics() :\n    Size(ForceInit),\n    Color(FColor::White),\n    Flip(EFlipType::None),\n    Texture(nullptr),\n    UsingAlpha(1),\n    bMeshDirty(false)\n{\n}\n\nFNGraphics::~FNGraphics()\n{\n}\n\nvoid FNGraphics::SetColor(const FColor& InColor)\n{\n    if (Color != InColor)\n    {\n        bMeshDirty = true;\n        Color = InColor;\n    }\n}\n\nvoid FNGraphics::SetFlip(EFlipType InFlip)\n{\n    if (Flip != InFlip)\n    {\n        Flip = InFlip;\n        bMeshDirty = true;\n    }\n}\n\nvoid FNGraphics::SetMeshFactory(const TSharedPtr<IMeshFactory>& InMeshFactory)\n{\n    MeshFactory = InMeshFactory;\n    bMeshDirty = true;\n}\n\nvoid FNGraphics::SetTexture(UNTexture* InTexture)\n{\n    if (InTexture != Texture)\n    {\n        Texture = InTexture;\n        if (InTexture != nullptr)\n        {\n            Brush.SetResourceObject(InTexture->NativeTexture);\n            Brush.SetImageSize(InTexture->GetSize());\n            //static const FSlateBrush* WhiteBrush = FCoreStyle::Get().GetBrush(\"GenericWhiteBox\");\n            ResourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(Brush);\n        }\n        else\n        {\n            Brush.SetResourceObject(nullptr);\n            ResourceHandle = FSlateResourceHandle();\n        }\n        bMeshDirty = true;\n    }\n}\n\nvoid FNGraphics::Paint(const FGeometry& AllottedGeometry,\n    FSlateWindowElementList& OutDrawElements,\n    int32 LayerId,\n    float Alpha,\n    bool bEnabled)\n{\n    if (Size != AllottedGeometry.GetLocalSize())\n    {\n        Size = AllottedGeometry.GetLocalSize();\n        bMeshDirty = true;\n    }\n\n    if (bMeshDirty)\n    {\n        UsingAlpha = Alpha;\n        UpdateMeshNow();\n    }\n    else if (Alpha != UsingAlpha)\n    {\n        UsingAlpha = Alpha;\n        int32 cnt = Vertices.Num();\n        for (int32 i = 0; i < cnt; i++)\n        {\n            Vertices[i].Color.A = (uint8)FMath::Clamp<int32>(FMath::TruncToInt(AlphaBackup[i] * UsingAlpha), 0, 255);\n        }\n    }\n\n    const ESlateDrawEffect DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;\n\n    int32 VerticeLength = Vertices.Num();\n    for (int32 i = 0; i < VerticeLength; i++)\n    {\n        Vertices[i].Position = AllottedGeometry.LocalToAbsolute(PositionsBackup[i]);\n    }\n\n    FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, ResourceHandle, Vertices, Triangles, nullptr, 0, 0, DrawEffects);\n}\n\nvoid FNGraphics::UpdateMeshNow()\n{\n    bMeshDirty = false;\n    Vertices.Reset();\n    Triangles.Reset();\n\n    if (Texture == nullptr || !MeshFactory.IsValid())\n        return;\n\n    FVertexHelper Helper;\n    Helper.ContentRect = FBox2D(FVector2D::ZeroVector, Size);\n    Helper.UVRect = Texture->UVRect;\n    Helper.TextureSize = Texture->GetSize();\n    if (Flip != EFlipType::None)\n    {\n        if (Flip == EFlipType::Horizontal || Flip == EFlipType::Both)\n        {\n            float tmp = Helper.UVRect.Min.X;\n            Helper.UVRect.Min.X = Helper.UVRect.Max.X;\n            Helper.UVRect.Max.X = tmp;\n        }\n        if (Flip == EFlipType::Vertical || Flip == EFlipType::Both)\n        {\n            float tmp = Helper.UVRect.Min.Y;\n            Helper.UVRect.Min.Y = Helper.UVRect.Max.Y;\n            Helper.UVRect.Max.Y = tmp;\n        }\n    }\n    Helper.VertexColor = Color;\n    MeshFactory->OnPopulateMesh(Helper);\n\n    int32 vertCount = Helper.GetVertexCount();\n    if (vertCount == 0)\n        return;\n\n    if (Texture->bRotated)\n    {\n        float xMin = Texture->UVRect.Min.X;\n        float yMin = Texture->UVRect.Min.Y;\n        float xMax = Texture->UVRect.Max.X;\n        float yMax = Texture->UVRect.Max.Y;\n        for (int32 i = 0; i < vertCount; i++)\n        {\n            auto& vec = Helper.Vertices[i].TexCoords;\n            float tmp = vec[1];\n            vec[1] = yMin + xMax - vec[0];\n            vec[0] = xMin + tmp - yMin;\n        }\n    }\n\n    AlphaBackup.SetNum(vertCount, false);\n    PositionsBackup.SetNum(vertCount, false);\n\n    for (int32 i = 0; i < vertCount; i++)\n    {\n        FSlateVertex& Vertex = Helper.Vertices[i];\n\n        AlphaBackup[i] = Vertex.Color.A;\n        Vertex.Color.A = (uint8)FMath::Clamp<int32>(FMath::TruncToInt(Vertex.Color.A * UsingAlpha), 0, 255),\n\n        PositionsBackup[i] = Vertex.Position;\n    }\n\n    Vertices += Helper.Vertices;\n    Triangles += Helper.Triangles;\n}\n\nvoid FNGraphics::PopulateDefaultMesh(FVertexHelper& Helper)\n{\n    FBox2D rect = Texture->GetDrawRect(Helper.ContentRect);\n\n    Helper.AddQuad(rect, Helper.VertexColor, Helper.UVRect);\n    Helper.AddTriangles();\n}\n\nvoid FNGraphics::AddReferencedObjects(FReferenceCollector& Collector)\n{\n    if (Texture != nullptr)\n        Collector.AddReferencedObject(Texture);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/NTextFormat.cpp",
    "content": "#include \"Widgets/NTextFormat.h\"\n#include \"UI/UIConfig.h\"\n#include \"UI/UIPackage.h\"\n\nFNTextFormat::FNTextFormat() :\n    Size(12),\n    Color(FColor::White),\n    bBold(false),\n    bItalic(false),\n    bUnderline(false),\n    LineSpacing(3),\n    LetterSpacing(0),\n    Align(EAlignType::Left),\n    VerticalAlign(EVerticalAlignType::Top),\n    OutlineColor(FColor::Black),\n    OutlineSize(0),\n    ShadowColor(FColor::Black),\n    ShadowOffset(0, 0)\n{\n\n}\n\nbool FNTextFormat::EqualStyle(const FNTextFormat& AnotherFormat) const\n{\n    return Size == AnotherFormat.Size && Color == AnotherFormat.Color\n        && bBold == AnotherFormat.bBold && bUnderline == AnotherFormat.bUnderline\n        && bItalic == AnotherFormat.bItalic\n        && Align == AnotherFormat.Align;\n}\n\nFTextBlockStyle FNTextFormat::GetStyle() const\n{\n    FTextBlockStyle Style;\n\n    const FString& FontFace = Face.IsEmpty() ? FUIConfig::Config.DefaultFont : Face;\n    if (!FontFace.StartsWith(\"ui://\"))\n    {\n        const UObject* Font = UUIPackageStatic::Get().Fonts.FindRef(FontFace);\n        if (Font != nullptr)\n        {\n            FSlateFontInfo SlateFont(Font, Size * 0.75f);\n            SlateFont.OutlineSettings.OutlineSize = OutlineSize;\n            SlateFont.OutlineSettings.OutlineColor = OutlineColor;\n            Style.SetFont(SlateFont);\n        }\n        else\n        {\n            FSlateFontInfo SlateFont = FCoreStyle::GetDefaultFontStyle(*FontFace, Size * 0.75f);\n            SlateFont.OutlineSettings.OutlineSize = OutlineSize;\n            SlateFont.OutlineSettings.OutlineColor = OutlineColor;\n            Style.SetFont(SlateFont);\n        }\n    }\n\n    Style.SetColorAndOpacity(FSlateColor(FLinearColor(Color)));\n    Style.SetShadowOffset(ShadowOffset);\n    Style.SetShadowColorAndOpacity(ShadowColor);\n\n    return MoveTemp(Style);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/NTexture.cpp",
    "content": "#include \"Widgets/NTexture.h\"\n#include \"FairyApplication.h\"\n\nUNTexture* UNTexture::WhiteTexture = nullptr;\n\nUNTexture* UNTexture::GetWhiteTexture()\n{\n    if (WhiteTexture == nullptr)\n    {\n        UTexture2D* NativeTexture = UTexture2D::CreateTransient(2, 2);\n        uint8* MipData = (uint8*)NativeTexture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);\n        for (int32 i = 0; i < 16; i++)\n            *(MipData + i) = 255;\n        NativeTexture->PlatformData->Mips[0].BulkData.Unlock();\n#if WITH_EDITORONLY_DATA\n        NativeTexture->CompressionNone = true;\n        NativeTexture->MipGenSettings = TMGS_NoMipmaps;\n#endif // WITH_EDITORONLY_DATA\n        NativeTexture->CompressionSettings = TC_Default;\n        NativeTexture->UpdateResource();\n\n        WhiteTexture = NewObject<UNTexture>();\n        WhiteTexture->AddToRoot();\n        WhiteTexture->Init(NativeTexture);\n    }\n\n    return WhiteTexture;\n}\n\nvoid UNTexture::DestroyWhiteTexture()\n{\n    if (WhiteTexture != nullptr)\n    {\n        WhiteTexture->RemoveFromRoot();\n        WhiteTexture = nullptr;\n    }\n}\n\nUNTexture::UNTexture() :\n    UVRect(ForceInit),\n    Region(ForceInit),\n    Offset(ForceInit),\n    OriginalSize(ForceInit)\n{\n\n}\n\nvoid UNTexture::Init(UTexture2D* InNativeTexture)\n{\n    Init(InNativeTexture, 1, 1);\n}\n\nvoid UNTexture::Init(UTexture2D* InNativeTexture, float ScaleX, float ScaleY)\n{\n    NativeTexture = InNativeTexture;\n    UVRect = FBox2D(FVector2D::ZeroVector, FVector2D(ScaleX, ScaleY));\n    if (ScaleY < 0)\n    {\n        UVRect.Min.Y = -ScaleY;\n        UVRect.Max.Y = 0;\n    }\n    if (ScaleX < 0)\n    {\n        UVRect.Min.X = -ScaleX;\n        UVRect.Max.X = 0;\n    }\n    if (NativeTexture != nullptr)\n        OriginalSize.Set(NativeTexture->GetSurfaceWidth(), NativeTexture->GetSurfaceHeight());\n    Region = FBox2D(FVector2D::ZeroVector, FVector2D(OriginalSize.X, OriginalSize.Y));\n}\n\nvoid UNTexture::Init(UTexture2D* InNativeTexture, const FBox2D& InRegion)\n{\n    NativeTexture = InNativeTexture;\n    Region = InRegion;\n    Region.bIsValid = true;\n    OriginalSize = Region.GetSize();\n\n    if (NativeTexture != nullptr)\n    {\n        UVRect = FBox2D(FVector2D(Region.Min.X / NativeTexture->GetSurfaceWidth(),\n            Region.Min.Y / NativeTexture->GetSurfaceHeight()),\n            FVector2D(Region.Max.X / NativeTexture->GetSurfaceWidth(),\n                Region.Max.Y / NativeTexture->GetSurfaceHeight()));\n    }\n    else\n        UVRect = FBox2D(FVector2D::ZeroVector, FVector2D(1, 1));\n}\n\nvoid UNTexture::Init(UNTexture* InRoot, const FBox2D& InRegion, bool bInRotated)\n{\n    Root = InRoot;\n    NativeTexture = Root->NativeTexture;\n    bRotated = bInRotated;\n    Region = InRegion;\n    Region.bIsValid = true;\n\n    Region.Min.X += Root->Region.Min.X;\n    Region.Min.Y += Root->Region.Min.Y;\n    FVector2D RootSize = Root->GetSize();\n    UVRect = FBox2D(FVector2D(Region.Min.X * Root->UVRect.GetSize().X / RootSize.X,\n        Region.Min.Y * Root->UVRect.GetSize().Y / RootSize.Y),\n        FVector2D(Region.Max.X * Root->UVRect.GetSize().X / RootSize.X,\n            Region.Max.Y * Root->UVRect.GetSize().Y / RootSize.Y));\n\n    if (bRotated)\n    {\n        FVector2D TmpSize = Region.GetSize();\n        Region.Max.X = Region.Min.X + TmpSize.Y;\n        Region.Max.Y = Region.Min.Y + TmpSize.X;\n\n        TmpSize = UVRect.GetSize();\n        UVRect.Max.X = UVRect.Min.X + TmpSize.Y;\n        UVRect.Max.Y = UVRect.Min.Y + TmpSize.X;\n    }\n    OriginalSize = Region.GetSize();\n}\n\nvoid UNTexture::Init(UNTexture* InRoot, const FBox2D& InRegion, bool bInRotated, const FVector2D& InOriginalSize, const FVector2D& InOffset)\n{\n    Init(InRoot, InRegion, bInRotated);\n\n    OriginalSize = InOriginalSize;\n    Offset = InOffset;\n}\n\nFVector2D UNTexture::GetSize() const\n{\n    return Region.GetSize();\n}\n\nFBox2D UNTexture::GetDrawRect(FBox2D& InDrawRect) const\n{\n    if (OriginalSize == Region.GetSize())\n        return InDrawRect;\n\n    FVector2D Scale = InDrawRect.GetSize() / OriginalSize;\n    return FBox2D(Offset * Scale, (Region.GetSize() + Offset)*Scale);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/SContainer.cpp",
    "content": "\n#include \"Widgets/SContainer.h\"\n#include \"FairyApplication.h\"\n#include \"UI/GObject.h\"\n\nSContainer::SContainer() :\n    Children(this)\n{\n    bCanSupportFocus = false;\n}\n\nvoid SContainer::Construct(const SContainer::FArguments& InArgs)\n{\n    SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject));\n}\n\nvoid SContainer::AddChild(const TSharedRef<SWidget>& SlotWidget)\n{\n    AddChildAt(SlotWidget, Children.Num());\n}\n\nvoid SContainer::AddChildAt(const TSharedRef<SWidget>& SlotWidget, int32 Index)\n{\n    int32 Count = Children.Num();\n    verifyf(Index >= 0 && Index <= Count, TEXT(\"Invalid child index\"));\n\n    if (SlotWidget->GetParentWidget().Get() == this)\n        SetChildIndex(SlotWidget, Index);\n    else\n    {\n        verifyf(!SlotWidget->GetParentWidget().IsValid(), TEXT(\"Cant add a child has parent\"));\n\n        FSlotBase& NewSlot = *new FSlotBase();\n        if (Index == Count)\n            Children.Add(&NewSlot);\n        else\n            Children.Insert(&NewSlot, Index);\n        NewSlot.AttachWidget(SlotWidget);\n\n        UGObject* OnStageObj = SDisplayObject::GetWidgetGObjectIfOnStage(AsShared());\n        if (OnStageObj != nullptr)\n        {\n            OnStageObj->GetApp()->BroadcastEvent(FUIEvents::AddedToStage, SlotWidget);\n        }\n    }\n}\n\nvoid SContainer::SetChildIndex(const TSharedRef<SWidget>& SlotWidget, int32 Index)\n{\n    if (Index >= Children.Num())\n        Index = Children.Num() - 1;\n    int32 OldIndex = GetChildIndex(SlotWidget);\n    verifyf(OldIndex != -1, TEXT(\"Not a child of this container\"));\n    if (OldIndex == Index) return;\n    Children.Move(OldIndex, Index);\n}\n\nvoid SContainer::RemoveChild(const TSharedRef<SWidget>& SlotWidget)\n{\n    int32 Index = GetChildIndex(SlotWidget);\n    RemoveChildAt(Index);\n}\n\nvoid SContainer::RemoveChildAt(int32 Index)\n{\n    verifyf(Index >= 0 && Index < Children.Num(), TEXT(\"Invalid child index\"));\n    TSharedRef<SWidget> SlotWidget = Children[Index].GetWidget();\n\n    UGObject* OnStageObj = SDisplayObject::GetWidgetGObjectIfOnStage(AsShared());\n    if (OnStageObj != nullptr)\n    {\n        OnStageObj->GetApp()->BroadcastEvent(FUIEvents::RemovedFromStage, SlotWidget);\n    }\n\n    Children.RemoveAt(Index);\n}\n\nint32 SContainer::GetChildIndex(const TSharedRef<SWidget>& SlotWidget) const\n{\n    for (int32 SlotIdx = 0; SlotIdx < Children.Num(); ++SlotIdx)\n    {\n        if (SlotWidget == Children[SlotIdx].GetWidget())\n        {\n            return SlotIdx;\n        }\n    }\n\n    return -1;\n}\n\nvoid SContainer::RemoveChildren(int32 BeginIndex, int32 EndIndex)\n{\n    if (EndIndex < 0 || EndIndex >= Children.Num())\n        EndIndex = Children.Num() - 1;\n\n    UGObject* OnStageObj = SDisplayObject::GetWidgetGObjectIfOnStage(AsShared());\n    UFairyApplication* Dispatcher = OnStageObj != nullptr ? OnStageObj->GetApp() : nullptr;\n\n    if (Dispatcher != nullptr || BeginIndex > 0 || EndIndex < Children.Num() - 1)\n    {\n        for (int32 i = BeginIndex; i <= EndIndex; ++i)\n        {\n            if (Dispatcher != nullptr)\n            {\n                TSharedRef<SWidget> SlotWidget = Children[BeginIndex].GetWidget();\n                Dispatcher->BroadcastEvent(FUIEvents::RemovedFromStage, SlotWidget);\n            }\n            Children.RemoveAt(BeginIndex);\n        }\n    }\n    else\n        Children.Empty();\n}\n\nint32 SContainer::NumChildren() const\n{\n    return Children.Num();\n}\n\nvoid SContainer::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n    if (Children.Num() > 0)\n    {\n        SDisplayObject::bMindVisibleOnly = true;\n\n        for (int32 ChildIndex = 0; ChildIndex < Children.Num(); ++ChildIndex)\n        {\n            const FSlotBase& CurChild = Children[ChildIndex];\n            const TSharedRef<SWidget>& CurWidget = CurChild.GetWidget();\n            if (ArrangedChildren.Accepts(CurWidget->GetVisibility()))\n                ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(\n                    CurWidget, FVector2D::ZeroVector, CurWidget.Get().GetDesiredSize()\n                ));\n        }\n\n        SDisplayObject::bMindVisibleOnly = false;\n    }\n}\n\nint32 SContainer::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    FArrangedChildren ArrangedChildren(EVisibility::Visible);\n    ArrangeChildren(AllottedGeometry, ArrangedChildren);\n\n    // Because we paint multiple children, we must track the maximum layer id that they produced in case one of our parents\n    // wants to an overlay for all of its contents.\n    int32 MaxLayerId = LayerId;\n\n    const bool bForwardedEnabled = ShouldBeEnabled(bParentEnabled);\n\n    const FPaintArgs NewArgs = Args.WithNewParent(this);\n\n    for (int32 ChildIndex = 0; ChildIndex < ArrangedChildren.Num(); ++ChildIndex)\n    {\n        FArrangedWidget& CurWidget = ArrangedChildren[ChildIndex];\n\n        //if (!IsChildWidgetCulled(MyCullingRect, CurWidget))\n        {\n            const int32 CurWidgetsMaxLayerId = CurWidget.Widget->Paint(NewArgs, CurWidget.Geometry, MyCullingRect, OutDrawElements, MaxLayerId + 1, InWidgetStyle, bForwardedEnabled);\n\n            MaxLayerId = FMath::Max(MaxLayerId, CurWidgetsMaxLayerId);\n        }\n        //else\n        {\n\n        }\n    }\n\n    return MaxLayerId;\n}\n\nFChildren* SContainer::GetChildren()\n{\n    return &Children;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/SDisplayObject.cpp",
    "content": "#include \"Widgets/SDisplayObject.h\"\n#include \"FairyApplication.h\"\n#include \"Engine/GameViewportClient.h\"\n#include \"UI/GObject.h\"\n\nbool SDisplayObject::bMindVisibleOnly = false;\nFNoChildren SDisplayObject::NoChildrenInstance;\nFName SDisplayObject::SDisplayObjectTag(\"SDisplayObjectTag\");\n\nSDisplayObject::SDisplayObject() :\n    bVisible(true),\n    bInteractable(true),\n    bTouchable(true),\n    bOpaque(true),\n    Size(ForceInit)\n{\n    SetCanTick(false);\n    bCanSupportFocus = false;\n}\n\nvoid SDisplayObject::Construct(const SDisplayObject::FArguments& InArgs)\n{\n    GObject = InArgs._GObject;\n    SetTag(InArgs._Tag);\n}\n\nconst FVector2D& SDisplayObject::GetPosition() const\n{\n    if (!GetRenderTransform().IsSet())\n        return FVector2D::ZeroVector;\n    else\n        return GetRenderTransform()->GetTranslation();\n}\n\nvoid SDisplayObject::SetPosition(const FVector2D& InPosition)\n{\n    if (!GetRenderTransform().IsSet())\n        SetRenderTransform(FSlateRenderTransform(InPosition));\n    else\n        SetRenderTransform(\n            FSlateRenderTransform(GetRenderTransform()->GetMatrix(), InPosition));\n}\n\nvoid SDisplayObject::SetX(float InX)\n{\n    if (!GetRenderTransform().IsSet())\n        SetRenderTransform(FSlateRenderTransform(FVector2D(InX, 0)));\n    else\n        SetRenderTransform(\n            FSlateRenderTransform(GetRenderTransform()->GetMatrix(),\n                FVector2D(InX, GetRenderTransform()->GetTranslation().Y)));\n}\n\nvoid SDisplayObject::SetY(float InY)\n{\n    if (!GetRenderTransform().IsSet())\n        SetRenderTransform(FSlateRenderTransform(FVector2D(0, InY)));\n    else\n        SetRenderTransform(\n            FSlateRenderTransform(GetRenderTransform()->GetMatrix(),\n                FVector2D(GetRenderTransform()->GetTranslation().X, InY)));\n}\n\nvoid SDisplayObject::SetSize(const FVector2D& InSize)\n{\n    if (Size != InSize)\n    {\n        Size = InSize;\n        Invalidate(EInvalidateWidget::LayoutAndVolatility);\n    }\n}\n\nvoid SDisplayObject::SetVisible(bool bInVisible)\n{\n    if (bVisible != bInVisible)\n    {\n        bVisible = bInVisible;\n        UpdateVisibilityFlags();\n    }\n}\n\nvoid SDisplayObject::SetTouchable(bool bInTouchable)\n{\n    if (bTouchable != bInTouchable)\n    {\n        bTouchable = bInTouchable;\n        UpdateVisibilityFlags();\n    }\n}\n\nvoid SDisplayObject::SetOpaque(bool bInOpaque)\n{\n    if (bOpaque != bInOpaque)\n    {\n        bOpaque = bInOpaque;\n        UpdateVisibilityFlags();\n    }\n}\n\nvoid SDisplayObject::SetInteractable(bool bInInteractable)\n{\n    if (bInteractable != bInInteractable)\n    {\n        bInteractable = bInInteractable;\n        UpdateVisibilityFlags();\n    }\n}\n\nvoid SDisplayObject::UpdateVisibilityFlags()\n{\n    bool HitTestFlag = bInteractable && bTouchable;\n    if (!bVisible)\n        SetVisibility(EVisibility::Collapsed);\n    else if (!HitTestFlag)\n        SetVisibility(EVisibility::HitTestInvisible);\n    else  if (GObject.IsValid() && GObject->GetHitArea() != nullptr)\n        Visibility.BindRaw(this, &SDisplayObject::GetVisibilityFlags);\n    else if (!bOpaque)\n        SetVisibility(EVisibility::SelfHitTestInvisible);\n    else\n        SetVisibility(EVisibility::All);\n}\n\nEVisibility SDisplayObject::GetVisibilityFlags() const\n{\n    if (!bMindVisibleOnly && GObject.IsValid() && GObject->GetHitArea() != nullptr)\n    {\n        FVector2D Pos = GObject->GetApp()->GetTouchPosition();\n        Pos = GObject->GlobalToLocal(Pos);\n        FBox2D ContentRect(FVector2D::ZeroVector, GObject->GetSize());\n\n        if (!ContentRect.IsInside(Pos))\n            return EVisibility::HitTestInvisible;\n\n        FVector2D LayoutScaleMultiplier = GObject->GetSize() / GObject->SourceSize;\n        if (LayoutScaleMultiplier.ContainsNaN())\n            LayoutScaleMultiplier.Set(1, 1);\n\n        if (!GObject->GetHitArea()->HitTest(ContentRect, LayoutScaleMultiplier, Pos))\n            return EVisibility::HitTestInvisible;\n        else\n            return EVisibility::All;\n    }\n    else\n    {\n        if (!bOpaque)\n            return EVisibility::SelfHitTestInvisible;\n        else\n            return EVisibility::All;\n    }\n}\n\nFVector2D SDisplayObject::ComputeDesiredSize(float) const\n{\n    return Size;\n}\n\nFChildren* SDisplayObject::GetChildren()\n{\n    return &NoChildrenInstance;\n}\n\nvoid SDisplayObject::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n}\n\nint32 SDisplayObject::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    return LayerId;\n}\n\nFReply SDisplayObject::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        return Obj->GetApp()->OnWidgetMouseButtonDown(AsShared(), MyGeometry, MouseEvent);\n    else\n        return FReply::Unhandled();\n}\n\nFReply SDisplayObject::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        return Obj->GetApp()->OnWidgetMouseButtonUp(AsShared(), MyGeometry, MouseEvent);\n    else\n        return FReply::Unhandled();\n}\n\nFReply SDisplayObject::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        return Obj->GetApp()->OnWidgetMouseMove(AsShared(), MyGeometry, MouseEvent);\n    else\n        return FReply::Unhandled();\n}\n\nFReply SDisplayObject::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        return Obj->GetApp()->OnWidgetMouseButtonDoubleClick(AsShared(), MyGeometry, MouseEvent);\n    else\n        return FReply::Unhandled();\n}\n\nvoid SDisplayObject::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        Obj->GetApp()->OnWidgetMouseEnter(AsShared(), MyGeometry, MouseEvent);\n}\n\nvoid SDisplayObject::OnMouseLeave(const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        Obj->GetApp()->OnWidgetMouseLeave(AsShared(), MouseEvent);\n}\n\nFReply SDisplayObject::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)\n{\n    UGObject* Obj = GetWidgetGObject(AsShared());\n    if (Obj != nullptr)\n        return Obj->GetApp()->OnWidgetMouseWheel(AsShared(), MyGeometry, MouseEvent);\n    else\n        return FReply::Unhandled();\n}\n\nbool SDisplayObject::IsWidgetOnStage(const TSharedPtr<SWidget>& InWidget)\n{\n    TSharedPtr<SWidget> Ptr = InWidget;\n    while (Ptr.IsValid())\n    {\n        if (Ptr->Advanced_IsWindow())\n            return true;\n\n        Ptr = Ptr->GetParentWidget();\n    }\n\n    return false;\n}\n\nUGObject* SDisplayObject::GetWidgetGObject(const TSharedPtr<SWidget>& InWidget)\n{\n    TSharedPtr<SWidget> Ptr = InWidget;\n    while (Ptr.IsValid() && !Ptr->Advanced_IsWindow())\n    {\n        if (Ptr->GetTag() == SDisplayObject::SDisplayObjectTag)\n        {\n            const TWeakObjectPtr<UGObject>& ObjPtr = StaticCastSharedPtr<SDisplayObject>(Ptr)->GObject;\n            if (ObjPtr.IsValid())\n                return ObjPtr.Get();\n        }\n\n        Ptr = Ptr->GetParentWidget();\n    }\n\n    return nullptr;\n}\n\nUGObject* SDisplayObject::GetWidgetGObjectIfOnStage(const TSharedPtr<SWidget>& InWidget)\n{\n    TSharedPtr<SWidget> Ptr = InWidget;\n    UGObject* Result = nullptr;\n    while (Ptr.IsValid())\n    {\n        if (Ptr->Advanced_IsWindow())\n            return Result;\n\n        if (Result == nullptr && Ptr->GetTag() == SDisplayObject::SDisplayObjectTag)\n            Result = StaticCastSharedPtr<SDisplayObject>(Ptr)->GObject.Get();\n\n        Ptr = Ptr->GetParentWidget();\n    }\n\n    return nullptr;\n}\n\nvoid SDisplayObject::GetWidgetPathToRoot(const TSharedRef<SWidget>& InWidget, TArray<UGObject*>& OutArray)\n{\n    TSharedPtr<SWidget> Ptr = InWidget;\n    while (Ptr.IsValid() && !Ptr->Advanced_IsWindow())\n    {\n        if (Ptr->GetTag() == SDisplayObject::SDisplayObjectTag)\n        {\n            const TWeakObjectPtr<UGObject>& ObjPtr = StaticCastSharedPtr<SDisplayObject>(Ptr)->GObject;\n            if (ObjPtr.IsValid())\n                OutArray.Add(ObjPtr.Get());\n        }\n\n        Ptr = Ptr->GetParentWidget();\n    }\n}\n\nvoid SDisplayObject::GetWidgetDescendants(const TSharedRef<SWidget>& InWidget, TArray<UGObject*>& OutArray)\n{\n    if (InWidget->GetTag() == SDisplayObject::SDisplayObjectTag)\n    {\n        const TSharedRef<SDisplayObject>& DisplayObject = StaticCastSharedRef<SDisplayObject>(InWidget);\n        if (DisplayObject->GObject.IsValid())\n            OutArray.Add(DisplayObject->GObject.Get());\n    }\n\n    FChildren* Children = InWidget->GetChildren();\n    for (int32 SlotIdx = 0; SlotIdx < Children->Num(); ++SlotIdx)\n    {\n        GetWidgetDescendants(Children->GetChildAt(SlotIdx), OutArray);\n    }\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/SFImage.cpp",
    "content": "#include \"Widgets/SFImage.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/Mesh/VertexHelper.h\"\n#include \"UI/FieldTypes.h\"\n\nSFImage::SFImage() :\n    bScaleByTile(false),\n    TextureScale(1, 1),\n    TileGridIndice(0)\n{\n    Graphics.SetMeshFactory(MakeShared<FMeshFactory>(this));\n}\n\nvoid SFImage::Construct(const FArguments& InArgs)\n{\n    SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject));\n}\n\nvoid SFImage::SetTexture(UNTexture* InTexture)\n{\n    Graphics.SetTexture(InTexture);\n\n    if (InTexture != nullptr && Size.IsZero())\n    {\n        SetSize(InTexture->GetSize());\n        Invalidate(EInvalidateWidget::LayoutAndVolatility);\n    }\n}\n\nvoid SFImage::SetNativeSize()\n{\n    if (Graphics.GetTexture() != nullptr)\n        SetSize(Graphics.GetTexture()->GetSize());\n}\n\nvoid SFImage::SetScale9Grid(const TOptional<FBox2D>& InGridRect)\n{\n    Scale9Grid = InGridRect;\n}\n\nvoid SFImage::SetScaleByTile(bool bInScaleByTile)\n{\n    if (bScaleByTile != bInScaleByTile)\n    {\n        bScaleByTile = bInScaleByTile;\n        Graphics.SetMeshDirty();\n    }\n}\n\nvoid SFImage::SetTileGridIndice(int32 InTileGridIndex)\n{\n    if (TileGridIndice != InTileGridIndex)\n    {\n        TileGridIndice = InTileGridIndex;\n        Graphics.SetMeshDirty();\n    }\n}\n\nEFillMethod SFImage::GetFillMethod() const\n{\n    return FillMesh.IsValid() ? FillMesh->Method : EFillMethod::None;\n}\n\nvoid SFImage::SetFillMethod(EFillMethod InMethod)\n{\n    if (!FillMesh.IsValid())\n    {\n        if (InMethod == EFillMethod::None)\n            return;\n\n        FillMesh = MakeUnique<FFillMesh>();\n    }\n\n    if (FillMesh->Method != InMethod)\n    {\n        FillMesh->Method = InMethod;\n        Graphics.SetMeshDirty();\n    }\n}\n\nint32 SFImage::GetFillOrigin() const\n{\n    return FillMesh.IsValid() ? FillMesh->Origin : 0;\n}\n\nvoid SFImage::SetFillOrigin(int32 InOrigin)\n{\n    if (!FillMesh.IsValid())\n        FillMesh = MakeUnique<FFillMesh>();\n\n    if (FillMesh->Origin != InOrigin)\n    {\n        FillMesh->Origin = InOrigin;\n        Graphics.SetMeshDirty();\n    }\n}\n\nbool SFImage::IsFillClockwise() const\n{\n    return FillMesh.IsValid() ? FillMesh->bClockwise : true;\n}\n\nvoid SFImage::SetFillClockwise(bool bInClockwise)\n{\n    if (!FillMesh.IsValid())\n        FillMesh = MakeUnique<FFillMesh>();\n\n    if (FillMesh->bClockwise != bInClockwise)\n    {\n        FillMesh->bClockwise = bInClockwise;\n        Graphics.SetMeshDirty();\n    }\n}\n\nfloat SFImage::GetFillAmount() const\n{\n    return FillMesh.IsValid() ? FillMesh->Amount : 0;\n}\n\nvoid SFImage::SetFillAmount(float InAmount)\n{\n    if (!FillMesh.IsValid())\n        FillMesh = MakeUnique<FFillMesh>();\n\n    if (FillMesh->Amount != InAmount)\n    {\n        FillMesh->Amount = InAmount;\n        Graphics.SetMeshDirty();\n    }\n}\n\nint32 SFImage::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    const bool bIsEnabled = ShouldBeEnabled(bParentEnabled);\n    const_cast<SFImage*>(this)->Graphics.Paint(AllottedGeometry, OutDrawElements, LayerId,\n        InWidgetStyle.GetColorAndOpacityTint().A, bIsEnabled);\n    return LayerId;\n}\n\nvoid SFImage::OnPopulateMesh(FVertexHelper& Helper)\n{\n    if (FillMesh.IsValid() && FillMesh->Method != EFillMethod::None)\n    {\n        FillMesh->OnPopulateMesh(Helper);\n    }\n    else if (bScaleByTile)\n    {\n        UNTexture* Texture = Graphics.GetTexture();\n        if (Texture->Root == Texture\n            && Texture->NativeTexture != nullptr\n            && Texture->NativeTexture->AddressX == TextureAddress::TA_Mirror\n            && Texture->NativeTexture->AddressY == TextureAddress::TA_Mirror)\n        {\n            FBox2D UVRect = Helper.UVRect;\n            UVRect.Max = UVRect.Min + UVRect.GetSize() * Helper.ContentRect.GetSize() / Texture->GetSize() * TextureScale;\n\n            Helper.AddQuad(Helper.ContentRect, Helper.VertexColor, UVRect);\n            Helper.AddTriangles();\n        }\n        else\n        {\n            FBox2D ContentRect = Helper.ContentRect;\n            ContentRect.Max = ContentRect.Min + ContentRect.GetSize() * TextureScale;\n\n            TileFill(Helper, ContentRect, Helper.UVRect, Graphics.GetTexture()->GetSize());\n            Helper.AddTriangles();\n        }\n    }\n    else if (Scale9Grid.IsSet())\n    {\n        SliceFill(Helper);\n    }\n    else\n        Graphics.PopulateDefaultMesh(Helper);\n}\n\nvoid SFImage::SliceFill(FVertexHelper& Helper)\n{\n    const SlateIndex TRIANGLES_9_GRID[] = {\n        4, 0, 1, 1, 5, 4,\n        5, 1, 2, 2, 6, 5,\n        6, 2, 3, 3, 7, 6,\n        8, 4, 5, 5, 9, 8,\n        9, 5, 6, 6, 10, 9,\n        10, 6, 7, 7, 11, 10,\n        12, 8, 9, 9, 13, 12,\n        13, 9, 10, 10, 14, 13,\n        14, 10, 11,\n        11, 15, 14\n    };\n\n    const int32 gridTileIndice[] = { -1, 0, -1, 2, 4, 3, -1, 1, -1 };\n\n    static float gridX[4];\n    static float gridY[4];\n    static float gridTexX[4];\n    static float gridTexY[4];\n\n    UNTexture* Texture = Graphics.GetTexture();\n    FBox2D GridRect = Scale9Grid.GetValue();\n    FBox2D ContentRect = Helper.ContentRect;\n    ContentRect.Max = ContentRect.Min + ContentRect.GetSize() * TextureScale;\n    FBox2D UVRect = Helper.UVRect;\n    FVector2D TextureSize = Texture->GetSize();\n    EFlipType FlipType = Graphics.GetFlip();\n\n    if (FlipType != EFlipType::None)\n    {\n        if (FlipType == EFlipType::Horizontal || FlipType == EFlipType::Both)\n        {\n            GridRect.Min.X = TextureSize.X - GridRect.Max.X;\n            GridRect.Max.X = GridRect.Min.X + GridRect.GetSize().X;\n        }\n\n        if (FlipType == EFlipType::Vertical || FlipType == EFlipType::Both)\n        {\n            GridRect.Min.Y = TextureSize.Y - GridRect.Max.Y;\n            GridRect.Max.Y = GridRect.Min.Y + GridRect.GetSize().Y;\n        }\n    }\n\n    FVector2D Scale = UVRect.GetSize() / TextureSize;\n\n    gridTexX[0] = UVRect.Min.X;\n    gridTexX[1] = UVRect.Min.X + GridRect.Min.X * Scale.X;\n    gridTexX[2] = UVRect.Min.X + GridRect.Max.X * Scale.X;\n    gridTexX[3] = UVRect.Max.X;\n    gridTexY[0] = UVRect.Min.Y;\n    gridTexY[1] = UVRect.Min.Y + GridRect.Min.Y * Scale.Y;\n    gridTexY[2] = UVRect.Min.Y + GridRect.Max.Y * Scale.Y;\n    gridTexY[3] = UVRect.Max.Y;\n\n    if (ContentRect.GetSize().X >= (Scale.X - GridRect.GetSize().X))\n    {\n        gridX[1] = GridRect.Min.X;\n        gridX[2] = ContentRect.GetSize().X - (TextureSize.X - GridRect.Max.X);\n        gridX[3] = ContentRect.GetSize().X;\n    }\n    else\n    {\n        float tmp = GridRect.Min.X / (TextureSize.X - GridRect.Max.X);\n        tmp = ContentRect.GetSize().X * tmp / (1 + tmp);\n        gridX[1] = tmp;\n        gridX[2] = tmp;\n        gridX[3] = ContentRect.GetSize().X;\n    }\n\n    if (ContentRect.GetSize().Y >= (TextureSize.Y - GridRect.GetSize().Y))\n    {\n        gridY[1] = GridRect.Min.Y;\n        gridY[2] = ContentRect.GetSize().Y - (TextureSize.Y - GridRect.Max.Y);\n        gridY[3] = ContentRect.GetSize().Y;\n    }\n    else\n    {\n        float tmp = GridRect.Min.Y / (TextureSize.Y - GridRect.Max.Y);\n        tmp = ContentRect.GetSize().Y * tmp / (1 + tmp);\n        gridY[1] = tmp;\n        gridY[2] = tmp;\n        gridY[3] = ContentRect.GetSize().Y;\n    }\n\n    if (TileGridIndice == 0)\n    {\n        for (int32 cy = 0; cy < 4; cy++)\n        {\n            for (int32 cx = 0; cx < 4; cx++)\n                Helper.AddVertex(FVector2D(gridX[cx] / TextureScale.X, gridY[cy] / TextureScale.Y), Helper.VertexColor, FVector2D(gridTexX[cx], gridTexY[cy]));\n        }\n        Helper.AddTriangles(TRIANGLES_9_GRID, sizeof(TRIANGLES_9_GRID) / sizeof(SlateIndex));\n    }\n    else\n    {\n        FBox2D drawRect;\n        FBox2D texRect;\n        int32 row, col;\n        int32 part;\n\n        for (int32 pii = 0; pii < 9; pii++)\n        {\n            col = pii % 3;\n            row = pii / 3;\n            part = gridTileIndice[pii];\n            drawRect = FBox2D(FVector2D(gridX[col], gridY[row]), FVector2D(gridX[col + 1], gridY[row + 1]));\n            texRect = FBox2D(FVector2D(gridTexX[col], gridTexY[row]), FVector2D(gridTexX[col + 1], gridTexY[row + 1]));\n\n            if (part != -1 && (TileGridIndice & (1 << part)) != 0)\n            {\n                TileFill(Helper, drawRect, texRect,\n                    (part == 0 || part == 1 || part == 4) ? GridRect.GetSize() : drawRect.GetSize());\n            }\n            else\n            {\n                drawRect.Min /= TextureScale;\n                drawRect.Max = drawRect.Min + drawRect.GetSize() * TextureScale;\n\n                Helper.AddQuad(drawRect, Helper.VertexColor, texRect);\n            }\n        }\n\n        Helper.AddTriangles();\n    }\n}\n\nvoid SFImage::TileFill(FVertexHelper& Helper, const FBox2D& ContentRect, const FBox2D& UVRect, const FVector2D& TextureSize)\n{\n    FVector2D cnt = ContentRect.GetSize() / TextureSize;\n    cnt.Set(FMath::CeilToInt(cnt.X), FMath::CeilToInt(cnt.Y));\n    FVector2D tailSize = ContentRect.GetSize() - (cnt - FVector2D(1, 1)) * TextureSize;\n\n    for (int32 i = 0; i < cnt.X; i++)\n    {\n        for (int32 j = 0; j < cnt.Y; j++)\n        {\n            FBox2D UVTmp = UVRect;\n            if (i == cnt.X - 1)\n                UVTmp.Max.X = FMath::Lerp(UVRect.Min.X, UVRect.Max.X, tailSize.X / TextureSize.X);\n            if (j == cnt.Y - 1)\n                UVTmp.Max.Y = FMath::Lerp(UVRect.Min.Y, UVRect.Max.Y, tailSize.Y / TextureSize.Y);\n\n            FVector2D Min = ContentRect.Min + FVector2D(i, j) * TextureSize;\n            FBox2D drawRect = FBox2D(Min,\n                Min + FVector2D(i == (cnt.X - 1) ? tailSize.X : TextureSize.X, j == (cnt.Y - 1) ? tailSize.Y : TextureSize.Y));\n\n            drawRect.Min /= TextureScale;\n            drawRect.Max = drawRect.Min + drawRect.GetSize() / TextureScale;\n\n            Helper.AddQuad(drawRect, Helper.VertexColor, UVTmp);\n        }\n    }\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/SMovieClip.cpp",
    "content": "#include \"Widgets/SMovieClip.h\"\n\nFMovieClipData::FMovieClipData() :\n    Interval(0),\n    RepeatDelay(0),\n    bSwing(false)\n{\n}\n\nvoid FMovieClipData::AddReferencedObjects(FReferenceCollector& Collector)\n{\n    for (auto& Frame : Frames)\n    {\n        if (Frame.Texture != nullptr)\n            Collector.AddReferencedObject(Frame.Texture);\n    }\n}\n\nSMovieClip::SMovieClip() :\n    Frame(0),\n    bPlaying(true),\n    TimeScale(1),\n    Start(0),\n    End(0),\n    Times(0),\n    EndAt(0),\n    Status(0),\n    FrameElapsed(0),\n    bReversed(false),\n    RepeatedCount(0)\n{\n}\n\nvoid SMovieClip::Construct(const FArguments& InArgs)\n{\n    SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject));\n}\n\nvoid SMovieClip::SetClipData(TSharedPtr<FMovieClipData> InData)\n{\n    Data = InData;\n\n    SetScale9Grid(TOptional<FBox2D>());\n    SetScaleByTile(false);\n\n    if (!Data.IsValid())\n    {\n        SetCanTick(false);\n        Graphics.SetTexture(nullptr);\n        return;\n    }\n\n    SetCanTick(bPlaying);\n    int32 frameCount = Data->Frames.Num();\n\n    if (End == -1 || End > frameCount - 1)\n        End = frameCount - 1;\n    if (EndAt == -1 || EndAt > frameCount - 1)\n        EndAt = frameCount - 1;\n\n    if (Frame < 0 || Frame > frameCount - 1)\n        Frame = frameCount - 1;\n\n    FrameElapsed = 0;\n    RepeatedCount = 0;\n    bReversed = false;\n\n    DrawFrame();\n}\n\nvoid SMovieClip::SetPlaying(bool InPlaying)\n{\n    bPlaying = InPlaying;\n    SetCanTick(bPlaying && Data.IsValid());\n}\n\nvoid SMovieClip::SetTimeScale(float InTimeScale)\n{\n    TimeScale = InTimeScale;\n}\n\nvoid SMovieClip::SetFrame(int32 InFrame)\n{\n    if (!Data.IsValid())\n    {\n        Frame = InFrame;\n        return;\n    }\n\n    int32 frameCount = Data->Frames.Num();\n\n    if (InFrame >= frameCount)\n        InFrame = frameCount - 1;\n\n    Frame = InFrame;\n    FrameElapsed = 0;\n    DrawFrame();\n}\n\nvoid SMovieClip::Advance(float Time)\n{\n    if (!Data.IsValid())\n        return;\n\n    int32 frameCount = Data->Frames.Num();\n    if (frameCount == 0)\n        return;\n\n    int32 beginFrame = Frame;\n    bool beginReversed = bReversed;\n    float backupTime = Time;\n    while (true)\n    {\n        float tt = Data->Interval + Data->Frames[Frame].AddDelay;\n        if (Frame == 0 && RepeatedCount > 0)\n            tt += Data->RepeatDelay;\n        if (Time < tt)\n        {\n            FrameElapsed = 0;\n            break;\n        }\n\n        Time -= tt;\n\n        if (Data->bSwing)\n        {\n            if (bReversed)\n            {\n                Frame--;\n                if (Frame <= 0)\n                {\n                    Frame = 0;\n                    RepeatedCount++;\n                    bReversed = !bReversed;\n                }\n            }\n            else\n            {\n                Frame++;\n                if (Frame > frameCount - 1)\n                {\n                    Frame = FMath::Max(0, frameCount - 2);\n                    RepeatedCount++;\n                    bReversed = !bReversed;\n                }\n            }\n        }\n        else\n        {\n            Frame++;\n            if (Frame > frameCount - 1)\n            {\n                Frame = 0;\n                RepeatedCount++;\n            }\n        }\n\n        if (Frame == beginFrame && bReversed == beginReversed)\n        {\n            float roundTime = backupTime - Time;\n            Time -= FMath::FloorToInt(Time / roundTime) * roundTime;\n        }\n    }\n}\n\nvoid SMovieClip::SetPlaySettings(int32 InStart, int32 InEnd, int32 InTimes, int32 InEndAt, const FSimpleDelegate& InCompleteCallback)\n{\n    int32 frameCount = Data.IsValid() ? Data->Frames.Num() : 0;\n\n    Start = InStart;\n    End = InEnd;\n    if (End == -1 || End > frameCount - 1)\n        End = frameCount - 1;\n    Times = InTimes;\n    EndAt = InEndAt;\n    if (EndAt == -1)\n        EndAt = End;\n    Status = 0;\n    CompleteCallback = InCompleteCallback;\n\n    SetFrame(InStart);\n}\n\nvoid SMovieClip::DrawFrame()\n{\n    if (Data.IsValid() && Frame < Data->Frames.Num())\n        Graphics.SetTexture(Data->Frames[Frame].Texture);\n}\n\nvoid SMovieClip::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)\n{\n    SFImage::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);\n\n    if (!Data.IsValid() || !bPlaying)\n        return;\n\n    int32 frameCount = Data->Frames.Num();\n    if (frameCount == 0 || Status == 3)\n        return;\n\n    float dt = InDeltaTime;\n    if (TimeScale != 1)\n        dt *= TimeScale;\n\n    FrameElapsed += dt;\n    float tt = Data->Interval + Data->Frames[Frame].AddDelay;\n    if (Frame == 0 && RepeatedCount > 0)\n        tt += Data->RepeatDelay;\n    if (FrameElapsed < tt)\n        return;\n\n    FrameElapsed -= tt;\n    if (FrameElapsed > Data->Interval)\n        FrameElapsed = Data->Interval;\n\n    if (Data->bSwing)\n    {\n        if (bReversed)\n        {\n            Frame--;\n            if (Frame <= 0)\n            {\n                Frame = 0;\n                RepeatedCount++;\n                bReversed = !bReversed;\n            }\n        }\n        else\n        {\n            Frame++;\n            if (Frame > frameCount - 1)\n            {\n                Frame = FMath::Max(0, frameCount - 2);\n                RepeatedCount++;\n                bReversed = !bReversed;\n            }\n        }\n    }\n    else\n    {\n        Frame++;\n        if (Frame > frameCount - 1)\n        {\n            Frame = 0;\n            RepeatedCount++;\n        }\n    }\n\n    if (Status == 1) //new loop\n    {\n        Frame = Start;\n        FrameElapsed = 0;\n        Status = 0;\n    }\n    else if (Status == 2) //ending\n    {\n        Frame = EndAt;\n        FrameElapsed = 0;\n        Status = 3; //ended\n\n        CompleteCallback.Execute();\n    }\n    else\n    {\n        if (Frame == End)\n        {\n            if (Times > 0)\n            {\n                Times--;\n                if (Times == 0)\n                    Status = 2; //ending\n                else\n                    Status = 1; //new loop\n            }\n            else if (Start != 0)\n                Status = 1; //new loop\n        }\n    }\n\n    DrawFrame();\n}\n"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/SShape.cpp",
    "content": "#include \"Widgets/SShape.h\"\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/Mesh/VertexHelper.h\"\n\nSShape::SShape()\n{\n}\n\nvoid SShape::Construct(const FArguments& InArgs)\n{\n    SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject));\n    Graphics.SetTexture(UNTexture::GetWhiteTexture());\n}\n\nint32 SShape::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    const bool bIsEnabled = ShouldBeEnabled(bParentEnabled);\n    const_cast<SShape*>(this)->Graphics.Paint(AllottedGeometry, OutDrawElements, LayerId,\n        InWidgetStyle.GetColorAndOpacityTint().A, bIsEnabled);\n    return LayerId;\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/STextField.cpp",
    "content": "#include \"Widgets/STextField.h\"\n#include \"Internationalization/BreakIterator.h\"\n#include \"Utils/HTMLParser.h\"\n#include \"Widgets/LoaderRun.h\"\n#include \"Widgets/BitmapFontRun.h\"\n#include \"UI/GObject.h\"\n#include \"UI/UIPackage.h\"\n\nSTextField::STextField() :\n    bHTML(false),\n    AutoSize(EAutoSizeType::None),\n    bSingleLine(false),\n    MaxWidth(0),\n    TextLayout(FSlateTextLayout::Create(this, FTextBlockStyle::GetDefault()))\n{\n    TextLayout->SetLineBreakIterator(FBreakIterator::CreateCharacterBoundaryIterator());\n}\n\nvoid STextField::Construct(const FArguments& InArgs)\n{\n    SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject));\n}\n\nvoid STextField::SetText(const FString& InText, bool bInHTML)\n{\n    const int32 OldLength = Text.Len();\n\n    // Only compare reasonably sized strings, it's not worth checking this\n    // for large blocks of text.\n    if (bHTML == bInHTML && OldLength <= 20)\n    {\n        if (InText.Compare(Text, ESearchCase::CaseSensitive) == 0)\n        {\n            return;\n        }\n    }\n\n    Text = InText;\n    bHTML = bInHTML;\n    TextLayout->DirtyLayout();\n    Invalidate(EInvalidateWidget::LayoutAndVolatility);\n}\n\nvoid STextField::SetAutoSize(EAutoSizeType InAutoSize)\n{\n    if (AutoSize != InAutoSize)\n    {\n        AutoSize = InAutoSize;\n        if (AutoSize == EAutoSizeType::Both)\n        {\n            TextLayout->SetWrappingWidth(0);\n        }\n        else\n        {\n            TextLayout->SetWrappingWidth(Size.X);\n        }\n    }\n}\n\nvoid STextField::SetSingleLine(bool bInSingleLine)\n{\n    if (bSingleLine != bInSingleLine)\n    {\n        bSingleLine = bInSingleLine;\n        TextLayout->DirtyLayout();\n    }\n}\n\nvoid STextField::SetMaxWidth(float InMaxWidth)\n{\n    if (MaxWidth != InMaxWidth)\n    {\n        MaxWidth = InMaxWidth;\n        TextLayout->DirtyLayout();\n    }\n}\n\nFVector2D STextField::GetTextSize()\n{\n    if(TextLayout->IsLayoutDirty())\n        UpdateTextLayout();\n\n    return TextLayout->GetSize();\n}\n\nvoid STextField::SetTextFormat(const FNTextFormat& InFormat)\n{\n    if (&InFormat != &TextFormat)\n        TextFormat = InFormat;\n    TextLayout->DirtyLayout();\n}\n\nFVector2D STextField::ComputeDesiredSize(float LayoutScaleMultiplier) const\n{\n    TextLayout->SetScale(LayoutScaleMultiplier);\n    if (TextLayout->IsLayoutDirty())\n        const_cast<STextField*>(this)->UpdateTextLayout();\n\n    return Size;\n}\n\nFChildren* STextField::GetChildren()\n{\n    return TextLayout->GetChildren();\n}\n\nvoid STextField::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n    TextLayout->ArrangeChildren(AllottedGeometry, ArrangedChildren);\n}\n\nint32 STextField::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    FVector2D AutoScrollValue = FVector2D::ZeroVector; // Scroll to the left\n    if (TextFormat.Align != EAlignType::Left)\n    {\n        const float ActualWidth = TextLayout->GetSize().X;\n        const float VisibleWidth = Size.X;\n        if (VisibleWidth < ActualWidth)\n        {\n            switch (TextFormat.Align)\n            {\n            case EAlignType::Center:\n                AutoScrollValue.X = (ActualWidth - VisibleWidth) * 0.5f; // Scroll to the center\n                break;\n\n            case EAlignType::Right:\n                AutoScrollValue.X = (ActualWidth - VisibleWidth); // Scroll to the right\n                break;\n\n            default:\n                break;\n            }\n        }\n    }\n\n    if (TextFormat.VerticalAlign != EVerticalAlignType::Top)\n    {\n        const float ActualHeight = TextLayout->GetSize().Y;\n        const float VisibleHeight = Size.Y;\n        switch (TextFormat.VerticalAlign)\n        {\n        case EVerticalAlignType::Middle:\n            AutoScrollValue.Y = FMath::CeilToFloat((ActualHeight - VisibleHeight) * .5f);\n            break;\n\n        case EVerticalAlignType::Bottom:\n            AutoScrollValue.Y = FMath::CeilToFloat(ActualHeight - VisibleHeight);\n            break;\n        }\n\n        if (AutoScrollValue.Y > 0)\n            AutoScrollValue.Y = 0;\n    }\n\n    TextLayout->SetVisibleRegion(Size, AutoScrollValue * TextLayout->GetScale());\n    TextLayout->UpdateIfNeeded();\n\n    LayerId = TextLayout->OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, ShouldBeEnabled(bParentEnabled));\n\n    return LayerId;\n}\n\nvoid STextField::UpdateTextLayout()\n{\n    TextLayout->ClearLines();\n    TextLayout->ClearLineHighlights();\n    TextLayout->ClearRunRenderers();\n\n    TextLayout->SetDefaultTextStyle(TextFormat.GetStyle());\n    TextLayout->SetJustification((ETextJustify::Type)TextFormat.Align);\n    TextLayout->SetWrappingPolicy(ETextWrappingPolicy::AllowPerCharacterWrapping);\n    if (AutoSize == EAutoSizeType::Both)\n        TextLayout->SetWrappingWidth(MaxWidth);\n    else\n        TextLayout->SetWrappingWidth(MaxWidth != 0 ? FMath::Min(MaxWidth, Size.X) : Size.X);\n    TextLayout->SetMargin(FMargin(2, 2));\n    TextLayout->SetLineHeightPercentage(1 + (TextFormat.LineSpacing - 3) / TextFormat.Size);\n\n    HTMLElements.Reset();\n    if (bHTML)\n    {\n        FHTMLParser::DefaultParser.Parse(Text, TextFormat, HTMLElements, FHTMLParser::DefaultParseOptions);\n    }\n    else\n    {\n        FHTMLElement TextElement;\n        TextElement.Type = EHTMLElementType::Text;\n        TextElement.Format = TextFormat;\n        TextElement.Text = Text;\n        HTMLElements.Add(MoveTemp(TextElement));\n    }\n\n    BuildLines();\n\n    TextLayout->UpdateIfNeeded();\n\n    if (AutoSize == EAutoSizeType::Both)\n    {\n        GObject->SetSize(TextLayout->GetSize());\n    }\n    else if (AutoSize == EAutoSizeType::Height)\n    {\n        GObject->SetSize(FVector2D(Size.X, TextLayout->GetSize().Y));\n    }\n}\n\nvoid STextField::BuildLines()\n{\n    class FLineHelper\n    {\n    public:\n        TArray<FTextLayout::FNewLineData> Lines;\n        FTextLayout::FNewLineData* LastLineData;\n        bool bNewLine;\n\n        FLineHelper()\n        {\n            NewLine();\n        }\n\n        TSharedRef<FString>& GetTextRef()\n        {\n            if (bNewLine)\n                NewLine();\n\n            return LastLineData->Text;\n        }\n\n        FString& GetText()\n        {\n            if (bNewLine)\n                NewLine();\n\n            return LastLineData->Text.Get();\n        }\n\n        TArray<TSharedRef<IRun>>& GetRuns()\n        {\n            if (bNewLine)\n                NewLine();\n\n            return LastLineData->Runs;\n        }\n\n    private:\n        void NewLine()\n        {\n            Lines.Emplace(MakeShareable(new FString()), TArray<TSharedRef<IRun>>());\n            LastLineData = &Lines.Last();\n            bNewLine = false;\n        }\n    } LineHelper;\n\n    TSharedPtr<FBitmapFont> BitmapFont;\n    if (TextFormat.Face.StartsWith(\"ui://\"))\n    {\n        TSharedPtr<FPackageItem> FontItem = UUIPackage::GetItemByURL(TextFormat.Face);\n        if (FontItem.IsValid())\n        {\n            FontItem->Load();\n            BitmapFont = FontItem->BitmapFont;\n        }\n    }\n\n    TArray<FTextRange> LineRangesBuffer;\n    for (int32 ElementIndex = 0; ElementIndex < HTMLElements.Num(); ++ElementIndex)\n    {\n        const FHTMLElement& Element = HTMLElements[ElementIndex];\n        if (Element.Type == EHTMLElementType::Text)\n        {\n            LineRangesBuffer.Reset();\n\n            FTextBlockStyle TextStyle = Element.Format.GetStyle();\n\n            FTextRange::CalculateLineRangesFromString(Element.Text, LineRangesBuffer);\n\n            for (int32 LineIndex = 0; LineIndex < LineRangesBuffer.Num(); ++LineIndex)\n            {\n                const FTextRange& LineRange = LineRangesBuffer[LineIndex];\n                FString TextBlock = Element.Text.Mid(LineRange.BeginIndex, LineRange.Len());\n                if (BitmapFont.IsValid())\n                {\n                    int32 len = TextBlock.Len();\n                    for (int32 CharIndex = 0; CharIndex < len; CharIndex++)\n                    {\n                        FTextRange ModelRange;\n                        ModelRange.BeginIndex = LineHelper.GetText().Len();\n                        LineHelper.GetText().AppendChar(TextBlock[CharIndex]);\n                        ModelRange.EndIndex = LineHelper.GetText().Len();\n                        LineHelper.GetRuns().Add(FBitmapFontRun::Create(LineHelper.GetTextRef(), BitmapFont.ToSharedRef(), ModelRange));\n                    }\n                }\n                else\n                {\n                    FTextRange ModelRange;\n                    ModelRange.BeginIndex = LineHelper.GetText().Len();\n                    LineHelper.GetText().Append(TextBlock);\n                    ModelRange.EndIndex = LineHelper.GetText().Len();\n\n                    LineHelper.GetRuns().Add(FSlateTextRun::Create(FRunInfo(), LineHelper.GetTextRef(), TextStyle, ModelRange));\n                }\n\n                if (LineIndex != LineRangesBuffer.Num() - 1)\n                    LineHelper.bNewLine = true;\n            }\n        }\n        else if (Element.Type == EHTMLElementType::Image)\n        {\n            FTextRange ModelRange;\n            ModelRange.BeginIndex = LineHelper.GetText().Len();\n            LineHelper.GetText().Append(TEXT(\"\\x200B\")); // Zero-Width Breaking Space\n            ModelRange.EndIndex = LineHelper.GetText().Len();\n            LineHelper.GetRuns().Add(FLoaderRun::Create(GObject->GetApp(), Element, LineHelper.GetTextRef(), ModelRange));\n        }\n    }\n\n    TextLayout->AddLines(LineHelper.Lines);\n}"
  },
  {
    "path": "Source/FairyGUI/Private/Widgets/STextInput.cpp",
    "content": "#include \"Widgets/STextInput.h\"\n#include \"Widgets/Text/SlateEditableTextLayout.h\"\n\nclass SMyTextInput : public SMultiLineEditableText\n{\npublic:\n    SMyTextInput() :bPassword(false)\n    {\n\n    }\n\n    void SetTextFormat(const FNTextFormat& InTextFormat)\n    {\n        EditableTextLayout->SetTextStyle(InTextFormat.GetStyle());\n        EditableTextLayout->SetJustification((ETextJustify::Type)InTextFormat.Align);\n    }\n\n    void SetOnTextChanged(FOnTextChanged Callback)\n    {\n        OnTextChangedCallback = Callback;\n    }\n\n    void SetOnTextCommitted(FOnTextCommitted Callback)\n    {\n        OnTextCommittedCallback = Callback;\n    }\n\n    void SetAllowMultiLine(bool bInAllowMultiLine)\n    {\n        bAllowMultiLine = bInAllowMultiLine;\n    }\n\n    virtual bool IsTextPassword() const override\n    {\n        return bPassword;\n    }\n\n    bool bPassword;\n};\n\nSTextInput::STextInput() :\n    Widget(SNew(SMyTextInput)),\n    ChildSlot(this)\n{\n}\n\nvoid STextInput::Construct(const FArguments& InArgs)\n{\n    SDisplayObject::Construct(SDisplayObject::FArguments().GObject(InArgs._GObject));\n\n    ChildSlot.AttachWidget(Widget);\n}\n\nvoid STextInput::SetTextFormat(const FNTextFormat& InTextFormat)\n{\n    StaticCastSharedRef<SMyTextInput>(Widget)->SetTextFormat(InTextFormat);\n}\n\nvoid STextInput::SetPassword(bool bInPassword)\n{\n    StaticCastSharedRef<SMyTextInput>(Widget)->bPassword = bInPassword;\n}\n\nvoid STextInput::SetSingleLine(bool bInSingleLine)\n{\n    StaticCastSharedRef<SMyTextInput>(Widget)->SetAllowMultiLine(!bInSingleLine);\n}\n\nvoid STextInput::SetOnTextChanged(FOnTextChanged Callback)\n{\n    StaticCastSharedRef<SMyTextInput>(Widget)->SetOnTextChanged(Callback);\n}\n\nvoid STextInput::SetOnTextCommitted(FOnTextCommitted Callback)\n{\n    StaticCastSharedRef<SMyTextInput>(Widget)->SetOnTextCommitted(Callback);\n}\n\nFChildren* STextInput::GetChildren()\n{\n    return &ChildSlot;\n}\n\nvoid STextInput::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const\n{\n    if (ArrangedChildren.Accepts(Widget->GetVisibility()))\n        ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(\n            Widget, FVector2D::ZeroVector, Size\n        ));\n}\n\nint32 STextInput::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const\n{\n    FArrangedChildren ArrangedChildren(EVisibility::Visible);\n    ArrangeChildren(AllottedGeometry, ArrangedChildren);\n\n    FArrangedWidget& TheChild = ArrangedChildren[0];\n    return TheChild.Widget->Paint(Args.WithNewParent(this), TheChild.Geometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, ShouldBeEnabled(bParentEnabled));\n}\n"
  },
  {
    "path": "Source/FairyGUI/Public/Event/EventContext.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Input/Events.h\"\n#include \"EventTypes.h\"\n#include \"Utils/NVariant.h\"\n#include \"EventContext.generated.h\"\n\nclass UGObject;\nclass SDisplayObject;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UEventContext : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetSender() const\n    {\n        return Sender;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetInitiator() const\n    {\n        return Initiator;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FName& GetType() const\n    {\n        return Type;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetPointerPosition() const\n    {\n        return PointerEvent->GetScreenSpacePosition();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetPointerIndex() const\n    {\n        return (int32)PointerEvent->GetPointerIndex();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetUserIndex() const\n    {\n        return PointerEvent->GetUserIndex();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetWheelDelta() const\n    {\n        return PointerEvent->GetWheelDelta();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FKey GetMouseButton() const\n    {\n        if (PointerEvent->IsTouchEvent())\n            return EKeys::LeftMouseButton;\n        else\n            return PointerEvent->GetEffectingButton();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FPointerEvent& GetPointerEvent() const\n    {\n        return *PointerEvent;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FKeyEvent& GetKeyEvent() const\n    {\n        return *KeyEvent;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetClickCount() const\n    {\n        return ClickCount;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsDoubleClick() const\n    {\n        return ClickCount == 2;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FNVariant& GetData() const\n    {\n        return Data;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void StopPropagation()\n    {\n        bStopped = true;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsPropagationStopped() const\n    {\n        return bStopped;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void PreventDefault()\n    {\n        bDefaultPrevented = true;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsDefaultPrevented() const\n    {\n        return bDefaultPrevented;\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void CaptureTouch()\n    {\n        bIsMouseCaptor = true;\n    }\n\nprivate:\n    UGObject* Sender;\n    UGObject* Initiator;\n    FName Type;\n    bool bStopped;\n    bool bDefaultPrevented;\n    bool bIsMouseCaptor;\n    FPointerEvent* PointerEvent;\n    FKeyEvent* KeyEvent;\n    int32 ClickCount;\n    FNVariant Data;\n\n    friend class UFairyApplication;\n};\n\nDECLARE_DELEGATE_OneParam(FGUIEventDelegate, UEventContext*);\nDECLARE_MULTICAST_DELEGATE_OneParam(FGUIEventMDelegate, UEventContext*);\n\nDECLARE_DYNAMIC_DELEGATE_OneParam(FGUIEventDynDelegate, UEventContext*, EventContext);\nDECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FGUIEventDynMDelegate, UEventContext*, EventContext);\n\nDECLARE_DYNAMIC_DELEGATE(FSimpleDynDelegate);"
  },
  {
    "path": "Source/FairyGUI/Public/Event/EventTypes.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n\nstruct FAIRYGUI_API FUIEvents\n{\n    static const FName Click;\n    static const FName TouchBegin;\n    static const FName TouchMove;\n    static const FName TouchEnd;\n    static const FName RollOver;\n    static const FName RollOut;\n    static const FName MouseWheel;\n\n    static const FName DragStart;\n    static const FName DragMove;\n    static const FName DragEnd;\n    static const FName Drop;\n\n    static const FName AddedToStage;\n    static const FName RemovedFromStage;\n\n    static const FName Changed;\n    static const FName ClickItem;\n    static const FName ClickLink;\n    static const FName GearStop;\n\n    static const FName Scroll;\n    static const FName ScrollEnd;\n    static const FName PullDownRelease;\n    static const FName PullUpRelease;\n\n    static const FName Submit;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/FairyApplication.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Engine/GameViewportClient.h\"\n#include \"Engine.h\"\n#include \"Framework/Application/IInputProcessor.h\"\n#include \"FairyCommons.h\"\n#include \"Event/EventContext.h\"\n#include \"Tween/TweenManager.h\"\n#include \"UI/UIConfig.h\"\n#include \"FairyApplication.generated.h\"\n\nclass UUIPackage;\nclass UNTexture;\nclass UGObject;\nclass UGRoot;\nclass UDragDropManager;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UFairyApplication : public UObject\n{\n    GENERATED_BODY()\n\nprivate:\n    struct FTouchInfo\n    {\n        int32 UserIndex;\n        int32 PointerIndex;\n        bool bDown;\n        bool bToClearCaptors;\n        FVector2D DownPosition;\n        bool bClickCancelled;\n        int32 ClickCount;\n        TArray<TWeakPtr<SWidget>> DownPath;\n        TArray<TWeakObjectPtr<UGObject>> MouseCaptors;\n        FPointerEvent Event;\n\n        FTouchInfo();\n    };\n\n    class FInputProcessor : public IInputProcessor\n    {\n    public:\n        FInputProcessor(UFairyApplication* InApplication);\n        virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Cursor) override;\n        virtual bool HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override;\n        virtual bool HandleMouseButtonUpEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override;\n        virtual bool HandleMouseMoveEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) override;\n\n        UFairyApplication* Application;\n    };\n\npublic:\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI\", meta = (DisplayName = \"Get Application\", WorldContext = \"WorldContextObject\"))\n        static UFairyApplication* Get(UObject* WorldContextObject);\n\n    static void Destroy();\n\n    UFairyApplication();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        UGRoot* GetUIRoot() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        UDragDropManager* GetDragDropManager() const { return DragDropManager; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        FVector2D GetTouchPosition(int32 InUserIndex = -1, int32 InPointerIndex = -1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        int32 GetTouchCount() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        UGObject* GetObjectUnderPoint(const FVector2D& ScreenspacePosition);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        void CancelClick(int32 InUserIndex = -1, int32 InPointerIndex = -1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        void PlaySound(const FString& URL, float VolumeScale = 1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        bool IsSoundEnabled() const { return bSoundEnabled; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        void SetSoundEnabled(bool InEnabled);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        float GetSoundVolumeScale() const { return SoundVolumeScale; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n        void SetSoundVolumeScale(float InVolumeScale);\n\npublic:\n    virtual UWorld* GetWorld() const override {\n        return GameInstance->GetWorld();\n    }\n\n    bool DispatchEvent(const FName& EventType, const TSharedRef<SWidget>& Initiator, const FNVariant& Data = FNVariant::Null);\n    void BubbleEvent(const FName& EventType, const TSharedRef<SWidget>& Initiator, const FNVariant& Data = FNVariant::Null);\n    void BroadcastEvent(const FName& EventType, const TSharedRef<SWidget>& Initiator, const FNVariant& Data = FNVariant::Null);\n\n    void AddMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget);\n    void RemoveMouseCaptor(int32 InUserIndex, int32 InPointerIndex, UGObject* InTarget);\n    bool HasMouseCaptor(int32 InUserIndex, int32 InPointerIndex);\n\n    FReply OnWidgetMouseButtonDown(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);\n    FReply OnWidgetMouseButtonUp(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);\n    FReply OnWidgetMouseMove(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);\n    FReply OnWidgetMouseButtonDoubleClick(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);\n    void OnWidgetMouseEnter(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);\n    void OnWidgetMouseLeave(const TSharedRef<SWidget>& Widget, const FPointerEvent& MouseEvent);\n    FReply OnWidgetMouseWheel(const TSharedRef<SWidget>& Widget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent);\n\n    UGameViewportClient* GetViewportClient() const { return ViewportClient; }\n    const TSharedPtr<SWidget>& GetViewportWidget() const { return ViewportWidget; }\n\n    void CallAfterSlateTick(FSimpleDelegate Callback);\n\n    template< class UserClass, typename... VarTypes >\n    void DelayCall(FTimerHandle& InOutHandle, UserClass* InUserObject, typename TMemFunPtrType<false, UserClass, void(VarTypes...)>::Type inTimerMethod, VarTypes...);\n    void CancelDelayCall(FTimerHandle& InHandle);\n\nprivate:\n    void OnCreate();\n    void OnDestroy();\n\n    void PreviewDownEvent(const FPointerEvent& MouseEvent);\n    void PreviewUpEvent(const FPointerEvent& MouseEvent);\n    void PreviewMoveEvent(const FPointerEvent& MouseEvent);\n\n    UEventContext* BorrowEventContext();\n    void ReturnEventContext(UEventContext* Context);\n\n    void InternalBubbleEvent(const FName& EventType, const TArray<UGObject*>& CallChain, const FNVariant& Data);\n\n    FTouchInfo* GetTouchInfo(const FPointerEvent& MouseEvent);\n    FTouchInfo* GetTouchInfo(int32 InUserIndex, int32 InPointerIndex);\n\n    void OnSlatePostTick(float DeltaTime);\n\nprivate:\n    UPROPERTY(Transient)\n        UGRoot* UIRoot;\n    UPROPERTY(Transient)\n        UDragDropManager* DragDropManager;\n    UPROPERTY(Transient)\n        TArray<UEventContext*> EventContextPool;\n\n    TSharedPtr<IInputProcessor> InputProcessor;\n    UGameViewportClient* ViewportClient;\n    TSharedPtr<SWidget> ViewportWidget;\n    TIndirectArray<FTouchInfo> Touches;\n    FTouchInfo* LastTouch;\n    bool bNeedCheckPopups;\n    FDelegateHandle PostTickDelegateHandle;\n    FSimpleMulticastDelegate PostTickMulticastDelegate;\n    bool bSoundEnabled;\n    float SoundVolumeScale;\n\n    UGameInstance* GameInstance;\n\n    static TMap<uint32, UFairyApplication*> Instances;\n};\n\ntemplate< class UserClass, typename... VarTypes >\nvoid UFairyApplication::DelayCall(FTimerHandle& InOutHandle, UserClass* InUserObject, typename TMemFunPtrType<false, UserClass, void(VarTypes...)>::Type inTimerMethod, VarTypes... Vars)\n{\n    if (!GameInstance->GetWorld()->GetTimerManager().TimerExists(InOutHandle))\n        InOutHandle = GameInstance->GetWorld()->GetWorld()->GetTimerManager().SetTimerForNextTick(FTimerDelegate::CreateUObject(InUserObject, inTimerMethod, Vars...));\n}\n\ninline void UFairyApplication::CancelDelayCall(FTimerHandle& InHandle)\n{\n    GameInstance->GetWorld()->GetTimerManager().ClearTimer(InHandle);\n}"
  },
  {
    "path": "Source/FairyGUI/Public/FairyBlueprintLibrary.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Kismet/BlueprintFunctionLibrary.h\"\n#include \"Utils/NVariant.h\"\n#include \"Tween/TweenValue.h\"\n#include \"Tween/EaseType.h\"\n#include \"Tween/TweenerHandle.h\"\n#include \"Event/EventContext.h\"\n#include \"FairyBlueprintLibrary.generated.h\"\n\nDECLARE_DYNAMIC_DELEGATE_TwoParams(FTweenUpdateDynDelegate, const FTweenValue&, Value, const FTweenValue&, DeltaValue);\n\nUCLASS()\nclass FAIRYGUI_API UFairyBlueprintLibrary : public UBlueprintFunctionLibrary\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI\")\n    static const FUIConfig& GetUIConfig();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static void SetUIConfig(const FUIConfig& InConfig);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI|Variant\")\n    static bool GetVariantAsBool(UPARAM(ref) FNVariant& InVariant);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI|Variant\")\n    static int32 GetVariantAsInt(UPARAM(ref) FNVariant& InVariant);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI|Variant\")\n    static float GetVariantAsFloat(UPARAM(ref) FNVariant& InVariant);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI|Variant\")\n    static FString GetVariantAsString(UPARAM(ref) FNVariant& InVariant);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI|Variant\")\n    static FColor GetVariantAsColor(UPARAM(ref) FNVariant& InVariant);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI|Variant\", meta = (DeterminesOutputType = \"ClassType\"))\n    static UObject* GetVariantAsUObject(UPARAM(ref) FNVariant& InVariant, TSubclassOf<UObject> ClassType);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Variant\")\n    static FNVariant& SetVariantBool(UPARAM(ref) FNVariant& InVariant, bool bInValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Variant\")\n    static FNVariant& SetVariantInt(UPARAM(ref) FNVariant& InVariant, int32 InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Variant\")\n    static FNVariant& SetVariantFloat(UPARAM(ref) FNVariant& InVariant, float InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Variant\")\n    static FNVariant& SetVariantString(UPARAM(ref) FNVariant& InVariant, const FString& InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Variant\")\n    static FNVariant& SetVariantColor(UPARAM(ref) FNVariant& InVariant, const FColor& InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Variant\")\n    static FNVariant& SetVariantUObject(UPARAM(ref) FNVariant& InVariant, UObject* InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Tween\", meta = (AutoCreateRefTerm = \"OnUpdate,OnComplete\"))\n    static FTweenerHandle TweenFloat(float StartValue, float EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Tween\", meta = (AutoCreateRefTerm = \"OnUpdate,OnComplete\"))\n    static FTweenerHandle TweenVector2(const FVector2D& StartValue, const FVector2D& EndValue, EEaseType EaseType, float Duration, int32 Repeat, const FTweenUpdateDynDelegate& OnUpdate, const FSimpleDynDelegate& OnComplete);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI|Tween\")\n    static void KillTween(UPARAM(ref) FTweenerHandle& Handle, bool bSetComplete = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static void SetPackageItemExtension(const FString& URL, TSubclassOf<UGComponent> ClassType);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/FairyCommons.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nFAIRYGUI_API DECLARE_LOG_CATEGORY_EXTERN(LogFairyGUI, Log, All)\n\nextern const FString FAIRYGUI_API G_EMPTY_STRING;\n\nDECLARE_DELEGATE_RetVal_OneParam(class UGComponent*, FGComponentCreator, UObject*);"
  },
  {
    "path": "Source/FairyGUI/Public/FairyGUI.h",
    "content": "#pragma once\n\n#include \"UI/UIObjectFactory.h\"\n#include \"UI/UIPackage.h\"\n#include \"UI/PackageItem.h\"\n#include \"UI/GComponent.h\"\n#include \"UI/GImage.h\"\n#include \"UI/GMovieClip.h\"\n#include \"UI/GTextField.h\"\n#include \"UI/GRichTextField.h\"\n#include \"UI/GTextInput.h\"\n#include \"UI/GGraph.h\"\n#include \"UI/GLoader.h\"\n#include \"UI/GLoader3D.h\"\n#include \"UI/GGroup.h\"\n#include \"UI/GLabel.h\"\n#include \"UI/GButton.h\"\n#include \"UI/GComboBox.h\"\n#include \"UI/GProgressBar.h\"\n#include \"UI/GSlider.h\"\n#include \"UI/GScrollBar.h\"\n#include \"UI/GList.h\"\n#include \"UI/GTree.h\"\n#include \"UI/PopupMenu.h\"\n#include \"UI/GWindow.h\"\n#include \"UI/GRoot.h\"\n#include \"UI/GController.h\"\n#include \"UI/Transition.h\"\n#include \"UI/ScrollPane.h\"\n#include \"UI/TranslationHelper.h\"\n\n#include \"Tween/GTween.h\"\n\n#include \"Utils/NVariant.h\"\n#include \"Utils/ByteBuffer.h\"\n\n#include \"Widgets/NTexture.h\"\n#include \"Widgets/Mesh/EllipseMesh.h\"\n#include \"Widgets/Mesh/PolygonMesh.h\"\n#include \"Widgets/Mesh/RectMesh.h\"\n#include \"Widgets/Mesh/RegularPolygonMesh.h\"\n#include \"Widgets/Mesh/RoundedRectMesh.h\"\n\n#include \"UIPackageAsset.h\"\n#include \"FairyApplication.h\"\n"
  },
  {
    "path": "Source/FairyGUI/Public/FairyGUIModule.h",
    "content": "// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Modules/ModuleManager.h\"\n\nclass FFairyGUIModule : public IModuleInterface\n{\npublic:\n\n\t/** IModuleInterface implementation */\n\tvirtual void StartupModule() override;\n\tvirtual void ShutdownModule() override;\n\n    FDelegateHandle EndPieDelegateHandle;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/EaseManager.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"EaseType.h\"\n\nclass FAIRYGUI_API EaseManager\n{\npublic:\n    static float Evaluate(EEaseType EaseType, float Time, float Duration, float OvershootOrAmplitude, float Period);\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/EaseType.h",
    "content": "#pragma once\n\n#include \"EaseType.generated.h\"\n\nUENUM()\nenum class EEaseType : uint8\n{\n    Linear,\n    SineIn,\n    SineOut,\n    SineInOut,\n    QuadIn,\n    QuadOut,\n    QuadInOut,\n    CubicIn,\n    CubicOut,\n    CubicInOut,\n    QuartIn,\n    QuartOut,\n    QuartInOut,\n    QuintIn,\n    QuintOut,\n    QuintInOut,\n    ExpoIn,\n    ExpoOut,\n    ExpoInOut,\n    CircIn,\n    CircOut,\n    CircInOut,\n    ElasticIn,\n    ElasticOut,\n    ElasticInOut,\n    BackIn,\n    BackOut,\n    BackInOut,\n    BounceIn,\n    BounceOut,\n    BounceInOut,\n    Custom\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/GPath.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nstruct FAIRYGUI_API FGPathPoint\n{\n    enum class ECurveType\n    {\n        CRSpline,\n        Bezier,\n        CubicBezier,\n        Straight\n    };\n\n    FVector Pos;\n    FVector Control1;\n    FVector Control2;\n    ECurveType CurveType;\n\n    FGPathPoint(const FVector& InPos);\n    FGPathPoint(const FVector& InPos, const FVector& InControl);\n    FGPathPoint(const FVector& InPos, const FVector& InControl1, const FVector& InControl2);\n    FGPathPoint(const FVector& InPos, ECurveType InCurveType);\n};\n\nclass FAIRYGUI_API FGPath\n{\npublic:\n    FGPath();\n    void Create(const FGPathPoint* InPoints, int32 Count);\n    void Clear();\n    FVector GetPointAt(float Time);\n\n    float GetLength() { return FullLength; }\n    int32 GetSegmentCount() { return Segments.Num(); }\n    float GetSegmentLength(int32 SegmentIndex);\n    void GetPointsInSegment(int32 SegmentIndex, float t0, float t1,\n        TArray<FVector>& OutPoints, TArray<float>* OutTimeArray = nullptr, float PointDensity = 0.1f);\n    void GetAllPoints(TArray<FVector>& OutPoints, float PointDensity = 0.1f);\n\n    struct FSegment\n    {\n        FGPathPoint::ECurveType Type;\n        float Length;\n        int32 PointStart;\n        int32 PointCount;\n    };\n\nprivate:\n    void CreateSplineSegment(TArray<FVector>& InOutSplinePoints);\n    FVector OnCRSplineCurve(int32 PointStart, int32 PointCount, float Time);\n    FVector OnBezierCurve(int32 PointStart, int32 PointCount, float Time);\n\n    TArray<FSegment> Segments;\n    TArray<FVector> Points;\n    float FullLength;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/GTween.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"GTweener.h\"\n#include \"EaseType.h\"\n#include \"TweenValue.h\"\n\nclass FAIRYGUI_API FGTween\n{\npublic:\n    static FGTweener* To(float StartValue, float EndValue, float Duration);\n    static FGTweener* To(const FVector2D& StartValue, const FVector2D& EndValue, float Duration);\n    static FGTweener* To(const FVector& StartValue, const FVector& EndValue, float Duration);\n    static FGTweener* To(const FVector4& StartValue, const FVector4& EndValue, float Duration);\n    static FGTweener* To(const FColor& StartValue, const FColor& EndValue, float Duration);\n    static FGTweener* ToDouble(double StartValue, double EndValue, float Duration);\n    static FGTweener* DelayedCall(float Delay);\n    static FGTweener* Shake(const FVector2D& StartValue, float Amplitude, float Duration);\n\n    static bool IsTweening(const FTweenerHandle& Handle);\n    static bool IsTweening(UObject* Target);\n\n    static FGTweener* GetTween(const FTweenerHandle& Handle);\n    static FGTweener* GetTween(UObject* Target);\n\n    static void Kill(FTweenerHandle& Handle, bool bSetComplete = false);\n    static void Kill(UObject* Target, bool bSetComplete = false);\n};\n\nclass FAIRYGUI_API FGTweenAction\n{\npublic:\n    static void MoveX(FGTweener* Tweener);\n    static void MoveY(FGTweener* Tweener);\n    static void Move(FGTweener* Tweener);\n    static void SetWidth(FGTweener* Tweener);\n    static void SetHeight(FGTweener* Tweener);\n    static void SetSize(FGTweener* Tweener);\n    static void ScaleX(FGTweener* Tweener);\n    static void ScaleY(FGTweener* Tweener);\n    static void ScaleXY(FGTweener* Tweener);\n    static void Rotate(FGTweener* Tweener);\n    static void SetAlpha(FGTweener* Tweener);\n    static void SetProgress(FGTweener* Tweener);\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/GTweener.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"EaseType.h\"\n#include \"TweenValue.h\"\n#include \"TweenerHandle.h\"\n#include \"Utils/NVariant.h\"\n\nclass FGPath;\nclass FGTweener;\n\nDECLARE_DELEGATE_OneParam(FTweenDelegate, FGTweener*);\n\nclass FAIRYGUI_API FGTweener\n{\npublic:\n    FGTweener();\n    ~FGTweener();\n\n    const FTweenerHandle& GetHandle() {\n        return Handle;\n    }\n\n    FGTweener* SetDelay(float InValue);\n    float GetDelay() const { return Delay; }\n    FGTweener* SetDuration(float InValue);\n    float GetDuration() const { return Duration; }\n    FGTweener* SetBreakpoint(float InValue);\n    FGTweener* SetEase(EEaseType InValue);\n    FGTweener* SetEasePeriod(float InValue);\n    FGTweener* SetEaseOvershootOrAmplitude(float InValue);\n    FGTweener* SetRepeat(int32 InRepeat, bool bInYoyo = false);\n    int32 GetRepeat() const { return Repeat; }\n    FGTweener* SetTimeScale(float InValue);\n    FGTweener* SetSnapping(bool InValue);\n    FGTweener* SetTarget(UObject* InTarget);\n    UObject* GetTarget() const { return Target.Get(); }\n    const FNVariant& GetUserData() const { return UserData; }\n    FGTweener* SetUserData(const FNVariant& InData);\n    FGTweener* SetPath(TSharedPtr<FGPath> InPath);\n    FGTweener* OnUpdate(FTweenDelegate Callback);\n    FGTweener* OnStart(FTweenDelegate Callback);\n    FGTweener* OnComplete(FTweenDelegate Callback);\n    FGTweener* OnUpdate(FSimpleDelegate Callback);\n    FGTweener* OnStart(FSimpleDelegate Callback);\n    FGTweener* OnComplete(FSimpleDelegate Callback);\n\n    float GetNormalizedTime() const { return NormalizedTime; }\n    bool IsCompleted() const { return Ended != 0; }\n    bool AllCompleted() const { return Ended == 1; }\n    FGTweener* SetPaused(bool bInPaused);\n    void Seek(float Time);\n    void Kill(bool bSetComplete = false);\n\n    FTweenValue StartValue;\n    FTweenValue EndValue;\n    FTweenValue Value;\n    FTweenValue DeltaValue;\n\nprivate:\n    FGTweener* To(float InStart, float InEnd, float InDuration);\n    FGTweener* To(const FVector2D& InStart, const FVector2D& InEnd, float InDuration);\n    FGTweener* To(const FVector& InStart, const FVector& InEnd, float InDuration);\n    FGTweener* To(const FVector4& InStart, const FVector4& InEnd, float InDuration);\n    FGTweener* To(const FColor& InStart, const FColor& InEnd, float InDuration);\n    FGTweener* To(double InStart, double InEnd, float InDuration);\n    FGTweener* Shake(const FVector2D& InStart, float InAmplitude, float InDuration);\n    void Init();\n    void Reset();\n    void Update(float DeltaTime);\n    void Update();\n\nprivate:\n    TWeakObjectPtr<UObject> Target;\n    bool bKilled;\n    bool bPaused;\n\n    float Delay;\n    float Duration;\n    float Breakpoint;\n    EEaseType EaseType;\n    float EaseOvershootOrAmplitude;\n    float EasePeriod;\n    int32 Repeat;\n    bool bYoyo;\n    float TimeScale;\n    bool bSnapping;\n    FNVariant UserData;\n    int32 ValueSize;\n    TSharedPtr<FGPath> Path;\n    FTweenerHandle Handle;\n\n    FTweenDelegate OnUpdateCallback;\n    FTweenDelegate OnStartCallback;\n    FTweenDelegate OnCompleteCallback;\n\n    bool bStarted;\n    int32 Ended;\n    float ElapsedTime;\n    float NormalizedTime;\n\n    friend class FGTween;\n    friend class FTweenManager;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/TweenManager.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Engine/Engine.h\"\n#include \"Tickable.h\"\n#include \"GTweener.h\"\n\nclass UGObject;\n\nclass FAIRYGUI_API FTweenManager : public FTickableGameObject\n{\npublic:\n    static FTweenManager Singleton;\n\n    FTweenManager();\n    virtual ~FTweenManager();\n    void Reset();\n\n    FGTweener* CreateTween();\n\n    bool IsTweening(FTweenerHandle const& Handle) { return GetTween(Handle) != nullptr; }\n    bool IsTweening(UObject* Target) { return GetTween(Target) != nullptr; }\n\n    bool KillTween(FTweenerHandle & Handle, bool bCompleted);\n    bool KillTweens(UObject* Target, bool bCompleted);\n\n    FGTweener* GetTween(FTweenerHandle const& Handle);\n    FGTweener* GetTween(UObject* Target);\n\n    void Tick(float DeltaTime);\n    TStatId GetStatId() const {\n        return TStatId();\n    }\n\nprivate:\n    FGTweener** ActiveTweens;\n    TArray<FGTweener*> TweenerPool;\n    int32 TotalActiveTweens;\n    int32 ArrayLength;\n    uint32 TweenerInstanceCount;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/TweenValue.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"TweenValue.generated.h\"\n\nUSTRUCT(BlueprintType)\nstruct FAIRYGUI_API FTweenValue\n{\n    GENERATED_USTRUCT_BODY()\n\npublic:\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float X;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float Y;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float Z;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float W;\n\n    double D;\n\n    FTweenValue();\n\n    FVector2D GetVec2() const;\n    void SetVec2(const FVector2D& Value);\n    FVector GetVec3() const;\n    void SetVec3(const FVector& Value);\n    FVector4 GetVec4() const;\n    void SetVec4(const FVector4& Value);\n    FColor GetColor() const;\n    void SetColor(const FColor& Color);\n    float operator[] (int32 Index) const;\n    float& operator[] (int32 Index);\n    void Reset();\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Tween/TweenerHandle.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"TweenerHandle.generated.h\"\n\nUSTRUCT(BlueprintType)\nstruct FAIRYGUI_API FTweenerHandle\n{\n    GENERATED_USTRUCT_BODY()\n\npublic:\n    FTweenerHandle()\n        : Handle(0)\n    {\n    }\n\n    bool IsValid() const\n    {\n        return Handle != 0;\n    }\n\n    void Invalidate()\n    {\n        Handle = 0;\n    }\n\n    bool operator==(const FTweenerHandle& Other) const\n    {\n        return Handle == Other.Handle;\n    }\n\n    bool operator!=(const FTweenerHandle& Other) const\n    {\n        return Handle != Other.Handle;\n    }\n\n    FString ToString() const\n    {\n        return FString::Printf(TEXT(\"%ull\"), Handle);\n    }\n\nprivate:\n    FORCEINLINE int32 GetIndex() const\n    {\n        return (int32)(Handle & (uint64)(MaxIndex - 1));\n    }\n\n    FORCEINLINE uint64 GetSerialNumber() const\n    {\n        return Handle >> IndexBits;\n    }\n\n    static const uint32 IndexBits = 24;\n    static const uint32 SerialNumberBits = 40;\n    static const int32  MaxIndex = (int32)1 << IndexBits;\n    static const uint64 MaxSerialNumber = (uint64)1 << SerialNumberBits;\n\n    void SetIndex(int32 Index)\n    {\n        Handle = (uint64)(uint32)Index;\n    }\n\n    void IncreaseSerialNumber()\n    {\n        int32 Index = (int32)(Handle & (uint64)(MaxIndex - 1));\n        uint64 SerialNumber = Handle >> IndexBits;\n        SerialNumber++;\n        if (!ensureMsgf(SerialNumber != FTweenerHandle::MaxSerialNumber, TEXT(\"Tweener serial number has wrapped around!\")))\n        {\n            SerialNumber = 0;\n        }\n        Handle = (SerialNumber << IndexBits) | (uint64)(uint32)Index;\n    }\n\n    uint64 Handle;\n    friend class FTweenManager;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/UI/ControllerAction/ChangePageAction.h",
    "content": "#pragma once\n\n#include \"ControllerAction.h\"\n\nclass FChangePageAction : public FControllerAction\n{\npublic:\n    virtual void Setup(FByteBuffer * Buffer) override;\n\n    FString ObjectID;\n    FString ControllerName;\n    FString TargetPage;\n\nprotected:\n    virtual void Enter(UGController* Controller) override;\n    virtual void Leave(UGController* Controller) override;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/ControllerAction/ControllerAction.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nclass UGController;\nclass FByteBuffer;\n\nclass FControllerAction\n{\npublic:\n    static FControllerAction* CreateAction(int32 ActionType);\n\n    FControllerAction();\n    virtual ~FControllerAction();\n\n    void Run(UGController* Controller, const FString& PreviousPage, const FString& CurrentPage);\n    virtual void Setup(FByteBuffer * Buffer);\n\n    TArray<FString> FromPage;\n    TArray<FString> ToPage;\n\nprotected:\n    virtual void Enter(UGController* Controller) = 0;\n    virtual void Leave(UGController* Controller) = 0;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/ControllerAction/PlayTransitionAction.h",
    "content": "#pragma once\n\n#include \"ControllerAction.h\"\n\nclass UTransition;\n\nclass FPlayTransitionAction : public FControllerAction\n{\npublic:\n    FPlayTransitionAction();\n    virtual void Setup(FByteBuffer * Buffer) override;\n\n    FString TransitionName;\n    int32 PlayTimes;\n    float Delay;\n    bool bStopOnExit;\n\nprotected:\n    virtual void Enter(UGController* Controller) override;\n    virtual void Leave(UGController* Controller) override;\n\n    UTransition* CurrentTransition;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/DragDropManager.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Event/EventContext.h\"\n#include \"UI/GLoader.h\"\n#include \"DragDropManager.generated.h\"\n\nUCLASS(BlueprintType)\nclass UDragDropManager : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    UDragDropManager();\n    virtual ~UDragDropManager();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGLoader* GetAgent() const { return Agent; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsDragging() const { return Agent->GetParent() != nullptr; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm=\"InSourceData\"))\n    void StartDrag(const FString& InIcon, const FNVariant& InUserData, int32 InUserIndex = -1, int32 InPointerIndex = -1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Cancel();\n\n    void CreateAgent();\nprivate:\n    void DelayStartDrag(int32 InUserIndex, int32 InPointerIndex);\n    void OnDragEnd(UEventContext* Context);\n\n    UPROPERTY(Transient)\n    UGLoader* Agent;\n    FNVariant UserData;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/UI/FieldTypes.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"FieldTypes.generated.h\"\n\nUENUM()\nenum class EPackageItemType\n{\n    Image,\n    MovieClip,\n    Sound,\n    Component,\n    Atlas,\n    Font,\n    Swf,\n    Misc,\n    Unknown,\n    Spine,\n    DragonBones\n};\n\nUENUM()\nenum class EObjectType\n{\n    Image,\n    MovieClip,\n    Swf,\n    Graph,\n    Loader,\n    Group,\n    Text,\n    RichText,\n    InputText,\n    Component,\n    List,\n    Label,\n    Button,\n    ComboBox,\n    ProgressBar,\n    Slider,\n    ScrollBar,\n    Tree,\n    Loader3D\n};\n\nUENUM()\nenum class EButtonMode : uint8\n{\n    Common,\n    Check,\n    Radio\n};\n\nUENUM()\nenum class EChildrenRenderOrder : uint8\n{\n    Ascent,\n    Descent,\n    Arch,\n};\n\nUENUM()\nenum class EOverflowType : uint8\n{\n    Visible,\n    Hidden,\n    Scroll\n};\n\nUENUM()\nenum class EScrollType : uint8\n{\n    Horizontal,\n    Vertical,\n    Both\n};\n\nUENUM()\nenum class EScrollBarDisplayType : uint8\n{\n    Default,\n    Visible,\n    Auto,\n    Hidden\n};\n\nUENUM()\nenum class ELoaderFillType : uint8\n{\n    None,\n    Scale,\n    ScaleMatchHeight,\n    ScaleMatchWidth,\n    ScaleFree,\n    ScaleNoBorder\n};\n\nUENUM()\nenum class EProgressTitleType : uint8\n{\n    Percent,\n    ValueMax,\n    Value,\n    Max\n};\n\nUENUM()\nenum class EListLayoutType : uint8\n{\n    SingleColumn,\n    SingleRow,\n    FlowHorizontal,\n    FlowVertical,\n    Pagination\n};\n\nUENUM()\nenum class EListSelectionMode : uint8\n{\n    Single,\n    Multiple,\n    MultipleSingleclick,\n    None\n};\n\nUENUM()\nenum class EGroupLayoutType : uint8\n{\n    None,\n    Horizontal,\n    Vertical\n};\n\nUENUM()\nenum class EPopupDirection : uint8\n{\n    Auto,\n    Up,\n    Down\n};\n\nUENUM()\nenum class EAutoSizeType : uint8\n{\n    None,\n    Both,\n    Height,\n    Shrink\n};\n\nUENUM()\nenum class EFlipType : uint8\n{\n    None,\n    Horizontal,\n    Vertical,\n    Both\n};\n\nUENUM()\nenum class ETransitionActionType\n{\n    XY,\n    Size,\n    Scale,\n    Pivot,\n    Alpha,\n    Rotation,\n    Color,\n    Animation,\n    Visible,\n    Sound,\n    Transition,\n    Shake,\n    ColorFilter,\n    Skew,\n    Text,\n    Icon,\n    Unknown\n};\n\nUENUM()\nenum class EFillMethod : uint8\n{\n    None,\n    Horizontal,\n    Vertical,\n    Radial90,\n    Radial180,\n    Radial360,\n};\n\nUENUM()\nenum class EOriginHorizontal : uint8\n{\n    Left,\n    Right,\n};\n\nUENUM()\nenum class EOriginVertical : uint8\n{\n    Top,\n    Bottom\n};\n\nUENUM()\nenum class EOrigin90 : uint8\n{\n    TopLeft,\n    TopRight,\n    BottomLeft,\n    BottomRight\n};\n\nUENUM()\nenum class EOrigin180 : uint8\n{\n    Top,\n    Bottom,\n    Left,\n    Right\n};\n\nUENUM()\nenum class EOrigin360 : uint8\n{\n    Top,\n    Bottom,\n    Left,\n    Right\n};\n\nUENUM()\nenum class EObjectPropID\n{\n    Text,\n    Icon,\n    Color,\n    OutlineColor,\n    Playing,\n    Frame,\n    DeltaTime,\n    TimeScale,\n    FontSize,\n    Selected\n};\n\nUENUM()\nenum class EAlignType : uint8\n{\n    Left,\n    Center,\n    Right\n};\n\nUENUM()\nenum class EVerticalAlignType : uint8\n{\n    Top,\n    Middle,\n    Bottom\n};\n\nUENUM()\nenum class ERelationType : uint8\n{\n    Left_Left,\n    Left_Center,\n    Left_Right,\n    Center_Center,\n    Right_Left,\n    Right_Center,\n    Right_Right,\n\n    Top_Top,\n    Top_Middle,\n    Top_Bottom,\n    Middle_Middle,\n    Bottom_Top,\n    Bottom_Middle,\n    Bottom_Bottom,\n\n    Width,\n    Height,\n\n    LeftExt_Left,\n    LeftExt_Right,\n    RightExt_Left,\n    RightExt_Right,\n    TopExt_Top,\n    TopExt_Bottom,\n    BottomExt_Top,\n    BottomExt_Bottom,\n\n    Size\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GButton.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GButton.generated.h\"\n\nclass UGController;\nclass UGTextField;\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGButton : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGButton();\n    virtual ~UGButton();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetTitle() const { return Title; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitle(const FString& InTitle) { SetText(InTitle); };\n\n    virtual const FString& GetText() const override { return Title; }\n    virtual void SetText(const FString& InText) override;\n\n    virtual const FString& GetIcon() const override;\n    virtual void SetIcon(const FString& InIcon) override;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetSelectedTitle() const { return SelectedTitle; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectedTitle(const FString& InTitle);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetSelectedIcon() const { return SelectedIcon; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectedIcon(const FString& InIcon);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetTitleColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleColor(const FColor& InColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetTitleFontSize() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleFontSize(int32 InFontSize);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsSelected() const { return bSelected; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelected(bool bInSelected);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGController* GetRelatedController() const { return RelatedController; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetRelatedController(UGController* InController);\n\n    UGTextField* GetTextField() const;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnChanged;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bChangeStateOnClick;\n\n    static const FString UP;\n    static const FString DOWN;\n    static const FString OVER;\n    static const FString SELECTED_OVER;\n    static const FString DISABLED;\n    static const FString SELECTED_DISABLED;\n\nprotected:\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    virtual void HandleControllerChanged(UGController* Controller) override;\n\n    void SetState(const FString& InState);\n    void SetCurrentState();\n\nprivate:\n    void OnRollOverHandler(UEventContext* Context);\n    void OnRollOutHandler(UEventContext* Context);\n    void OnTouchBeginHandler(UEventContext* Context);\n    void OnTouchEndHandler(UEventContext* Context);\n    void OnClickHandler(UEventContext* Context);\n    void OnRemovedFromStageHandler(UEventContext* Context);\n\n    EButtonMode Mode;\n    UGObject* TitleObject;\n    UGObject* IconObject;\n    UGController* ButtonController;\n    UGController* RelatedController;\n    FString RelatedPageID;\n    FString Title;\n    FString SelectedTitle;\n    FString Icon;\n    FString SelectedIcon;\n    FString Sound;\n    float SoundVolumeScale;\n    bool bSelected;\n    bool bOver;\n    bool bDown;\n    int32 DownEffect;\n    bool bDownScaled;\n    float DownEffectValue;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GComboBox.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GComboBox.generated.h\"\n\nclass UGController;\nclass UGTextField;\nclass UGList;\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGComboBox : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGComboBox();\n    virtual ~UGComboBox();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetTitle() const { return GetText(); }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitle(const FString& InTitle) { SetText(InTitle); };\n\n    virtual const FString& GetText() const override;\n    virtual void SetText(const FString& InText) override;\n\n    virtual const FString& GetIcon() const override;\n    virtual void SetIcon(const FString& InIcon) override;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetTitleColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleColor(const FColor& InColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetTitleFontSize() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleFontSize(int32 InFontSize);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetValue() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetValue(const FString& InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetSelectedIndex() const { return SelectedIndex; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectedIndex(int32 InIndex);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGController* GetSelectionController() const { return SelectionController; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectionController(UGController* InController) { SelectionController = InController; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetDropdown() const { return DropdownObject; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Refresh();\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 VisibleItemCount;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    EPopupDirection PopupDirection;\n\n    UGTextField* GetTextField() const;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    TArray<FString> Items;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    TArray<FString> Icons;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    TArray<FString> Values;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnChanged;\n\nprotected:\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    virtual void HandleControllerChanged(UGController* Controller) override;\n    virtual void HandleGrayedChanged() override;\n\n    void SetState(const FString& InState);\n    void SetCurrentState();\n    void UpdateSelectionController();\n    void UpdateDropdownList();\n    void ShowDropdown();\n    void RenderDropdownList();\n\n    UPROPERTY(Transient)\n    UGComponent* DropdownObject;\n    UGObject* TitleObject;\n    UGObject* IconObject;\n    UGList* ListObject;\n    UGController* SelectionController;\n\nprivate:\n\n    void OnClickItem(UEventContext* Context);\n    void OnRollOverHandler(UEventContext* Context);\n    void OnRollOutHandler(UEventContext* Context);\n    void OnTouchBeginHandler(UEventContext* Context);\n    void OnTouchEndHandler(UEventContext* Context);\n    void OnPopupWinClosed(UEventContext* Context);\n\n    bool bItemsUpdated;\n    int32 SelectedIndex;\n    UGController* ButtonController;\n    bool bDown;\n    bool bOver;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GComponent.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"ScrollPane.h\"\n#include \"GComponent.generated.h\"\n\nclass UGController;\nclass UTransition;\nclass SContainer;\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGComponent : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGComponent();\n    virtual ~UGComponent();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* AddChild(UGObject* Child);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual UGObject* AddChildAt(UGObject* Child, int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChild(UGObject* Child);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual void RemoveChildAt(int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChildren(int32 BeginIndex = 0, int32 EndIndex = -1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DeterminesOutputType = \"ClassType\"))\n    UGObject* GetChildAt(int32 Index, TSubclassOf<UGObject> ClassType = nullptr) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DeterminesOutputType = \"ClassType\"))\n    UGObject* GetChild(const FString& ChildName, TSubclassOf<UGObject> ClassType = nullptr) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DeterminesOutputType = \"ClassType\"))\n    UGObject* GetChildByPath(const FString& Path, TSubclassOf<UGObject> ClassType = nullptr) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DeterminesOutputType = \"ClassType\"))\n    UGObject* GetChildInGroup(const UGGroup* Group, const FString& ChildName, TSubclassOf<UGObject> ClassType = nullptr) const;\n\n    UGObject* GetChildByID(const FString& ChildID) const;\n    const TArray<UGObject*>& GetChildren() const { return Children; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetChildIndex(const UGObject* Child) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetChildIndex(UGObject* Child, int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 SetChildIndexBefore(UGObject* Child, int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SwapChildren(UGObject* Child1, UGObject* Child2);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SwapChildrenAt(int32 Index1, int32 Index2);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 NumChildren() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsAncestorOf(const UGObject* Obj) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual bool IsChildInView(UGObject* Child) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual int32 GetFirstChildInView() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGController* GetControllerAt(int32 Index) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGController* GetController(const FString& ControllerName) const;\n\n    const TArray<UGController*>& GetControllers() const { return Controllers; }\n    void AddController(UGController* Controller);\n    void RemoveController(UGController* Controller);\n    void ApplyController(UGController* Controller);\n    void ApplyAllControllers();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UTransition* GetTransition(const FString& TransitionName) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UTransition* GetTransitionAt(int32 Index) const;\n\n    const TArray<UTransition*>& GetTransitions() const { return Transitions; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsOpaque() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetOpaque(bool bInOpaque);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FMargin& GetMargin() { return Margin; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMargin(const FMargin& InMargin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EChildrenRenderOrder GetChildrenRenderOrder() const { return ChildrenRenderOrder; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetChildrenRenderOrder(EChildrenRenderOrder InChildrenRenderOrder);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetApexIndex() const { return ApexIndex; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetApexIndex(int32 InApedIndex);\n\n    //UGObject* getMask() const;\n    //void setMask(UGObject* value, bool inverted = false);\n\n    virtual IHitTest* GetHitArea() const override { return HitArea.Get(); }\n    void SetHitArea(const TSharedPtr<IHitTest>& InHitArea);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UScrollPane* GetScrollPane() const { return ScrollPane; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetViewWidth() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetViewWidth(float InViewWidth);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetViewHeight() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetViewHeight(float InViewHeight);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetBoundsChangedFlag();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void EnsureBoundsCorrect();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void OnClickChild(const FString& ChildName, const FGUIEventDynDelegate& Delegate)\n    {\n        GetChild(ChildName)->OnClick.AddUnique(Delegate);\n    }\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnDrop;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnScroll;\n   \n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnScrollEnd;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnPullUpRelease;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnPullDownRelease;\n\n    virtual FVector2D GetSnappingPosition(const FVector2D& InPoint);\n\n    //internal use\n    void ChildSortingOrderChanged(UGObject* Child, int32 OldValue, int32 NewValue);\n    void ChildStateChanged(UGObject* Child);\n    void AdjustRadioGroupDepth(UGObject* Child, UGController* Controller);\n\n    virtual void ConstructFromResource() override;\n    void ConstructFromResource(TArray<UGObject*>* ObjectPool, int32 PoolIndex);\n\n    bool bBuildingDisplayList;\n\nprotected:\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n    virtual void OnConstruct();\n    UFUNCTION(BlueprintImplementableEvent, Category = \"FairyGUI\",  meta = ( DisplayName = \"OnConstruct\"))\n    void K2_OnConstruct();\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void HandleSizeChanged() override;\n    virtual void HandleGrayedChanged() override;\n    virtual void HandleControllerChanged(UGController* Controller) override;\n\n    virtual void UpdateBounds();\n    void SetBounds(float ax, float ay, float aw, float ah);\n\n    void SetupOverflow(EOverflowType InOverflow);\n    void SetupScroll(FByteBuffer* Buffer);\n\n    UPROPERTY(Transient)\n    TArray<UGObject*> Children;\n    UPROPERTY(Transient)\n    TArray<UGController*> Controllers;\n    UPROPERTY(Transient)\n    TArray<UTransition*> Transitions;\n    UPROPERTY(Transient)\n    UScrollPane* ScrollPane;\n\n    TSharedPtr<SContainer> RootContainer;\n    TSharedPtr<SContainer> Container;\n    FMargin Margin;\n    FVector2D AlignOffset;\n    EChildrenRenderOrder ChildrenRenderOrder;\n    int32 ApexIndex;\n    uint8 bBoundsChanged : 1;\n    uint8 bTrackBounds : 1;\n    TSharedPtr<IHitTest> HitArea;\n\nprivate:\n    int32 GetInsertPosForSortingChild(UGObject* Child);\n    int32 MoveChild(UGObject* Child, int32 OldIndex, int32 NewIndex);\n\n    void BuildNativeDisplayList(bool bImmediatelly = false);\n\n    void OnAddedToStageHandler(UEventContext* Context);\n    void OnRemovedFromStageHandler(UEventContext* Context);\n\n    int32 SortingChildCount;\n    UGController* ApplyingController;\n\n    FTimerHandle UpdateBoundsTimerHandle;\n    FTimerHandle BuildDisplayListTimerHandle;\n\n    friend class UScrollPane;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GController.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"ControllerAction/ControllerAction.h\"\n#include \"GController.generated.h\"\n\nclass UGComponent;\nclass FByteBuffer;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGController : public UObject\n{\n    GENERATED_BODY()\npublic:\n    UGController();\n    virtual ~UGController();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetSelectedIndex() const { return SelectedIndex; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectedIndex(int32 Index);\n    void SetSelectedIndex(int32 Index, bool bTriggerEvent);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetSelectedPage() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectedPage(const FString& PageName);\n    void SetSelectedPage(const FString& PageName, bool bTriggerEvent);\n\n    const FString& GetSelectedPageID() const;\n    void SetSelectedPageID(const FString& PageID, bool bTriggerEvent = true);\n\n    int32 GetPrevisousIndex() const { return PreviousIndex; }\n    const FString& GetPreviousPage() const;\n    const FString& GetPreviousPageID() const;\n\n    int32 GetPageCount() const;\n    bool HasPage(const FString& PageName) const;\n    int32 GetPageIndexByID(const FString& PageID) const;\n    const FString& GetPageNameByID(const FString& PageID) const;\n    const FString& GetPageID(int32 Index) const;\n    void SetOppositePageID(const FString& PageID);\n    void RunActions();\n\n    void Setup(FByteBuffer* Buffer);\n\n    FString Name;\n    bool bChanging;\n    bool bAutoRadioGroupDepth;\n\n    DECLARE_EVENT_OneParam(UGController, FOnChanged, UGController*);\n    FOnChanged& OnChanged() { return OnChangedEvent; }\n\nprivate:\n    int32 SelectedIndex;\n    int32 PreviousIndex;\n    TArray<FString> PageIDs;\n    TArray<FString> PageNames;\n    TIndirectArray<FControllerAction> Actions;\n\n    FOnChanged OnChangedEvent;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GGraph.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"GGraph.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGGraph : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGGraph();\n    virtual ~UGGraph();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetColor() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColor(const FColor& InColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"LineColor,FillColor\"))\n    void DrawRect(float LineWidth, const FColor& LineColor, const FColor& FillColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"LineColor,FillColor\"))\n    void DrawRoundRect(float LineWidth, const FColor& LineColor, const FColor& FillColor, float TopLeftRadius, float TopRightRadius, float BottomLeftRadius, float BottomRightRadius);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"LineColor,FillColor\"))\n    void DrawEllipse(float LineWidth, const FColor& LineColor, const FColor& FillColor, float StartDegree = 0, float EndDegree = 360);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"LineColor,FillColor,Points\"))\n    void DrawPolygon(float LineWidth, const FColor& LineColor, const FColor& FillColor, const TArray<FVector2D>& Points);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"LineColor,FillColor,Distances\"))\n    void DrawRegularPolygon(int32 Sides, float LineWidth, const FColor& LineColor, const FColor& FillColor, float Rotation, const TArray<float>& Distances);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Clear();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsEmpty() const;\n\n    virtual IHitTest* GetHitArea() const override;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\nprivate:\n    TSharedPtr<class SShape> Content;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GGroup.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"GGroup.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGGroup : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGGroup();\n    virtual ~UGGroup();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EGroupLayoutType GetLayout() { return Layout; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetLayout(EGroupLayoutType InLayout);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetColumnGap() { return ColumnGap; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColumnGap(int32 InColumnGap);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetLineGap() { return LineGap; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetLineGap(int32 InLineGap);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsExcludeInvisibles() { return bExcludeInvisibles; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetExcludeInvisibles(bool bInFlag);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsAutoSizeDisabled() { return bAutoSizeDisabled; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAutoSizeDisabled(bool bInFlag);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetMainGridIndex() { return MainGridIndex; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMainGridIndex(int32 InIndex);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetMainGridMinSize() { return MainGridMinSize; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMainGridMinSize(int32 InSize);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetBoundsChangedFlag(bool bPositionChangedOnly = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void EnsureBoundsCorrect();\n\n    void MoveChildren(const FVector2D& Delta);\n    void ResizeChildren(const FVector2D& Delta);\n\n    uint8 Updating;\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void HandleAlphaChanged() override;\n    virtual void HandleVisibleChanged() override;\n\nprivate:\n    void UpdateBounds();\n    void HandleLayout();\n\n    EGroupLayoutType Layout;\n    int32 LineGap;\n    int32 ColumnGap;\n    bool bExcludeInvisibles;\n    bool bAutoSizeDisabled;\n    int32 MainGridIndex;\n    int32 MainGridMinSize;\n\n    bool bPercentReady;\n    bool bBoundsChanged;\n    int32 MainChildIndex;\n    float TotalSize;\n    int32 NumChildren;\n\n    FTimerHandle UpdateBoundsTimerHandle;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GImage.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"GImage.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGImage : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGImage();\n    virtual ~UGImage();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EFlipType GetFlip() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFlip(EFlipType InFlip);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColor(const FColor& InColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EFillMethod GetFillMethod() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillMethod(EFillMethod Method);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetFillOrigin() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillOrigin(int32 Origin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsFillClockwise() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillClockwise(bool bClockwise);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetFillAmount() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillAmount(float Amount);\n\n    virtual void ConstructFromResource() override;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\nprivate:\n    TSharedPtr<class SFImage> Content;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GLabel.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GLabel.generated.h\"\n\nclass UGTextField;\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGLabel : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGLabel();\n    virtual ~UGLabel();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetTitle() const { return GetText(); }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitle(const FString& InTitle) { SetText(InTitle); };\n\n    virtual const FString& GetText() const override;\n    virtual void SetText(const FString& InText) override;\n\n    virtual const FString& GetIcon() const override;\n    virtual void SetIcon(const FString& InIcon) override;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetTitleColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleColor(const FColor& InColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetTitleFontSize() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleFontSize(int32 value);\n\n    UGTextField* GetTextField() const;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\nprotected:\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    UGObject* TitleObject;\n    UGObject* IconObject;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GList.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GList.generated.h\"\n\nclass FGObjectPool;\n\nDECLARE_DELEGATE_TwoParams(FListItemRenderer, int32, UGObject*);\nDECLARE_DELEGATE_RetVal_OneParam(FString, FListItemProvider, int32);\n\nDECLARE_DYNAMIC_DELEGATE_TwoParams(FDynListItemRenderer, int32, Index, UGObject*, Obj);\nDECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(FString, FDynListItemProvider, int32, Index);\n\nUCLASS(BlueprintType, NotBlueprintable)\nclass FAIRYGUI_API UGList : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGList();\n    virtual ~UGList();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetDefaultItem() const { return DefaultItem; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetDefaultItem(const FString& InDefaultItem);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EListLayoutType GetLayout() const { return Layout; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetLayout(EListLayoutType InLayout);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetLineCount() const { return LineCount; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetLineCount(int32 InLineCount);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetColumnCount() { return ColumnCount; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColumnCount(int32 InColumnCount);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetColumnGap() const { return ColumnGap; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColumnGap(int32 InColumnGap);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetLineGap() const { return LineGap; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetLineGap(int32 InLineGap);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EAlignType GetAlign() const { return Align; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAlign(EAlignType InAlign);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EVerticalAlignType GetVerticalAlign() const { return VerticalAlign; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetVerticalAlign(EVerticalAlignType InVerticalAlign);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool GetAutoResizeItem() const { return bAutoResizeItem; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAutoResizeItem(bool bFlag);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EListSelectionMode GetSelectionMode() const { return SelectionMode; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectionMode(EListSelectionMode InMode) { SelectionMode = InMode; }\n\n    FGObjectPool* GetItemPool() const { return Pool; }\n    UGObject* GetFromPool();\n    UGObject* GetFromPool(const FString& URL);\n    void ReturnToPool(UGObject* Obj);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* AddItemFromPool(const FString& URL = \"\");\n\n    virtual UGObject* AddChildAt(UGObject* Child, int32 Index) override;\n    virtual void RemoveChildAt(int32 Index) override;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChildToPoolAt(int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChildToPool(UGObject* Child);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChildrenToPool(int32 BeginIndex = 0, int32 EndIndex = -1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetSelectedIndex() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectedIndex(int32 Index);\n\n    void GetSelection(TArray<int32>& OutIndice) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void AddSelection(int32 Index, bool bScrollItToView);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveSelection(int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ClearSelection();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SelectAll();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SelectReverse();\n\n    void HandleArrowKey(int32 Direction);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ResizeToFit(int32 ItemCount, int32 InMinSize = 0);\n\n    virtual int32 GetFirstChildInView() const override;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollToView(int32 Index, bool bAnimation = false, bool bSetFirst = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGController* GetSelectionController() const { return SelectionController; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSelectionController(UGController* InController);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetVirtual();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetVirtualAndLoop();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsVirtual() const { return bVirtual; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RefreshVirtualList();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetNumItems() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetNumItems(int32 InNumItems);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 ChildIndexToItemIndex(int32 Index) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 ItemIndexToChildIndex(int32 Index) const;\n\n    virtual FVector2D GetSnappingPosition(const FVector2D& InPoint) override;\n\n    void SetItemRenderer(const FListItemRenderer& InItemRenderer) { ItemRenderer = InItemRenderer; }\n    void SetItemProvider(const FListItemProvider& InItemProvider) { ItemProvider = InItemProvider; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemRenderer(const FDynListItemRenderer& InItemRenderer)\n    { \n        if (InItemRenderer.IsBound())\n            ItemRenderer = FListItemRenderer::CreateUFunction(const_cast<UObject*>(InItemRenderer.GetUObject()), InItemRenderer.GetFunctionName());\n        else\n            ItemRenderer.Unbind();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemProvider(const FDynListItemProvider& InItemProvider)\n    { \n        if (InItemProvider.IsBound())\n            ItemProvider = FListItemProvider::CreateUFunction(const_cast<UObject*>(InItemProvider.GetUObject()), InItemProvider.GetFunctionName());\n        else\n            ItemProvider.Unbind();\n    }\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnClickItem;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bScrollItemToViewOnClick;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bFoldInvisibleItems;\n\nprotected:\n    virtual void HandleControllerChanged(UGController* Controller) override;\n    virtual void HandleSizeChanged() override;\n    virtual void UpdateBounds() override;\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    virtual void DispatchItemEvent(UGObject* Obj, UEventContext* Context);\n    virtual void ReadItems(FByteBuffer* Buffer);\n    virtual void SetupItem(FByteBuffer* Buffer, UGObject* Obj);\n\nprivate:\n    void ClearSelectionExcept(UGObject* Obj);\n    void SetSelectionOnEvent(UGObject* Obj, UEventContext* Context);\n\n    UFUNCTION()\n    void OnClickItemHandler(UEventContext* Context);\n\n    void UpdateSelectionController(int32 Index);\n\n    void SetVirtual(bool bLoop);\n    void CheckVirtualList();\n    void SetVirtualListChangedFlag(bool bLayoutChanged);\n    void DoRefreshVirtualList();\n\n    void OnScrollHandler(UEventContext* Context);\n\n    int32 GetIndexOnPos1(float& pos, bool forceUpdate);\n    int32 GetIndexOnPos2(float& pos, bool forceUpdate);\n    int32 GetIndexOnPos3(float& pos, bool forceUpdate);\n\n    void HandleScroll(bool forceUpdate);\n    bool HandleScroll1(bool forceUpdate);\n    bool HandleScroll2(bool forceUpdate);\n    void HandleScroll3(bool forceUpdate);\n\n    void HandleArchOrder1();\n    void HandleArchOrder2();\n\n    void HandleAlign(float InContentWidth, float InContentHeight);\n\n    FString DefaultItem;\n    EListLayoutType Layout;\n    int32 LineCount;\n    int32 ColumnCount;\n    int32 LineGap;\n    int32 ColumnGap;\n    EAlignType Align;\n    EVerticalAlignType VerticalAlign;\n    bool bAutoResizeItem;\n    EListSelectionMode SelectionMode;\n    UGController* SelectionController;\n    FListItemRenderer ItemRenderer;\n    FListItemProvider ItemProvider;\n\n    FGObjectPool* Pool;\n    int32 LastSelectedIndex;\n\n    //Virtual List support\n    bool bVirtual;\n    bool bLoop;\n    int32 NumItems;\n    int32 RealNumItems;\n    int32 FirstIndex;        //the top left index\n    int32 CurLineItemCount;  //item count in one line\n    int32 CurLineItemCount2; //item count in vertical direction,only pagination layout\n    FVector2D ItemSize;\n    int32 VirtualListChanged; //1-content changed, 2-size changed\n    bool bEventLocked;\n    uint32 ItemInfoVer;\n    FTimerHandle RefreshTimerHandle;\n\n    struct FItemInfo\n    {\n        FVector2D Size;\n        UGObject* Obj;\n        uint32 UpdateFlag;\n        bool bSelected;\n\n        FItemInfo();\n    };\n    TArray<FItemInfo> VirtualItems;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GLoader.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"GLoader.generated.h\"\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGLoader : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGLoader();\n    virtual ~UGLoader();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetURL() const { return URL; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetURL(const FString& InURL);\n\n    virtual const FString& GetIcon() const override { return URL; }\n    virtual void SetIcon(const FString& InIcon) override { SetURL(InIcon); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EAlignType GetAlign() const { return Align; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAlign(EAlignType InAlign);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EVerticalAlignType GetVerticalAlign() const { return VerticalAlign; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetVerticalAlign(EVerticalAlignType InVerticalAlign);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool GetAutoSize() const { return bAutoSize; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAutoSize(bool bInAutoSize);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    ELoaderFillType GetFill() const { return Fill; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFill(ELoaderFillType InFillType);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsShrinkOnly() const { return bShrinkOnly; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetShrinkOnly(bool bInShrinkOnly);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EFlipType GetFlip() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFlip(EFlipType InFlip);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColor(const FColor& InColor);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EFillMethod GetFillMethod() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillMethod(EFillMethod Method);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetFillOrigin() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillOrigin(int32 Origin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsFillClockwise() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillClockwise(bool bClockwise);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetFillAmount() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFillAmount(float Amount);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsPlaying() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPlaying(bool bInPlaying);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetFrame() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFrame(int32 InFrame);\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue);\n\nprotected:\n    virtual void HandleSizeChanged() override;\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    void LoadContent();\n    void ClearContent();\n    void LoadFromPackage(const FString& ItemURL);\n    void LoadExternal();\n    void OnExternalLoaded(FString LoadingURL);\n    void UpdateLayout();\n    void SetErrorState();\n\n    TSharedPtr<FSoftObjectPath> SoftObjectPath;\n\nprivate:\n    TSharedPtr<class SContainer> Container;\n    TSharedPtr<class SMovieClip> Content;\n    UPROPERTY(Transient)\n    UGObject* Content2;\n    TSharedPtr<FPackageItem> ContentItem;\n    FString URL;\n    ELoaderFillType Fill;\n    EAlignType Align;\n    EVerticalAlignType VerticalAlign;\n    uint8 bShowErrorSign : 1;\n    uint8 bShrinkOnly : 1;\n    uint8 bAutoSize : 1;\n    uint8 bUpdatingLayout : 1;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GLoader3D.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"GLoader3D.generated.h\"\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGLoader3D : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGLoader3D();\n    virtual ~UGLoader3D();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetURL() const { return URL; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetURL(const FString& InURL);\n\n    virtual const FString& GetIcon() const override { return URL; }\n    virtual void SetIcon(const FString& InIcon) override { SetURL(InIcon); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColor(const FColor& InColor);\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue);\n\nprotected:\n    virtual void HandleSizeChanged() override;\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    void LoadContent();\n    void ClearContent();\n    void LoadFromPackage(const FString& ItemURL);\n    void LoadExternal();\n    void UpdateLayout();\n    void SetErrorState();\n\nprivate:\n    TSharedPtr<class SFImage> Content;\n    TSharedPtr<FPackageItem> ContentItem;\n    FString URL;\n    ELoaderFillType Fill;\n    EAlignType Align;\n    EVerticalAlignType VerticalAlign;\n    bool bShowErrorSign;\n    bool bShrinkOnly;\n    bool bAutoSize;\n    bool bUpdatingLayout;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GMovieClip.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"Event/EventContext.h\"\n#include \"GMovieClip.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGMovieClip : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGMovieClip();\n    virtual ~UGMovieClip();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsPlaying() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPlaying(bool bInPlaying);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetFrame() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFrame(int32 InFrame);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetTimeScale() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTimeScale(float InTimeScale);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Advance(float Time);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EFlipType GetFlip() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetFlip(EFlipType InFlip);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FColor GetColor() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetColor(const FColor& InColor);\n\n    //from start to end(-1 means ending) repeat times(0 means infinite loop) when all is over, stopping at endAt(-1 means same value of end)\n    void SetPlaySettings(int32 InStart = 0, int32 InEnd = -1, int32 InTimes = 0, int32 InEndAt = -1, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate());\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"InCompleteCallback\"))\n    void SetPlaySettings(const FSimpleDynDelegate& InCompleteCallback, int32 InStart = 0, int32 InEnd = -1, int32 InTimes = 0, int32 InEndAt = -1)\n    {\n        SetPlaySettings(InStart, InEnd, InTimes, InEndAt,\n            InCompleteCallback.IsBound() ?\n            FSimpleDelegate::CreateUFunction(const_cast<UObject*>(InCompleteCallback.GetUObject()), InCompleteCallback.GetFunctionName())\n            : FSimpleDelegate());\n    }\n\n    virtual void ConstructFromResource() override;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\nprivate:\n    TSharedPtr<class SMovieClip> Content;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GObject.h",
    "content": "#pragma once\n\n#include \"Relations.h\"\n#include \"PackageItem.h\"\n#include \"UIConfig.h\"\n#include \"FairyCommons.h\"\n#include \"Widgets/SDisplayObject.h\"\n#include \"Widgets/HitTest.h\"\n#include \"Event/EventContext.h\"\n#include \"Utils/NVariant.h\"\n#include \"GObject.generated.h\"\n\nclass FByteBuffer;\nclass FRelations;\nclass FGearBase;\n\nclass UGGroup;\nclass UGComponent;\nclass UGTreeNode;\nclass UGController;\nclass UGRoot;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGObject : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGObject();\n    virtual ~UGObject();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetX() const { return Position.X; };\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetX(float InX);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetY() const { return Position.Y; };\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetY(float InY);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetPosition() const { return Position; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPosition(const FVector2D& InPosition);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetXMin() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetXMin(float InXMin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetYMin() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetYMin(float InYMin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetWidth() const { return Size.X; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetWidth(float InWidth) { SetSize(FVector2D(InWidth, RawSize.Y)); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetHeight() const { return Size.Y; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetHeight(float InHeight) { SetSize(FVector2D(RawSize.X, InHeight)); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetSize() const { return Size; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AdvancedDisplay=\"bIgnorePivot\"))\n    void SetSize(const FVector2D& InSize, bool bIgnorePivot = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Center(bool bRestraint = false);\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void MakeFullScreen(bool bRestraint = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetPivot() const { return Pivot; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPivot(const FVector2D& InPivot, bool bAsAnchor = false);\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsPivotAsAnchor() const { return bPivotAsAnchor; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetScaleX() const { return Scale.X; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetScaleX(float InScaleX) { SetScale(FVector2D(InScaleX, Scale.Y)); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetScaleY() const { return Scale.Y; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetScaleY(float InScaleY) { SetScale(FVector2D(Scale.X, InScaleY)); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetScale() const { return Scale; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetScale(const FVector2D& InScale);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetSkew() const { return Skew; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSkew(const FVector2D& InSkew);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetRotation() const { return Rotation; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetRotation(float InRotation);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetAlpha() const { return Alpha; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAlpha(float InAlpha);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsGrayed() const { return bGrayed; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetGrayed(bool bInGrayed);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsVisible() const { return bVisible; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetVisible(bool bInVisible);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsTouchable() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTouchable(bool bInTouchable);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetSortingOrder() const { return SortingOrder; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSortingOrder(int32 InSortingOrder);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGGroup* GetGroup() const { return Group.Get(); }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetGroup(UGGroup* InGroup);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual const FString& GetText() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual void SetText(const FString& InText);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual const FString& GetIcon() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual void SetIcon(const FString& InIcon);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetTooltips() const { return Tooltips; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTooltips(const FString& InTooltips);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsDraggable() const { return bDraggable; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetDraggable(bool bInDraggable);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FBox2D GetDragBounds() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetDragBounds(const FBox2D& InBounds);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void StartDrag(int32 UserIndex, int32 PointerIndex);\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void StopDrag();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FString GetResourceURL() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FString GetResourceName() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FString GetPackageName() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FVector2D GlobalToLocal(const FVector2D& InPoint);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FBox2D GlobalToLocalRect(const FBox2D& InRect);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FVector2D RootToLocal(const FVector2D& InPoint);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FBox2D RootToLocalRect(const FBox2D& InRect);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FVector2D LocalToGlobal(const FVector2D& InPoint);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FBox2D LocalToGlobalRect(const FBox2D& InRect);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FVector2D LocalToRoot(const FVector2D& InPoint);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    FBox2D LocalToRootRect(const FBox2D& InRect);\n\n    const TSharedPtr<FRelations>& GetRelations() { return Relations; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void AddRelation(UGObject* Obj, ERelationType RelationType, bool bUsePercent = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveRelation(UGObject* Obj, ERelationType RelationType);\n\n    const TSharedPtr<FGearBase>& GetGear(int32 Index);\n    bool CheckGearController(int32 Index, UGController* Controller);\n    uint32 AddDisplayLock();\n    void ReleaseDisplayLock(uint32 Token);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetParent() const { return Parent.Get(); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetParent(UGObject* InParent);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetParentToRoot();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGRoot* GetUIRoot() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UFairyApplication* GetApp() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool OnStage() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveFromParent();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DeterminesOutputType = \"ClassType\"))\n    UGObject* CastTo(TSubclassOf<UGObject> ClassType) const;\n\n    template <typename T> T* As() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetTreeNode() const { return TreeNode; }\n\n    TSharedPtr<FPackageItem> GetPackageItem() const { return PackageItem; }\n    TSharedRef<SDisplayObject> GetDisplayObject() const { return DisplayObject.ToSharedRef(); }\n\n    virtual IHitTest* GetHitArea() const { return nullptr; }\n\n    template <typename T> T GetProp(EObjectPropID PropID) const;\n    virtual FNVariant GetProp(EObjectPropID PropID) const;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue);\n\n    virtual void ConstructFromResource();\n\npublic:\n    bool DispatchEvent(const FName& EventType, const FNVariant& Data = FNVariant::Null);\n    bool HasEventListener(const FName& EventType) const;\n    void InvokeEventDelegate(UEventContext* Context);\n    FGUIEventMDelegate& On(const FName& EventType);\n\n    FSimpleMulticastDelegate& OnPositionChanged()\n    {\n        return OnPositionChangedEvent;\n    }\n\n    FSimpleMulticastDelegate& OnSizeChanged()\n    {\n        return OnSizeChangedEvent;\n    }\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnClick;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnTouchBegin;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnTouchMove;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnTouchEnd;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnRollOver;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnRollOut;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnDragStart;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnDragMove;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnDragEnd;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnGearStop;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnAddedToStage;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnRemovedFromStage;\n\npublic:\n    UPROPERTY(Transient, BlueprintReadOnly, Category = \"FairyGUI\")\n    FString ID;\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString Name;\n\n    UPROPERTY(Transient, BlueprintReadOnly, Category = \"FairyGUI\")\n    FVector2D SourceSize;\n    UPROPERTY(Transient, BlueprintReadOnly, Category = \"FairyGUI\")\n    FVector2D InitSize;\n    UPROPERTY(Transient, BlueprintReadWrite, Category = \"FairyGUI\")\n    FVector2D MinSize;\n    UPROPERTY(Transient, BlueprintReadWrite, Category = \"FairyGUI\")\n    FVector2D MaxSize;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FNVariant UserData;\n    \n    bool bUnderConstruct;\n    bool bGearLocked;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static UGObject* GetDraggingObject() { return DraggingObject.Get(); }\n\npublic:\n    virtual UWorld* GetWorld() const override;\n\nprotected:\n    TWeakObjectPtr<UGComponent> Parent;\n    TSharedPtr<SDisplayObject> DisplayObject;\n    TSharedPtr<FPackageItem> PackageItem;\n\n    virtual void HandleSizeChanged();\n    virtual void HandleGrayedChanged();\n    virtual void HandlePositionChanged();\n    virtual void HandleControllerChanged(UGController* Controller);\n    virtual void HandleAlphaChanged();\n    virtual void HandleVisibleChanged();\n\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos);\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos);\n\n    void UpdateGear(int32 Index);\n    void CheckGearDisplay();\n\n    void SetSizeDirectly(const FVector2D& InSize);\n\n    FVector2D Position;\n    FVector2D Size;\n    FVector2D RawSize;\n    FVector2D Pivot;\n    FVector2D Scale;\n    FVector2D Skew;\n    uint8 bPivotAsAnchor : 1;\n    float Alpha;\n    float Rotation;\n    uint8 bVisible : 1;\n    uint8 bGrayed : 1;\n\nprivate:\n    bool InternalVisible() const;\n    bool InternalVisible2() const;\n    bool InternalVisible3() const;\n    void UpdateGearFromRelations(int32 Index, const FVector2D& Delta);\n    void UpdateTransform();\n\n    UFUNCTION()\n    void OnRollOverHandler(UEventContext* Context);\n    UFUNCTION()\n    void OnRollOutHandler(UEventContext* Context);\n\n    void InitDrag();\n    void DragBegin(int32 UserIndex, int32 PointerIndex);\n    void DragEnd();\n\n    UFUNCTION()\n    void OnTouchBeginHandler(UEventContext* Context);\n    UFUNCTION()\n    void OnTouchMoveHandler(UEventContext* Context);\n    UFUNCTION()\n    void OnTouchEndHandler(UEventContext* Context);\n\n    uint8 bInternalVisible : 1;\n    uint8 bHandlingController : 1;\n    uint8 bDraggable : 1;\n    int32 SortingOrder;\n    FString Tooltips;\n    TWeakObjectPtr<UGGroup> Group;\n    float SizePercentInGroup;\n    TSharedPtr<FRelations> Relations;\n    TSharedPtr<FGearBase> Gears[10];\n    FVector2D DragTouchStartPos;\n    TOptional<FBox2D> DragBounds;\n    uint8 bDragTesting : 1;\n    UGTreeNode* TreeNode;\n    UFairyApplication* CachedApp;\n\n    struct FUnifiedEventDelegate\n    {\n        FGUIEventMDelegate Func;\n        FGUIEventDynMDelegate* DynFunc;\n    };\n    TMap<FName, FUnifiedEventDelegate> EventDelegates;\n    FUnifiedEventDelegate& GetEventDelegate(const FName& EventType);\n\n    FSimpleMulticastDelegate OnPositionChangedEvent;\n    FSimpleMulticastDelegate OnSizeChangedEvent;\n\n    static TWeakObjectPtr<UGObject> DraggingObject;\n    static FVector2D GlobalDragStart;\n    static FBox2D GlobalRect;\n    static bool bUpdateInDragging;\n\n    friend class UGComponent;\n    friend class UGGroup;\n    friend class FRelationItem;\n    friend class FUIObjectFactory;\n    friend class UGTree;\n};\n\ntemplate <typename T>\ninline T* UGObject::As() const\n{\n    return const_cast<T*>(Cast<T>(this));\n}\n\ntemplate <typename T>\ninline T UGObject::GetProp(EObjectPropID PropID) const\n{\n    return GetProp(PropID).As<T>();\n}"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GObjectPool.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n\nclass UGObject;\n\nclass FGObjectPool : public FGCObject\n{\npublic:\n    UGObject* GetObject(const FString& URL, UObject* WorldContextObject);\n    void ReturnObject(UGObject* Obj);\n\n    virtual void AddReferencedObjects(FReferenceCollector& Collector) override;\n\nprivate:\n    TMap<FString, TArray<UGObject*>> Pool;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GProgressBar.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GProgressBar.generated.h\"\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGProgressBar : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGProgressBar();\n    virtual ~UGProgressBar();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EProgressTitleType GetTitleType() const { return TitleType; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleType(EProgressTitleType InType);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetMin() const { return Min; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMin(float InMin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetMax() const { return Max; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMax(float InMax);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetValue() const { return Value; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetValue(float InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void TweenValue(float InValue, float Duration);\n\n    void Update(float NewValue);\n\nprotected:\n    virtual void HandleSizeChanged() override;\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    bool SetFillAmount(UGObject* Bar, float Amount);\n\nprivate:\n    float Min;\n    float Max;\n    float Value;\n    EProgressTitleType TitleType;\n    bool bReverse;\n    FTweenerHandle TweenHandle;\n\n    UGObject* TitleObject;\n    UGObject* BarObjectH;\n    UGObject* BarObjectV;\n    FVector2D BarMaxSize;\n    FVector2D BarMaxSizeDelta;\n    FVector2D BarStartPosition;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GRichTextField.h",
    "content": "#pragma once\n\n#include \"GTextField.h\"\n#include \"GRichTextField.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGRichTextField : public UGTextField\n{\n    GENERATED_BODY()\n\npublic:\n    UGRichTextField();\n    virtual ~UGRichTextField();\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnClickLink;\n\nprotected:\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GRoot.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GRoot.generated.h\"\n\nclass UGGraph;\nclass UGWindow;\n\nUCLASS(BlueprintType, NotBlueprintable)\nclass FAIRYGUI_API UGRoot : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI\", meta = (DisplayName = \"Get UI Root\", WorldContext = \"WorldContextObject\"))\n    static UGRoot* Get(UObject* WorldContextObject);\n\n    static int32 ContentScaleLevel;\n\n    UGRoot();\n    virtual ~UGRoot();\n\n    void ShowWindow(UGWindow* Window);\n    void HideWindow(UGWindow* Window);\n    void HideWindowImmediately(UGWindow* Window);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void BringToFront(UGWindow* Window);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ShowModalWait();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void CloseModalWait();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void CloseAllExceptModals();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void CloseAllWindows();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGWindow* GetTopWindow() const;\n\n    UGObject* GetModalWaitingPane();\n    UGGraph* GetModalLayer();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool HasModalWindow() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsModalWaiting() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ShowPopup(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void TogglePopup(UGObject* Popup, UGObject* AtObject = nullptr, EPopupDirection Direction = EPopupDirection::Auto);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void HidePopup(UGObject* Popup = nullptr);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool HasAnyPopup() const;\n\n    FVector2D GetPoupPosition(UGObject* Popup, UGObject* AtObject, EPopupDirection Direction);\n    void CheckPopups(SWidget* ClickTarget);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ShowTooltips(const FString& Text);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ShowTooltipsWin(UGObject* InTooltipWin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void HideTooltips();\n\n    void AddToViewport();\nprivate:\n    void CreateModalLayer();\n    void AdjustModalLayer();\n    void ClosePopup(UGObject* Popup);\n\n    //void UpdateContentScaleLevel();\n\n    void DoShowTooltipsWin();\n\n    UPROPERTY(Transient)\n    UGGraph* ModalLayer;\n    UPROPERTY(Transient)\n    UGObject* ModalWaitPane;\n    UPROPERTY(Transient)\n    UGObject* TooltipWin;\n    UPROPERTY(Transient)\n    UGObject* DefaultTooltipWin;\n    TArray<TWeakObjectPtr<UGObject>> PopupStack;\n    TArray<TWeakObjectPtr<UGObject>> JustClosedPopups;\n    FTimerHandle ShowTooltipsTimerHandle;\n\n    friend class UFairyApplication;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GScrollBar.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GScrollBar.generated.h\"\n\nclass UScrollPane;\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGScrollBar : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGScrollBar();\n    virtual ~UGScrollBar();\n\n    void SetScrollPane(UScrollPane* Target, bool bVertical);\n    void SetDisplayPerc(float Value);\n    void SetScrollPerc(float Value);\n    float GetMinSize();\n\n    bool bGripDragging;\n\nprotected:\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n\nprivate:\n    void OnTouchBeginHandler(UEventContext* Context);\n    void OnGripTouchBegin(UEventContext* Context);\n    void OnGripTouchMove(UEventContext* Context);\n    void OnGripTouchEnd(UEventContext* Context);\n    void OnArrowButton1Click(UEventContext* Context);\n    void OnArrowButton2Click(UEventContext* Context);\n\n    UGObject* GripObject;\n    UGObject* ArrowButton1;\n    UGObject* ArrowButton2;\n    UGObject* BarObject;\n    UScrollPane* Target;\n\n    bool bVertical;\n    float ScrollPerc;\n    bool bFixedGripSize;\n\n    FVector2D DragOffset;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GSlider.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GSlider.generated.h\"\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGSlider : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UGSlider();\n    virtual ~UGSlider();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EProgressTitleType GetTitleType() const { return TitleType; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTitleType(EProgressTitleType InTitleType);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetMin() const { return Min; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMin(float InMin);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetMax() const { return Max; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMax(float InMax);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetValue() const { return Value; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetValue(float InValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool GetWholeNumbers() const { return bWholeNumbers; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetWholeNumbers(bool bWholeNumbers);\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bChangeOnClick;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bCanDrag;\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnChanged;\n\nprotected:\n    virtual void HandleSizeChanged() override;\n    virtual void ConstructExtension(FByteBuffer* Buffer);\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    void Update();\n    void UpdateWithPercent(float Percent, bool bManual);\n\nprivate:\n    void OnTouchBeginHandler(UEventContext* Context);\n    void OnGripTouchBegin(UEventContext* Context);\n    void OnGripTouchMove(UEventContext* Context);\n\n    float Min;\n    float Max;\n    float Value;\n    EProgressTitleType TitleType;\n    bool bReverse;\n    bool bWholeNumbers;\n\n    UGObject* TitleObject;\n    UGObject* BarObjectH;\n    UGObject* BarObjectV;\n    UGObject* GripObject;\n    FVector2D BarMaxSize;\n    FVector2D BarMaxSizeDelta;\n    FVector2D BarStartPosition;\n    FVector2D ClickPos;\n    float ClickPercent;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GTextField.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"Widgets/NTextFormat.h\"\n#include \"GTextField.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGTextField : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGTextField();\n    virtual ~UGTextField();\n\n    virtual const FString& GetText() const override { return Text; }\n    void SetText(const FString& InText) override;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsUBBEnabled() const { return bUBBEnabled; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual void SetUBBEnabled(bool InEnabled);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    EAutoSizeType GetAutoSize() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual void SetAutoSize(EAutoSizeType InAutoSize);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual bool IsSingleLine() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual void SetSingleLine(bool InSingleLine);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI\")\n    FNTextFormat& GetTextFormat();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTextFormat(const FNTextFormat& InTextFormat);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ApplyFormat();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    virtual FVector2D GetTextSize();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTextField* SetVar(const FString& VarKey, const FString& VarValue);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void FlushVars();\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\n    TOptional<TMap<FString, FString>> TemplateVars;\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    void UpdateSize();\n    FString ParseTemplate(const FString& Template);\n\n    FString Text;\n    bool bUBBEnabled;\n    bool bFormatApplied;\n    bool bSupportHTML;\n\n    TSharedPtr<class STextField> Content;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GTextInput.h",
    "content": "#pragma once\n\n#include \"GObject.h\"\n#include \"Widgets/NTextFormat.h\"\n#include \"GTextInput.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGTextInput : public UGObject\n{\n    GENERATED_BODY()\n\npublic:\n    UGTextInput();\n    virtual ~UGTextInput();\n\n    virtual const FString& GetText() const override { return Text; }\n    void SetText(const FString& InText) override;\n\n    TSharedRef<SMultiLineEditableText> GetInputWidget() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsSingleLine() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetSingleLine(bool InSingleLine);\n\n    UFUNCTION(BlueprintPure, Category = \"FairyGUI\")\n    FNTextFormat& GetTextFormat() { return TextFormat; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTextFormat(const FNTextFormat& InTextFormat);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ApplyFormat();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPrompt(const FString& InPrompt);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPassword(bool bInPassword);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetKeyboardType(int32 InKeyboardType);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetMaxLength(int32 InMaxLength);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetRestrict(const FString& InRestrict);\n\n    UPROPERTY(BlueprintAssignable, Category = \"FairyGUI|Event\")\n    FGUIEventDynMDelegate OnSubmit;\n\n    virtual FNVariant GetProp(EObjectPropID PropID) const override;\n    virtual void SetProp(EObjectPropID PropID, const FNVariant& InValue) override;\n\n    void NotifyTextChanged(const FText& InText);\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void SetupAfterAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n\n    FString Text;\n    bool bFormatApplied;\n    FNTextFormat TextFormat;\n\n    TSharedPtr<class STextInput> Content;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GTree.h",
    "content": "#pragma once\n\n#include \"GList.h\"\n#include \"GTreeNode.h\"\n#include \"GTree.generated.h\"\n\nDECLARE_DELEGATE_TwoParams(FTreeNodeRenderer, UGTreeNode*, UGComponent*);\nDECLARE_DELEGATE_TwoParams(FOnTreeNodeWillExpand, UGTreeNode*, bool);\nDECLARE_DYNAMIC_DELEGATE_TwoParams(FDynTreeNodeRenderer, UGTreeNode*, Node, UGComponent*, Obj);\nDECLARE_DYNAMIC_DELEGATE_TwoParams(FDynOnTreeNodeWillExpand, UGTreeNode*, Node, bool, bToExpand);\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UGTree : public UGList\n{\n    GENERATED_BODY()\n\npublic:\n    UGTree();\n    virtual ~UGTree();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetRootNode() const { return RootNode; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetSelectedNode() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void GetSelectedNodes(TArray<UGTreeNode*>& Result) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SelectNode(UGTreeNode* Node, bool bScrollItToView = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void UnselectNode(UGTreeNode* Node);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ExpandAll(UGTreeNode* Node);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void CollapseAll(UGTreeNode* Node);\n\n    void SetTreeNodeRenderer(const FTreeNodeRenderer& InDelegate) { TreeNodeRenderer = InDelegate; }\n    void SetOnTreeNodeWillExpand(const FOnTreeNodeWillExpand& InDelegate) { OnTreeNodeWillExpand = InDelegate; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTreeNodeRenderer(const FDynTreeNodeRenderer& InDelegate)\n    {\n        if (InDelegate.IsBound())\n            TreeNodeRenderer = FTreeNodeRenderer::CreateUFunction(const_cast<UObject*>(InDelegate.GetUObject()), InDelegate.GetFunctionName());\n        else\n            TreeNodeRenderer.Unbind();\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n     void SetOnTreeNodeWillExpand(const FDynOnTreeNodeWillExpand& InDelegate)\n    {\n        if (InDelegate.IsBound())\n            OnTreeNodeWillExpand = FOnTreeNodeWillExpand::CreateUFunction(const_cast<UObject*>(InDelegate.GetUObject()), InDelegate.GetFunctionName());\n        else\n            OnTreeNodeWillExpand.Unbind();\n    }\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 Indent;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 ClickToExpand;\n\nprotected:\n    virtual void SetupBeforeAdd(FByteBuffer* Buffer, int32 BeginPos) override;\n    virtual void ReadItems(FByteBuffer* Buffer) override;\n    virtual void DispatchItemEvent(UGObject* Obj, UEventContext* Context) override;\n\nprivate:\n    void CreateCell(UGTreeNode* Node);\n    void AfterInserted(UGTreeNode* Node);\n    int32 GetInsertIndexForNode(UGTreeNode* Node);\n    void AfterRemoved(UGTreeNode* Node);\n    void AfterExpanded(UGTreeNode* Node);\n    void AfterCollapsed(UGTreeNode* Node);\n    void AfterMoved(UGTreeNode* Node);\n    int32 CheckChildren(UGTreeNode* FolderNode, int32 Index);\n    void HideFolderNode(UGTreeNode* FolderNode);\n    void RemoveNode(UGTreeNode* Node);\n    int32 GetFolderEndIndex(int32 StartIndex, int32 Level);\n\n    UFUNCTION()\n    void OnCellTouchBegin(UEventContext* Context);\n    void OnExpandedStateChanged(UGController* Controller);\n\n    UPROPERTY()\n    UGTreeNode* RootNode;\n    bool bExpandedStatusInEvt;\n    FTreeNodeRenderer TreeNodeRenderer;\n    FOnTreeNodeWillExpand OnTreeNodeWillExpand;\n\n    friend class UGTreeNode;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GTreeNode.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Utils/NVariant.h\"\n#include \"GTreeNode.generated.h\"\n\nclass UGComponent;\nclass UGTree;\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGTreeNode : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DisplayName = \"Create Tree Node\"))\n    static UGTreeNode* CreateNode(bool bIsFolder = false, const FString& ResourceURL = \"\");\n\n    UGTreeNode();\n    virtual ~UGTreeNode();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetParent() const { return Parent.Get(); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetParent(UGTreeNode* InParent);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTree* GetTree() const { return Tree.Get(); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetCell() const { return Cell; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsExpanded() const { return bExpanded; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetExpaned(bool bInExpanded);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsFolder() const { return bIsFolder; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetText() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetText(const FString& InText);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetIcon() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetIcon(const FString& InIcon);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* AddChild(UGTreeNode* Child);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* AddChildAt(UGTreeNode* Child, int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChild(UGTreeNode* Child);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChildAt(int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void RemoveChildren(int32 BeginIndex = 0, int32 EndIndex = -1);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetChildAt(int32 Index) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetPrevSibling() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGTreeNode* GetNextSibling() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetChildIndex(const UGTreeNode* Child) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetChildIndex(UGTreeNode* Child, int32 Index);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SwapChildren(UGTreeNode* Child, UGTreeNode* Child2);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SwapChildrenAt(int32 Index1, int32 Index2);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 NumChildren() const;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FNVariant UserData;\n\nprivate:\n    int32 MoveChild(UGTreeNode* Child, int32 OldIndex, int32 Index);\n    void SetTree(UGTree* InTree);\n\n    TWeakObjectPtr<UGTree> Tree;\n    TWeakObjectPtr<UGTreeNode> Parent;\n    UPROPERTY()\n    UGComponent* Cell;\n    UPROPERTY()\n    TArray<UGTreeNode*> Children;\n\n    int32 Level;\n    bool bExpanded;\n    bool bIsFolder;\n    FString ResourceURL;\n\n    friend class UGTree;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/GWindow.h",
    "content": "#pragma once\n\n#include \"GComponent.h\"\n#include \"GWindow.generated.h\"\n\nclass FAIRYGUI_API IUISource\n{\npublic:\n    virtual const FString& GetFileName() = 0;\n    virtual void SetFileName(const FString& InFileName) = 0;\n    virtual bool IsLoaded() = 0;\n    virtual void Load(FSimpleDelegate Callback) = 0;\n};\n\nDECLARE_DYNAMIC_DELEGATE_OneParam(FWindowDynDelegate, class UGWindow*, Window);\n\nUCLASS(BlueprintType, Blueprintable)\nclass FAIRYGUI_API UGWindow : public UGComponent\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (WorldContext = \"WorldContextObject\"))\n    static UGWindow* CreateWindow(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject);\n\n    UGWindow();\n    virtual ~UGWindow();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Show();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Hide();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void HideImmediately();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ToggleStatus();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void BringToFront();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsShowing() const { return Parent.IsValid(); }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsTop() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsModal() const { return bModal; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetModal(bool bInModal) { bModal = bInModal; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ShowModalWait(int32 InRequestingCmd = 0);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool CloseModalWait(int32 InRequestingCmd = 0);\n\n    void Init();\n    void AddUISource(TSharedPtr<IUISource> UISource);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetContentPane() const { return ContentPane; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetContentPane(UGComponent* Obj);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetFrame() const { return FrameObject; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetCloseButton() const { return CloseButton; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetCloseButton(UGObject* Obj);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetDragArea() const { return DragArea; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetDragArea(UGObject* Obj);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetContentArea() const { return ContentArea; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetContentArea(UGObject* Obj) { ContentArea = Obj; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGObject* GetModalWaitingPane() const { return ModalWaitPane; }\n\n    virtual void OnShown();\n    virtual void OnHide();\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bBringToFontOnClick;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FWindowDynDelegate InitCallback;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FWindowDynDelegate ShownCallback;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FWindowDynDelegate HideCallback;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FWindowDynDelegate ShowingCallback;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FWindowDynDelegate HidingCallback;\n\nprotected:\n    virtual void OnInit();\n    virtual void DoShowAnimation();\n    virtual void DoHideAnimation();\n\n    UFUNCTION()\n    void CloseEventHandler(UEventContext* Context);\n\n    UPROPERTY(Transient)\n    UGComponent* ContentPane;\n\nprivate:\n    void LayoutModalWaitPane();\n    void OnUILoadComplete();\n    void InternalInit();\n\n    void OnTouchBeginHandler(UEventContext* Context);\n    UFUNCTION()\n    void OnDragStartHandler(UEventContext* Context);\n    void OnAddedToStageHandler(UEventContext* Context);\n    void OnRemovedFromStageHandler(UEventContext* Context);\n\n    UPROPERTY(Transient)\n    UGObject* ModalWaitPane;\n    UPROPERTY(Transient)\n    UGComponent* FrameObject;\n    UPROPERTY(Transient)\n    UGObject* CloseButton;\n    UPROPERTY(Transient)\n    UGObject* DragArea;\n    UPROPERTY(Transient)\n    UGObject* ContentArea;\n\n    int32 RequestingCmd;\n    TArray<TSharedPtr<IUISource>> UISources;\n    uint8 bModal : 1;\n    uint8 bInited : 1;\n    uint8 bLoading : 1;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearAnimation.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearAnimation : public FGearBase\n{\npublic:\n    FGearAnimation(UGObject* InOwner);\n    virtual ~FGearAnimation();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    struct FValue\n    {\n        bool bPlaying;\n        int32 Frame;\n\n        FValue();\n    };\n    TMap<FString, FValue> Storage;\n    FValue Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearBase.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Tween/GTween.h\"\n\nclass UGObject;\nclass UGController;\nclass FByteBuffer;\n\nclass FAIRYGUI_API FGearTweenConfig\n{\npublic:\n    FGearTweenConfig();\n\n    bool bTween;\n    EEaseType EaseType;\n    float Duration;\n    float Delay;\n\n    uint32 DisplayLockToken;\n    FTweenerHandle Handle;\n};\n\nclass FGearBase\n{\npublic:\n    enum class EType\n    {\n        Display,\n        XY,\n        Size,\n        Look,\n        Color,\n        Animation,\n        Text,\n        Icon,\n        Display2,\n        FontSize\n    };\n\n    FGearBase(UGObject* InOwner);\n    virtual ~FGearBase();\n\n    EType GetType() const { return Type; }\n\n    UGController* GetController() const { return Controller; }\n    void SetController(UGController* InController);\n\n    FGearTweenConfig& GetTweenConfig();\n\n    virtual void UpdateFromRelations(const FVector2D& Delta);\n    virtual void Apply();\n    virtual void UpdateState();\n\n    void Setup(FByteBuffer* Buffer);\n\n    static TSharedPtr<FGearBase> Create(UGObject* InOwner, EType InType);\n    static bool bDisableAllTweenEffect;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer);\n    virtual void Init();\n\n    EType Type;\n    UGObject* Owner;\n    UGController* Controller;\n    TOptional<FGearTweenConfig> TweenConfig;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearColor.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearColor : public FGearBase\n{\npublic:\n    FGearColor(UGObject* InOwner);\n    virtual ~FGearColor();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    void OnTweenUpdate(FGTweener* Tweener);\n    void OnTweenComplete();\n\n    struct FValue\n    {\n    public:\n        FColor Color;\n        FColor OutlineColor;\n\n        FValue();\n    };\n\n    TMap<FString, FValue> Storage;\n    FValue Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearDisplay.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearDisplay : public FGearBase\n{\npublic:\n    FGearDisplay(UGObject* InOwner);\n    virtual ~FGearDisplay();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\n    uint32 AddLock();\n    void ReleaseLock(uint32 Token);\n    bool IsConnected();\n\n    TArray<FString> Pages;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    int32 Visible;\n    uint32 DisplayLockToken;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearDisplay2.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearDisplay2 : public FGearBase\n{\npublic:\n    FGearDisplay2(UGObject* InOwner);\n    virtual ~FGearDisplay2();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n    bool Evaluate(bool bConnected);\n\n    TArray<FString> Pages;\n    int32 Condition;\n\nprotected:\n    virtual void AddStatus(const FString& pageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    int32 Visible;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearFontSize.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearFontSize : public FGearBase\n{\npublic:\n    FGearFontSize(UGObject* InOwner);\n    virtual ~FGearFontSize();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    TMap<FString, int32> Storage;\n    int32 Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearIcon.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearIcon : public FGearBase\n{\npublic:\n    FGearIcon(UGObject* InOwner);\n    virtual ~FGearIcon();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    TMap<FString, FString> Storage;\n    FString Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearLook.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearLook : public FGearBase\n{\npublic:\n    FGearLook(UGObject* InOwner);\n    virtual ~FGearLook();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    void OnTweenUpdate(FGTweener* Tweener);\n    void OnTweenComplete();\n\n    struct FValue\n    {\n        float Alpha;\n        float Rotation;\n        bool bGrayed;\n        bool bTouchable;\n\n        FValue();\n    };\n\n    TMap<FString, FValue> Storage;\n    FValue Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearSize.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearSize : public FGearBase\n{\npublic:\n    FGearSize(UGObject* InOwner);\n    virtual ~FGearSize();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n    virtual void UpdateFromRelations(const FVector2D& Delta) override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    void OnTweenUpdate(FGTweener* Tweener);\n    void OnTweenComplete();\n\n    TMap<FString, FVector4> Storage;\n    FVector4 Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearText.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearText : public FGearBase\n{\npublic:\n    FGearText(UGObject* InOwner);\n    virtual ~FGearText();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    TMap<FString, FString> Storage;\n    FString Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Gears/GearXY.h",
    "content": "#pragma once\n\n#include \"GearBase.h\"\n\nclass FAIRYGUI_API FGearXY : public FGearBase\n{\npublic:\n    FGearXY(UGObject* InOwner);\n    virtual ~FGearXY();\n\n    virtual void Apply() override;\n    virtual void UpdateState() override;\n    virtual void UpdateFromRelations(const FVector2D& Delta) override;\n\n    bool bPositionsInPercent;\n    void AddExtStatus(const FString& PageID, FByteBuffer* Buffer);\n\nprotected:\n    virtual void AddStatus(const FString& PageID, FByteBuffer* Buffer) override;\n    virtual void Init() override;\n\nprivate:\n    void OnTweenUpdate(FGTweener* Tweener);\n    void OnTweenComplete();\n\n    TMap<FString, FVector4> Storage;\n    FVector4 Default;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/PackageItem.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Engine/Texture2D.h\"\n#include \"FieldTypes.h\"\n#include \"Engine.h\"\n#include \"FairyCommons.h\"\n#include \"Widgets/HitTest.h\"\n\nclass FByteBuffer;\nstruct FMovieClipData;\nstruct FBitmapFont;\n\nclass UUIPackage;\nclass UNTexture;\nclass UGComponent;\n\nclass FAIRYGUI_API FPackageItem : public FGCObject, public TSharedFromThis<FPackageItem>\n{\npublic:\n    FPackageItem();\n\n    void Load();\n    TSharedPtr<FPackageItem> GetBranch();\n    TSharedPtr<FPackageItem> GetHighResolution();\n\n    virtual void AddReferencedObjects(FReferenceCollector& Collector) override;\n\npublic:\n    UUIPackage* Owner;\n\n    EPackageItemType Type;\n    EObjectType ObjectType;\n    FString ID;\n    FString Name;\n    FVector2D Size;\n    FString File;\n    TSharedPtr<FByteBuffer> RawData;\n    TOptional<TArray<FString>> Branches;\n    TOptional<TArray<FString>> HighResolution;\n\n    //atlas\n    UNTexture* Texture;\n\n    //image\n    TOptional<FBox2D> Scale9Grid;\n    bool bScaleByTile;\n    int32 TileGridIndice;\n    TSharedPtr<FPixelHitTestData> PixelHitTestData;\n\n    //movie clip\n    TSharedPtr<FMovieClipData> MovieClipData;\n\n    //component\n    FGComponentCreator ExtensionCreator;\n    bool bTranslated;\n\n    //font\n    TSharedPtr<FBitmapFont> BitmapFont;\n\n    //sound\n    TSharedPtr<FSlateSound> Sound;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/UI/PopupMenu.h",
    "content": "#pragma once\n\n#include \"GList.h\"\n#include \"GButton.h\"\n#include \"PopupMenu.generated.h\"\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UPopupMenu : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (WorldContext = \"WorldContextObject\"))\n    static UPopupMenu* CreatePopupMenu(const FString& ResourceURL, UObject* WorldContextObject);\n\n    static UPopupMenu* CreatePopupMenu(UObject* WorldContextObject) { return CreatePopupMenu(\"\", WorldContextObject); }\n\n    UPopupMenu();\n    virtual ~UPopupMenu();\n\n    UGButton* AddItem(const FString& Caption, FGUIEventDelegate Callback);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"Callback\"))\n    UGButton* AddItem(const FString& Caption, const FGUIEventDynDelegate& Callback);\n\n    UGButton* AddItemAt(const FString& Caption, int32 index, FGUIEventDelegate Callback);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"Callback\"))\n    UGButton* AddItemAt(const FString& Caption, int32 index, const FGUIEventDynDelegate& Callback);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void AddSeperator();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetItemName(int32 Index) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemText(const FString& Name, const FString& Caption);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemVisible(const FString& Name, bool bVisible);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemGrayed(const FString& Name, bool bGrayed);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemCheckable(const FString& Name, bool bCheckable);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetItemChecked(const FString& Name, bool bCheck);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsItemChecked(const FString& Name) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool RemoveItem(const FString& Name);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ClearItems();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetItemCount() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetContentPane() const { return ContentPane; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGList* GetList() const { return List; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Show(UGObject* AtObject, EPopupDirection Dir = EPopupDirection::Auto);\n\nprotected:\n    void Create(const FString& ResourceURL);\n\n    UPROPERTY(Transient)\n    UGComponent* ContentPane;\n    UGList* List;\n\nprivate:\n    void OnClickItem(UEventContext* Context);\n    void OnAddedToStage(UEventContext* Context);\n\n    static const FName ClickMenu;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/RelationItem.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"FieldTypes.h\"\n\nclass UGObject;\n\nstruct FAIRYGUI_API FRelationDef\n{\n    bool bPercent;\n    ERelationType Type;\n    int32 Axis;\n\n    FRelationDef() :\n        bPercent(false), Type(ERelationType::Left_Left), Axis(0)\n    {}\n};\n\nclass FAIRYGUI_API FRelationItem\n{\npublic:\n    FRelationItem(UGObject* InOwner);\n    ~FRelationItem();\n\n    UGObject* GetTarget() const { return Target.Get(); }\n    void SetTarget(UGObject* InTarget);\n\n    void Add(ERelationType RelationType, bool bUsePercent);\n    void InternalAdd(ERelationType RelationType, bool bUsePercent);\n    void Remove(ERelationType RelationType);\n    void CopyFrom(const FRelationItem& Source);\n    bool IsEmpty() const;\n    void ApplyOnSelfSizeChanged(float DeltaWidth, float DeltaHeight, bool bApplyPivot);\n\nprivate:\n    void ApplyOnXYChanged(UGObject* InTarget, const FRelationDef& info, float dx, float dy);\n    void ApplyOnSizeChanged(UGObject* InTarget, const FRelationDef& info);\n    void AddRefTarget(UGObject* InTarget);\n    void ReleaseRefTarget();\n    void OnTargetXYChanged();\n    void OnTargetSizeChanged();\n\n    UGObject* Owner;\n    TWeakObjectPtr<UGObject> Target;\n    TArray<FRelationDef> Defs;\n    FVector4 TargetData;\n\n    FDelegateHandle PositionDelegateHandle;\n    FDelegateHandle SizeDelegateHandle;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Relations.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"RelationItem.h\"\n\nclass UGObject;\nclass FByteBuffer;\n\nclass FAIRYGUI_API FRelations\n{\npublic:\n    FRelations(UGObject* InOwner);\n    ~FRelations();\n\n    void Add(UGObject* InTarget, ERelationType RelationType);\n    void Add(UGObject* InTarget, ERelationType RelationType, bool bUsePercent);\n    void Remove(UGObject* InTarget, ERelationType RelationType);\n    bool Contains(UGObject* InTarget);\n    void ClearFor(UGObject* InTarget);\n    void ClearAll();\n    void CopyFrom(const FRelations& Source);\n    void OnOwnerSizeChanged(const FVector2D& Delta, bool bApplyPivot);\n    bool IsEmpty() const;\n    void Setup(FByteBuffer* Buffer, bool bParentToChild);\n\n    UGObject* Handling;\n\nprivate:\n    UGObject* Owner;\n    TIndirectArray<FRelationItem> Items;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/ScrollPane.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Styling/SlateTypes.h\"\n#include \"FieldTypes.h\"\n#include \"Tween/GTween.h\"\n#include \"Event/EventContext.h\"\n#include \"ScrollPane.generated.h\"\n\nclass UGObject;\nclass UGComponent;\nclass UGScrollBar;\nclass UGController;\nclass FByteBuffer;\nclass FGTweener;\nclass SContainer;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UScrollPane : public UObject\n{\n    GENERATED_BODY()\npublic:\n    UScrollPane();\n    ~UScrollPane();\n\n    void Setup(FByteBuffer* Buffer);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetHeader() const { return Header; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGComponent* GetFooter() const { return Footer; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGScrollBar* GetVtScrollBar() const { return VtScrollBar; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    UGScrollBar* GetHzScrollBar() const { return HzScrollBar; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetPosX() const { return XPos; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPosX(float Value, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetPosY() const { return YPos; }\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPosY(float Value, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetPercX() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPercX(float Value, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetPercY() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPercY(float Value, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsBottomMost() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsRightMost() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollLeft(float Ratio = 1, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollRight(float Ratio = 1, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollUp(float Ratio = 1, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollDown(float Ratio = 1, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollTop(bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollBottom(bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ScrollToView(UGObject* Obj, bool bAnimation = false, bool bSetFirst = false);\n\n    void ScrollToView(const FBox2D& Rect, bool bAnimation = false, bool bSetFirst = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    bool IsChildInView(UGObject* Obj) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetPageX() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPageX(int32 PageX, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    int32 GetPageY() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPageY(int32 PageY, bool bAnimation = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetScrollingPosX() const;\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetScrollingPosY() const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetContentSize() const { return ContentSize; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FVector2D& GetViewSize() const { return ViewSize; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void LockHeader(int32 Size);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void LockFooter(int32 Size);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void CancelDragging();\n\n    static UScrollPane* GetDraggingPane() { return DraggingPane.Get(); }\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    uint8 bBouncebackEffect : 1;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    uint8 bTouchEffect : 1;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    uint8 bInertiaDisabled : 1;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    uint8 bMouseWheelEnabled : 1;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    uint8 bSnapToItem : 1;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    uint8 bPageMode : 1;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float DecelerationRate;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float ScrollStep;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    UGController* PageController;\n\nprivate:\n    void OnOwnerSizeChanged();\n    void AdjustMaskContainer();\n    void SetContentSize(const FVector2D& InSize);\n    void ChangeContentSizeOnScrolling(float DeltaWidth, float DeltaHeight, float DeltaPosX, float DeltaPosY);\n    void SetViewWidth(float Width);\n    void SetViewHeight(float Height);\n    void SetSize(const FVector2D& InSize);\n    void HandleSizeChanged();\n\n    void HandleControllerChanged(UGController* Controller);\n    void UpdatePageController();\n\n    void PosChanged(bool bAnimation);\n    void Refresh();\n    void Refresh2();\n\n    void UpdateScrollBarPos();\n    void UpdateScrollBarVisible();\n    void UpdateScrollBarVisible2(UGScrollBar* Bar);\n\n    float GetLoopPartSize(float Division, int32 Axis);\n    bool LoopCheckingCurrent();\n    void LoopCheckingTarget(FVector2D& EndPos);\n    void LoopCheckingTarget(FVector2D& EndPos, int32 Axis);\n    void LoopCheckingNewPos(float& Value, int32 Axis);\n    void AlignPosition(FVector2D& Pos, bool bInertialScrolling);\n    float AlignByPage(float Pos, int32 Axis, bool bInertialScrolling);\n    FVector2D UpdateTargetAndDuration(const FVector2D& OrignPos);\n    float UpdateTargetAndDuration(float Pos, int32 Axis);\n    void FixDuration(int32 Axis, float DldChange);\n    void StartTween(int32 Type);\n    void KillTween();\n    void TweenUpdate();\n    float RunTween(int32 Axis, float Delta);\n\n    void CheckRefreshBar();\n\n    void OnTouchBegin(UEventContext* Context);\n    void OnTouchMove(UEventContext* Context);\n    void OnTouchEnd(UEventContext* Context);\n    void OnMouseWheel(UEventContext* Context);\n    void OnRollOver(UEventContext* Context);\n    void OnRollOut(UEventContext* Context);\n\n    void OnBarTweenComplete(FGTweener* Tweener);\n\nprivate:\n    UGComponent* Owner;\n    TSharedPtr<SContainer> MaskContainer;\n    TSharedPtr<SContainer> Container;\n    UPROPERTY(Transient)\n    UGScrollBar* HzScrollBar;\n    UPROPERTY(Transient)\n    UGScrollBar* VtScrollBar;\n    UPROPERTY(Transient)\n    UGComponent* Header;\n    UPROPERTY(Transient)\n    UGComponent* Footer;\n\n    EScrollType ScrollType;\n    FMargin ScrollBarMargin;\n    uint8 bScrollBarDisplayAuto : 1;\n    uint8 bVScrollNone : 1;\n    uint8 bHScrollNone : 1;\n    uint8 bNeedRefresh : 1;\n    int32 RefreshBarAxis;\n    uint8 bDisplayOnLeft : 1;\n    uint8 bDisplayInDemand : 1;\n    uint8 bFloating : 1;\n    uint8 bDontClipMargin : 1;\n\n    float XPos;\n    float YPos;\n\n    FVector2D ViewSize;\n    FVector2D ContentSize;\n    FVector2D OverlapSize;\n    FVector2D PageSize;\n    FVector2D ContainerPos;\n    FVector2D BeginTouchPos;\n    FVector2D LastTouchPos;\n    FVector2D LastTouchGlobalPos;\n    FVector2D Velocity;\n    float VelocityScale;\n    float LastMoveTime;\n    uint8 bDragged : 1;\n    uint8 bIsHoldAreaDone : 1;\n    int32 AniFlag;\n    int32 LoopMode;\n    uint8 bHover : 1;\n\n    float HeaderLockedSize;\n    float FooterLockedSize;\n    uint8 bDispatchingPullDown : 1;\n    uint8 bDispatchingPullUp : 1;\n\n    int32 Tweening;\n    FVector2D TweenStart;\n    FVector2D TweenChange;\n    FVector2D TweenTime;\n    FVector2D TweenDuration;\n\n    FTimerHandle RefreshTimerHandle;\n    FTimerHandle TickTimerHandle;\n\n    static int32 GestureFlag;\n    static TWeakObjectPtr<UScrollPane> DraggingPane;\n\n    friend class UGComponent;\n    friend class UGList;\n    friend class UGScrollBar;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/Transition.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Tween/GTween.h\"\n#include \"Event/EventContext.h\"\n#include \"Transition.generated.h\"\n\nclass UGObject;\nclass UGComponent;\nclass UGController;\nclass FByteBuffer;\nclass FGTweener;\nstruct FTransitionItem;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UTransition : public UObject\n{\n    GENERATED_BODY()\npublic:\n    UTransition();\n    virtual ~UTransition();\n\n    bool IsPlaying() const { return bPlaying; }\n    void Play(const FSimpleDelegate& InCompleteCallback = FSimpleDelegate())\n    {\n        Play(1, 0, 0, -1, false, InCompleteCallback);\n    }\n\n    void Play(int32 InTimes, float InDelay, float InStartTime = 0, float InEndTime = -1, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate())\n    {\n        Play(InTimes, InDelay, InStartTime, InEndTime, false, InCompleteCallback);\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"InCompleteCallback\"))\n    void Play(const FSimpleDynDelegate& InCompleteCallback, int32 InTimes = 1, float InDelay = 0, float InStartTime = 0, float InEndTime = -1)\n    {\n        Play(InTimes, InDelay, InStartTime, InEndTime, false, \n            InCompleteCallback.IsBound() ?\n            FSimpleDelegate::CreateUFunction(const_cast<UObject*>(InCompleteCallback.GetUObject()), InCompleteCallback.GetFunctionName())\n            : FSimpleDelegate());\n    }\n\n    void PlayReverse(const FSimpleDelegate& InCompleteCallback = FSimpleDelegate())\n    {\n        Play(1, 0, 0, -1, true, InCompleteCallback);\n    }\n\n    void PlayReverse(int32 InTimes, float InDelay, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate())\n    {\n        Play(InTimes, InDelay, 0, -1, true, InCompleteCallback);\n    }\n    \n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (AutoCreateRefTerm = \"InCompleteCallback\"))\n    void PlayReverse(const FSimpleDynDelegate& InCompleteCallback, int32 InTimes = 1, float InDelay = 0)\n    {\n        Play(InTimes, InDelay, 0, -1, true, \n            InCompleteCallback.IsBound() ?\n            FSimpleDelegate::CreateUFunction(const_cast<UObject*>(InCompleteCallback.GetUObject()), InCompleteCallback.GetFunctionName())\n            : FSimpleDelegate());\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ChangePlayTimes(int32 InTimes);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void Stop(bool bSetToComplete = false, bool bProcessCallback = false);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetAutoPlay(bool bInAutoPlay, int32 InTimes, float InDelay);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetPaused(bool bInPaused);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetValue(const FString& InLabel, const TArray<FNVariant>& InValues);\n\n    void SetHook(const FString& InLabel, FSimpleDelegate Callback);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetHook(const FString& InLabel, FSimpleDynDelegate Callback)\n    {\n        SetHook(InLabel, Callback.IsBound() ?\n            FSimpleDelegate::CreateUFunction(const_cast<UObject*>(Callback.GetUObject()), Callback.GetFunctionName())\n            : FSimpleDelegate());\n    }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void ClearHooks();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTarget(const FString& InLabel, UGObject* InTarget);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetDuration(const FString& InLabel, float InDuration);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetLabelTime(const FString& InLabel) const;\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    float GetTimeScale() const { return TimeScale; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    void SetTimeScale(float InTimeScale);\n\n    void UpdateFromRelations(const FString& TargetID, const FVector2D& Delta);\n    void OnOwnerAddedToStage();\n    void OnOwnerRemovedFromStage();\n\n    void Setup(FByteBuffer* Buffer);\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString Name;\n\nprivate:\n    void Play(int32 InTimes, float InDelay, float InStartTime, float InEndTime, bool bInReverse, FSimpleDelegate InCompleteCallback);\n    void StopItem(FTransitionItem* Item, bool bSetToComplete);\n    void OnDelayedPlay();\n    void InternalPlay();\n    void PlayItem(FTransitionItem* Item);\n    void SkipAnimations();\n    void OnDelayedPlayItem(FGTweener* Tweener);\n    void OnTweenStart(FGTweener* Tweener);\n    void OnTweenUpdate(FGTweener* Tweener);\n    void OnTweenComplete(FGTweener* Tweener);\n    void OnPlayTransCompleted(FTransitionItem* item);\n    void CallHook(FTransitionItem* Item, bool bTweenEnd);\n    void CheckAllComplete();\n    void ApplyValue(FTransitionItem* Item);\n    void DecodeValue(FTransitionItem* Item, FByteBuffer* Buffer, struct FTransitionItemData* Value);\n\n    UGComponent* Owner;\n    TArray<FTransitionItem*> Items;\n    int32 TotalTimes;\n    int32 TotalTasks;\n    bool bPlaying;\n    bool bPaused;\n    FVector2D OwnerBasePos;\n    FSimpleDelegate CompleteCallback;\n    int32 Options;\n    bool bReversed;\n    float TotalDuration;\n    bool bAutoPlay;\n    int32 AutoPlayTimes;\n    float AutoPlayDelay;\n    float TimeScale;\n    float StartTime;\n    float EndTime;\n    FTweenerHandle DelayHandle;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/TranslationHelper.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nclass FPackageItem;\n\nclass FTranslationHelper\n{\npublic:\n    static TMap<FString, TMap<FString, FString>> Strings;\n\n    static void LoadFromXML(const FString XmlString);\n    static void TranslateComponent(const TSharedPtr<FPackageItem>& Item);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/UIConfig.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Engine/Texture2D.h\"\n#include \"FieldTypes.h\"\n#include \"UIConfig.generated.h\"\n\nUSTRUCT(BlueprintType)\nstruct FAIRYGUI_API FUIConfig\n{\n    GENERATED_USTRUCT_BODY()\n\npublic:\n    static FUIConfig Config;\n\n    FUIConfig();\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString DefaultFont;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString ButtonSound;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float ButtonSoundVolumeScale;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 DefaultScrollStep;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    float DefaultScrollDecelerationRate;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool DefaultScrollTouchEffect;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool DefaultScrollBounceEffect;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    EScrollBarDisplayType DefaultScrollBarDisplay;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString VerticalScrollBar;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString HorizontalScrollBar;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 TouchDragSensitivity;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 ClickDragSensitivity;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 TouchScrollSensitivity;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 DefaultComboBoxVisibleItemCount;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString GlobalModalWaiting;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FColor ModalLayerColor;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString TooltipsWin;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool BringWindowToFrontOnClick;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString WindowModalWaiting;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString PopupMenu;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString PopupMenuSeperator;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/UIObjectFactory.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"FieldTypes.h\"\n#include \"PackageItem.h\"\n\nclass UGComponent;\nclass UGLoader;\nclass UGObject;\n\nclass FAIRYGUI_API FUIObjectFactory\n{\npublic:\n    static void SetExtension(const FString& URL, FGComponentCreator Creator);\n    static void SetExtension(const FString& URL, TSubclassOf<UGComponent> ClassType);\n\n    static UGObject* NewObject(const TSharedPtr<FPackageItem>& PackageItem, UObject* Outer);\n    static UGObject* NewObject(EObjectType Type, UObject* Outer);\n\n    static void ResolvePackageItemExtension(const TSharedPtr<FPackageItem>& PackageItem);\n\npublic:\n    static TMap<FString, FGComponentCreator> PackageItemExtensions;\n    static TSubclassOf<class UGLoader> LoaderExtension;\n\n    friend class UFGUIPackage;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UI/UIPackage.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"UIPackage.generated.h\"\n\nclass FPackageItem;\nclass UGObject;\nclass FByteBuffer;\nclass UUIPackageAsset;\n\nUCLASS(BlueprintType)\nclass FAIRYGUI_API UUIPackage : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static const FString& GetBranch();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static void SetBranch(const FString& InBranch);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DisplayName = \"Get UI Global Variable\"))\n    static FString GetVar(const FString& VarKey);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DisplayName = \"Set UI Global Variable\"))\n    static void SetVar(const FString& VarKey, const FString& VarValue);\n\n    static UUIPackage* AddPackage(const TCHAR* InAssetPath, UObject* WorldContextObject);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (WorldContext = \"WorldContextObject\"))\n    static UUIPackage* AddPackage(class UUIPackageAsset* InAsset, UObject* WorldContextObject);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (WorldContext = \"WorldContextObject\"))\n    static void RemovePackage(const FString& IDOrName, UObject* WorldContextObject);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static void RemoveAllPackages();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static UUIPackage* GetPackageByID(const FString& PackageID);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static UUIPackage* GetPackageByName(const FString& PackageName);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DisplayName = \"Create UI\", DeterminesOutputType = \"ClassType\", WorldContext = \"WorldContextObject\"))\n    static UGObject* CreateObject(const FString& PackageName, const FString& ResourceName, UObject* WorldContextObject, TSubclassOf<UGObject> ClassType = nullptr);\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\", meta = (DisplayName = \"Create UI From URL\", DeterminesOutputType = \"ClassType\", WorldContext = \"WorldContextObject\"))\n    static UGObject* CreateObjectFromURL(const FString& URL, UObject* WorldContextObject, TSubclassOf<UGObject> ClassType = nullptr);\n\n    static FString GetItemURL(const FString& PackageName, const FString& ResourceName);\n    static TSharedPtr<FPackageItem> GetItemByURL(const FString& URL);\n    static FString NormalizeURL(const FString& URL);\n\n    static int32 Constructing;\n\npublic:\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    static void RegisterFont(const FString& FontFace, UObject* Font);\n\npublic:\n    UUIPackage();\n    virtual  ~UUIPackage();\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetID() const { return ID; }\n\n    UFUNCTION(BlueprintCallable, Category = \"FairyGUI\")\n    const FString& GetName() const { return Name; }\n\n    TSharedPtr<FPackageItem> GetItem(const FString& ResourceID) const;\n    TSharedPtr<FPackageItem> GetItemByName(const FString& ResourceName);\n    void* GetItemAsset(const TSharedPtr<FPackageItem>& Item);\n\n    UGObject* CreateObject(const FString& ResourceName, UObject* WorldContextObject);\n    UGObject* CreateObject(const TSharedPtr<FPackageItem>& Item, UObject* WorldContextObject);\n\nprivate:\n    void Load(FByteBuffer* Buffer);\n    void LoadAtlas(const TSharedPtr<FPackageItem>& Item);\n    void LoadImage(const TSharedPtr<FPackageItem>& Item);\n    void LoadMovieClip(const TSharedPtr<FPackageItem>& Item);\n    void LoadFont(const TSharedPtr<FPackageItem>& Item);\n    void LoadSound(const TSharedPtr<FPackageItem>& Item);\n\nprivate:\n    FString ID;\n    FString Name;\n    FString AssetPath;\n    UPROPERTY(Transient)\n    UUIPackageAsset* Asset;\n\n    TArray<TSharedPtr<FPackageItem>> Items;\n    TMap<FString, TSharedPtr<FPackageItem>> ItemsByID;\n    TMap<FString, TSharedPtr<FPackageItem>> ItemsByName;\n    TMap<FString, struct FAtlasSprite*> Sprites;\n    FString CustomID;\n    TArray<TMap<FString, FString>> Dependencies;\n    TArray<FString> Branches;\n    int32 BranchIndex;\n    TSet<uint32> RefWorlds;\n\n    friend class FPackageItem;\n    friend class UFairyApplication;\n};\n\nUCLASS(Transient)\nclass FAIRYGUI_API UUIPackageStatic : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    static UUIPackageStatic* Singleton;\n    static UUIPackageStatic& Get();\n    static void Destroy();\n\n    UPROPERTY(Transient)\n    TArray<UUIPackage*> PackageList;\n    TMap<FString, UUIPackage*> PackageInstByID;\n    TMap<FString, UUIPackage*> PackageInstByName;\n    TMap<FString, FString> Vars;\n    FString Branch;\n    UPROPERTY(Transient)\n    TMap<FString, UObject*> Fonts;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/UIPackageAsset.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"UIPackageAsset.generated.h\"\n\nUCLASS()\nclass FAIRYGUI_API UUIPackageAsset : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n\n    UPROPERTY(EditAnywhere)\n    TArray<uint8> Data;\n\n#if WITH_EDITORONLY_DATA\n    UPROPERTY(Instanced)\n    class UAssetImportData* AssetImportData;\n\n    virtual void GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const override;\n#endif\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/ByteBuffer.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"FairyCommons.h\"\n\nclass FAIRYGUI_API FByteBuffer\n{\npublic:\n    FByteBuffer(const uint8* InBuffer, int32 InOffset, int32 InLen, bool bInTransferOwnerShip);\n    ~FByteBuffer();\n\n    const uint8* GetBuffer() const { return Buffer; }\n\n    int32 GetBytesAvailable() const;\n    int32 GetLength() const { return Length; }\n\n    int32 GetPos() const { return Position; }\n    void SetPos(int32 InPos) { Position = InPos; }\n    void Skip(int32 Count) { Position += Count; }\n\n    int8 ReadByte();\n    uint8 ReadUbyte();\n    bool ReadBool();\n    int16 ReadShort();\n    uint16 ReadUshort();\n    int32 ReadInt();\n    uint32 ReadUint();\n    float ReadFloat();\n    FString ReadString();\n    FString ReadString(int32 InLen);\n    const FString& ReadS();\n    void ReadSArray(TArray<FString>& OutArray, int32 InCount);\n    bool ReadS(FString& OutString);\n    const FString* ReadSP();\n    void WriteS(const FString& InString);\n    FColor ReadColor();\n    TSharedPtr<FByteBuffer> ReadBuffer(bool bCloneBuffer);\n    bool Seek(int32 IndexTablePos, int32 BlockIndex);\n\n    bool bLittleEndian;\n    int32 Version;\n    TSharedPtr<TArray<FString>> StringTable;\n\nprivate:\n    const uint8* Buffer;\n    int32 Offset;\n    int32 Length;\n    int32 Position;;\n    bool bOwnsBuffer;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/HTMLElement.h",
    "content": "#pragma once\n\n#include \"Slate.h\"\n#include \"Widgets/NTextFormat.h\"\n#include \"XMLAttributes.h\"\n\nenum class EHTMLElementType\n{\n    Text,\n    Link,\n    Image,\n    Input,\n    Select,\n    Object,\n\n    //internal\n    LinkEnd,\n};\n\nclass FAIRYGUI_API FHTMLElement\n{\npublic:\n    EHTMLElementType Type;\n    FString Name;\n    FString Text;\n    FNTextFormat Format;\n    int32 CharIndex;\n\n    int32 Space;\n    FVector2D Position;\n    FXMLAttributes Attributes;\n};\n"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/HTMLParser.h",
    "content": "#pragma once\n\n#include \"HTMLElement.h\"\n\nstruct FAIRYGUI_API FHTMLParseOptions\n{\n    bool bLinkUnderline;\n    FColor LinkColor;\n    FColor LinkBgColor;\n    FColor LinkHoverBgColor;\n    bool bIgnoreWhiteSpace;\n};\n\nclass FAIRYGUI_API FHTMLParser\n{\npublic:\n    static FHTMLParser DefaultParser;\n    static FHTMLParseOptions DefaultParseOptions;\n\n    FHTMLParser();\n\n    void Parse(const FString& InText, const FNTextFormat& InFormat, TArray<FHTMLElement>& OutElements, const FHTMLParseOptions& InParseOptions);\n\nprotected:\n    void PushTextFormat();\n    void PopTextFormat();\n    bool IsNewLine();\n    void AppendText(const FString& InText);\n\n    struct FMyTextFormat : FNTextFormat\n    {\n        bool bColorChanged;\n    };\n    TArray<FMyTextFormat> TextFormatStack;\n    FMyTextFormat Format;\n    TArray<FHTMLElement>* Elements;\n    FHTMLParseOptions ParseOptions;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/NVariant.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Containers/Union.h\"\n#include \"NVariant.generated.h\"\n\nUSTRUCT(BlueprintType)\nstruct FAIRYGUI_API FNVariant\n{\n    GENERATED_USTRUCT_BODY()\npublic:\n    FNVariant();\n    FNVariant(const FNVariant& other);\n    FNVariant(FNVariant&& other);\n    ~FNVariant();\n\n    explicit FNVariant(bool bValue);\n    explicit FNVariant(int32 Value);\n    explicit FNVariant(float Value);\n    explicit FNVariant(const FString& Value);\n    explicit FNVariant(const FColor& Value);\n    explicit FNVariant(void* Value);\n\n    FNVariant& operator= (const FNVariant& other);\n    FNVariant& operator= (FNVariant&& other);\n\n    FNVariant& operator= (bool bValue);\n    FNVariant& operator= (int32 Value);\n    FNVariant& operator= (float Value);\n    FNVariant& operator= (const FString& Value);\n    FNVariant& operator= (const FColor& Value);\n    FNVariant& operator= (void* Value);\n\n    bool AsBool() const\n    {\n        return As<bool>();\n    }\n\n    int32 AsInt() const\n    {\n        return As<int32>();\n    }\n\n    float AsFloat() const\n    {\n        return As<float>();\n    }\n    \n    FString AsString() const\n    {\n        return As<FString>();\n    }\n\n    FColor AsColor() const\n    {\n        return As<FColor>();\n    }\n\n    UObject* AsUObject() const\n    {\n        return (UObject*)As<void *>();\n    }\n\n    template<typename DataType>\n    DataType As() const\n    {\n        if (TheUnion.HasSubtype<DataType>())\n            return TheUnion.GetSubtype<DataType>();\n        else\n            return DataType();\n    }\n\n    void Reset()\n    {\n        TheUnion.Reset();\n    }\n\n    static const FNVariant Null;\n\nprivate:\n    TUnion<bool, int32, float, FString, FColor, void*> TheUnion;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/UBBParser.h",
    "content": "#pragma once\n\n#include \"Slate.h\"\n#include \"Widgets/NTextFormat.h\"\n\nDECLARE_DELEGATE_RetVal_ThreeParams(FString, FTagHandler, const FString&, bool, const FString&);\nDECLARE_DELEGATE_RetVal_FourParams(bool, FDefaultTagHandler, const FString&, bool, const FString&, FString&);\n\nclass FAIRYGUI_API FUBBParser\n{\npublic:\n    static FUBBParser DefaultParser;\n\n    FUBBParser();\n    virtual ~FUBBParser();\n\n    FString Parse(const FString& Text, bool bRemove = false);\n\n    int32 DefaultImgWidth;\n    int32 DefaultImgHeight;\n    FString LastColor;\n    FString LastFontSize;\n    FDefaultTagHandler DefaultTagHandler;\n    TMap<FString, FTagHandler> Handlers;\n\nprotected:\n    virtual FString OnTag_URL(const FString& TagName, bool bEnd, const FString& Attr);\n    virtual FString OnTag_IMG(const FString& TagName, bool bEnd, const FString& Attr);\n    virtual FString OnTag_Simple(const FString& TagName, bool bEnd, const FString& Attr);\n    virtual FString OnTag_COLOR(const FString& TagName, bool bEnd, const FString& Attr);\n    virtual FString OnTag_FONT(const FString& TagName, bool bEnd, const FString& Attr);\n    virtual FString OnTag_SIZE(const FString& TagName, bool bEnd, const FString& Attr);\n    virtual FString OnTag_ALIGN(const FString& TagName, bool bEnd, const FString& Attr);\n\n    FString GetTagText(bool bRemove);\n\n    const FString* Source;\n    int32 ReadPos;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/XMLAttributes.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nstruct FXMLAttributes : TMap<FString, FString>\n{\n    const FString& Get(const FString& AttrName, const FString& DefaultValue = \"\");\n    int32 GetInt(const FString& AttrName, int32 DefaultValue = 0);\n    float GetFloat(const FString& AttrName, float DefaultValue = 0);\n    bool GetBool(const FString& AttrName, bool DefaultValue = false);\n    FColor GetColor(const FString& AttrName, const FColor& DefaultValue);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Utils/XMLIterator.h",
    "content": "#pragma once\n\n#include \"XMLAttributes.h\"\n\nenum class EXMLTagType\n{\n    Start,\n    End,\n    Void,\n    CDATA,\n    Comment,\n    Instruction\n};\n\nstruct FAIRYGUI_API FXMLIterator\n{\npublic:\n    void Begin(const FString& InText, bool bLowerCaseName = false);\n    bool NextTag();\n\n    FString GetTagSource() const;\n    FString GetRawText(bool bTrim = false) const;\n    FString GetText(bool bTrim = false) const;\n    void ParseAttributes();\n\n    static FString DecodeString(const FString& InSource);\n\n    FString TagName;\n    EXMLTagType TagType;\n    FString LastTagName;\n    FXMLAttributes Attributes;\n\nprivate:\n\n    const FString* Source;\n    int32 SourceLen;\n    int32 ParsePos;\n    int32 TagPos;\n    int32 TagLength;\n    int32 LastTagEnd;\n    bool bAttrParsed;\n    bool bLowerCaseName;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/BitmapFont.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nclass UNTexture;\n\nstruct FAIRYGUI_API FBitmapFont : public FGCObject\n{\n    struct FGlyph\n    {\n        FVector2D Offset;\n        FVector2D Size;\n        float XAdvance;\n        float LineHeight;\n        FBox2D UVRect;\n        int32 Channel;\n    };\n\n    int32 FontSize;\n    bool bResizable;\n    bool bHasChannel;\n    bool bCanTint;\n\n    TMap<TCHAR, FGlyph> Glyphs;\n\n    UNTexture* Texture;\n\n    virtual void AddReferencedObjects(FReferenceCollector& Collector) override;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/BitmapFontRun.h",
    "content": "#pragma once\n\n#include \"Slate.h\"\n#include \"BitmapFont.h\"\n\nclass FArrangedChildren;\nclass FPaintArgs;\nclass FSlateWindowElementList;\nstruct FTextBlockStyle;\nenum class ETextHitPoint : uint8;\n\nclass FAIRYGUI_API FBitmapFontRun : public ISlateRun, public TSharedFromThis< FBitmapFontRun >\n{\npublic:\n\n    static TSharedRef< FBitmapFontRun > Create(const TSharedRef< const FString >& InText, const TSharedRef<FBitmapFont>& InFont, const FTextRange& InRange);\n\npublic:\n\n    virtual ~FBitmapFontRun();\n\n    virtual FTextRange GetTextRange() const override;\n    virtual void SetTextRange(const FTextRange& Value) override;\n\n    virtual int16 GetBaseLine(float Scale) const override;\n    virtual int16 GetMaxHeight(float Scale) const override;\n\n    virtual FVector2D Measure(int32 StartIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const override;\n\n    virtual int8 GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const override;\n\n    virtual TSharedRef< ILayoutBlock > CreateBlock(int32 StartIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer) override;\n\n    virtual int32 OnPaint(const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n\n    virtual const TArray< TSharedRef<SWidget> >& GetChildren() override;\n\n    virtual void ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n\n    virtual int32 GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint = nullptr) const override;\n\n    virtual FVector2D GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const override;\n\n    virtual void BeginLayout() override {}\n    virtual void EndLayout() override {}\n\n    virtual void Move(const TSharedRef<FString>& NewText, const FTextRange& NewRange) override;\n    virtual TSharedRef<IRun> Clone() const override;\n\n    virtual void AppendTextTo(FString& AppendToText) const override;\n    virtual void AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const override;\n\n    virtual const FRunInfo& GetRunInfo() const override;\n\n    virtual ERunAttributes GetRunAttributes() const override;\n\nprotected:\n\n    FBitmapFontRun(const TSharedRef< const FString >& InText, const TSharedRef<FBitmapFont>& InFont, const FTextRange& InRange);\n\nprivate:\n    TSharedRef< const FString > Text;\n    FTextRange Range;\n\n    TSharedRef<FBitmapFont> Font;\n    FBitmapFont::FGlyph* Glyph;\n    FSlateBrush Brush;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/HitTest.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n\nclass FAIRYGUI_API IHitTest\n{\npublic:\n    virtual bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const = 0;\n};\n\nstruct FAIRYGUI_API FPixelHitTestData\n{\npublic:\n    int32 PixelWidth;\n    float Scale;\n    TArray<uint8> Pixels;\n\n    void Load(class FByteBuffer* Buffer);\n};\n\nclass FAIRYGUI_API FPixelHitTest : public IHitTest\n{\npublic:\n    FPixelHitTest(const TSharedPtr<FPixelHitTestData>& Data, int32 OffsetX, int32 OffsetY);\n    virtual ~FPixelHitTest();\n\n    bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const;\n\n    int32 OffsetX;\n    int32 OffsetY;\n\nprivate:\n    TSharedPtr<FPixelHitTestData> Data;\n};\n\nclass UGObject;\nclass FAIRYGUI_API FChildHitTest : public IHitTest\n{\npublic:\n    FChildHitTest(UGObject* InObj);\n\tvirtual ~FChildHitTest();\n\n    bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const;\n\n    TWeakObjectPtr<UGObject> Obj;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/LoaderRun.h",
    "content": "#pragma once\n\n#include \"Slate.h\"\n#include \"Utils/HTMLElement.h\"\n\nclass UFairyApplication;\nclass FArrangedChildren;\nclass FPaintArgs;\nclass FSlateWindowElementList;\nstruct FTextBlockStyle;\nenum class ETextHitPoint : uint8;\n\nclass FAIRYGUI_API FLoaderRun : public ISlateRun, public TSharedFromThis< FLoaderRun >, public FGCObject\n{\npublic:\n    static TSharedRef< FLoaderRun > Create(UFairyApplication* App, const FHTMLElement& InHTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange);\n\npublic:\n    virtual ~FLoaderRun();\n\n    virtual FTextRange GetTextRange() const override;\n    virtual void SetTextRange(const FTextRange& Value) override;\n\n    virtual int16 GetBaseLine(float Scale) const override;\n    virtual int16 GetMaxHeight(float Scale) const override;\n\n    virtual FVector2D Measure(int32 StartIndex, int32 EndIndex, float Scale, const FRunTextContext& TextContext) const override;\n\n    virtual int8 GetKerning(int32 CurrentIndex, float Scale, const FRunTextContext& TextContext) const override;\n\n    virtual TSharedRef< ILayoutBlock > CreateBlock(int32 StartIndex, int32 EndIndex, FVector2D Size, const FLayoutBlockTextContext& TextContext, const TSharedPtr< IRunRenderer >& Renderer) override;\n\n    virtual int32 OnPaint(const FPaintArgs& Args, const FTextLayout::FLineView& Line, const TSharedRef< ILayoutBlock >& Block, const FTextBlockStyle& DefaultStyle, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n\n    virtual const TArray< TSharedRef<SWidget> >& GetChildren() override;\n\n    virtual void ArrangeChildren(const TSharedRef< ILayoutBlock >& Block, const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n\n    virtual int32 GetTextIndexAt(const TSharedRef< ILayoutBlock >& Block, const FVector2D& Location, float Scale, ETextHitPoint* const OutHitPoint = nullptr) const override;\n\n    virtual FVector2D GetLocationAt(const TSharedRef< ILayoutBlock >& Block, int32 Offset, float Scale) const override;\n\n    virtual void BeginLayout() override {}\n    virtual void EndLayout() override {}\n\n    virtual void Move(const TSharedRef<FString>& NewText, const FTextRange& NewRange) override;\n    virtual TSharedRef<IRun> Clone() const override;\n\n    virtual void AppendTextTo(FString& AppendToText) const override;\n    virtual void AppendTextTo(FString& AppendToText, const FTextRange& PartialRange) const override;\n\n    virtual const FRunInfo& GetRunInfo() const override;\n\n    virtual ERunAttributes GetRunAttributes() const override;\n\n    virtual void AddReferencedObjects(FReferenceCollector& Collector) override;\n\nprotected:\n    FLoaderRun(UFairyApplication* App, const FHTMLElement& HTMLElement, const TSharedRef< const FString >& InText, const FTextRange& InRange);\n\nprivate:\n    TArray< TSharedRef<SWidget> > Children;\n    FHTMLElement HTMLElement;\n    TSharedRef< const FString > Text;\n    FTextRange Range;\n    class UGLoader* Loader;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/EllipseMesh.h",
    "content": "#pragma once\n\n#include \"MeshFactory.h\"\n#include \"Widgets/HitTest.h\"\n\nclass FAIRYGUI_API FEllipseMesh : public IMeshFactory, public IHitTest\n{\npublic:\n    MESHFACTORY_TYPE(FEllipseMesh, this)\n\n    FEllipseMesh();\n    virtual ~FEllipseMesh() {}\n\n    TOptional<FBox2D> DrawRect;\n    float LineWidth;\n    FColor LineColor;\n    TOptional<FColor> CenterColor;\n    TOptional<FColor> FillColor;\n    float StartDegree;\n    float EndDegreee;\n\n    void OnPopulateMesh(FVertexHelper& Helper);\n    bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/FillMesh.h",
    "content": "#pragma once\n\n#include \"MeshFactory.h\"\n#include \"UI/FieldTypes.h\"\n\nclass FAIRYGUI_API FFillMesh : public IMeshFactory\n{\npublic:\n    MESHFACTORY_TYPE(FFillMesh, nullptr)\n\n    FFillMesh();\n    virtual ~FFillMesh() {}\n\n    EFillMethod Method;\n    int32 Origin;\n    bool bClockwise;\n    float Amount;\n\n    void OnPopulateMesh(FVertexHelper& Helper);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/MeshFactory.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"VertexHelper.h\"\n#include \"Widgets/HitTest.h\"\n\n#define MESHFACTORY_TYPE(TYPE, HITTEST) \\\n    static const FName& GetMeshFactoryTypeId() { static FName Type(TEXT(#TYPE)); return Type; } \\\n    virtual bool IsMeshFactoryOfType(const FName& Type) const override { return GetMeshFactoryTypeId() == Type; } \\\n    virtual IHitTest* GetMeshHitTest() const { return (IHitTest*)HITTEST; }\n\nclass FAIRYGUI_API IMeshFactory\n{\npublic:\n    virtual void OnPopulateMesh(FVertexHelper& Helper) = 0;\n    virtual bool IsMeshFactoryOfType(const FName& Type) const = 0;\n    virtual IHitTest* GetMeshHitTest() const = 0;\n};\n\nclass FAIRYGUI_API FMeshFactory : public  IMeshFactory\n{\npublic:\n    FMeshFactory(IMeshFactory* InSourceFactory)\n    {\n        SourceFactory = InSourceFactory;\n    }\n\n    inline virtual void OnPopulateMesh(FVertexHelper& Helper) override\n    {\n        SourceFactory->OnPopulateMesh(Helper);\n    }\n\n    inline virtual bool IsMeshFactoryOfType(const FName& Type) const override\n    {\n        return SourceFactory->IsMeshFactoryOfType(Type);\n    }\n\n    inline virtual IHitTest* GetMeshHitTest() const override\n    {\n        return SourceFactory->GetMeshHitTest();\n    }\n\n    IMeshFactory* SourceFactory;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/PolygonMesh.h",
    "content": "#pragma once\n\n#include \"MeshFactory.h\"\n\nclass FAIRYGUI_API FPolygonMesh : public IMeshFactory, public IHitTest\n{\npublic:\n    MESHFACTORY_TYPE(FPolygonMesh, this)\n\n    FPolygonMesh();\n    virtual ~FPolygonMesh() {}\n\n    TArray<FVector2D> Points;\n    TArray<FVector2D> Texcoords;\n    float LineWidth;\n    FColor LineColor;\n    TOptional<FColor> FillColor;\n    TOptional<TArray<FColor>> Colors;\n    bool bUsePercentPositions;\n\n    void OnPopulateMesh(FVertexHelper& Helper);\n    bool HitTest(const FBox2D& ContentRect, const FVector2D& LayoutScaleMultiplier, const FVector2D& LocalPoint) const;\n\nprivate:\n    void DrawOutline(FVertexHelper& Helper);\n    bool IsPointInTriangle(const FVector2D& p, const FVector2D& a, const FVector2D& b, const FVector2D& c);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/RectMesh.h",
    "content": "#pragma once\n\n#include \"MeshFactory.h\"\n\nclass FAIRYGUI_API FRectMesh : public IMeshFactory\n{\npublic:\n    MESHFACTORY_TYPE(FRectMesh, nullptr)\n\n    FRectMesh();\n    virtual ~FRectMesh() {}\n\n    TOptional<FBox2D> DrawRect;\n    float LineWidth;\n    FColor LineColor;\n    TOptional<FColor> FillColor;\n    TOptional<TArray<FColor>> Colors;\n\n    void OnPopulateMesh(FVertexHelper& Helper);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/RegularPolygonMesh.h",
    "content": "#pragma once\n\n#include \"MeshFactory.h\"\n\nclass FAIRYGUI_API FRegularPolygonMesh : public IMeshFactory\n{\npublic:\n    MESHFACTORY_TYPE(FRegularPolygonMesh, nullptr)\n\n    FRegularPolygonMesh();\n    virtual ~FRegularPolygonMesh() {}\n\n    TOptional<FBox2D> DrawRect;\n    int32 Sides;\n    float LineWidth;\n    FColor LineColor;\n    TOptional<FColor> CenterColor;\n    TOptional<FColor> FillColor;\n    TArray<float> Distances;\n    float Rotation;\n\n    void OnPopulateMesh(FVertexHelper& Helper);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/RoundedRectMesh.h",
    "content": "#pragma once\n\n#include \"MeshFactory.h\"\n\nclass FAIRYGUI_API FRoundedRectMesh : public IMeshFactory\n{\npublic:\n    MESHFACTORY_TYPE(FRoundedRectMesh, nullptr)\n\n    FRoundedRectMesh();\n    virtual ~FRoundedRectMesh() {}\n\n    TOptional<FBox2D> DrawRect;\n    float LineWidth;\n    FColor LineColor;\n    TOptional<FColor> FillColor;\n    float TopLeftRadius;\n    float TopRightRadius;\n    float BottomLeftRadius;\n    float BottomRightRadius;\n\n    void OnPopulateMesh(FVertexHelper& Helper);\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/Mesh/VertexHelper.h",
    "content": "#pragma once\n\n#include \"Slate.h\"\n\nclass FAIRYGUI_API FVertexHelper\n{\npublic:\n    FVertexHelper();\n\n    void Clear();\n    int32 GetVertexCount() const;\n\n    void AddVertex(const FVector2D& Position);\n    void AddVertex(const FVector2D& Position, const FColor& Color);\n    void AddVertex(const FVector2D& Position, const FColor& Color, const FVector2D& TexCoords);\n\n    void AddQuad(const FBox2D& VertRect);\n    void AddQuad(const FBox2D& VertRect, const FColor& Color);\n    void AddQuad(const FBox2D& VertRect, const FColor& Color, const FBox2D& InUVRect);\n\n    void RepeatColors(FColor* Colors, int32 ColorCount, int32 StartIndex, int32 Count);\n\n    void AddTriangle(SlateIndex idx0, SlateIndex idx1, SlateIndex idx2);\n    void AddTriangles(const SlateIndex* Indice, int32 IndiceLength, int32 StartVertexIndex = 0);\n    void AddTriangles(int32 StartVertexIndex = 0);\n\n    const FVector2D& GetPosition(int32 Index);\n    FVector2D GetUVAtPosition(const FVector2D& Position, bool bUsePercent);\n\n    void Append(const FVertexHelper& VertexHelper);\n    void Insert(const FVertexHelper& VertexHelper);\n\npublic:\n    FBox2D ContentRect;\n    FBox2D UVRect;\n    FColor VertexColor;\n    FVector2D TextureSize;\n\n    TArray<FSlateVertex> Vertices;\n    TArray<SlateIndex> Triangles;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/MeshFactory.h",
    "content": "#pragma once\n\n#include \"VertexHelper.h\"\n\n#define MESHFACTORY_TYPE(TYPE) \\\n\tstatic const FName& GetMeshFactoryTypeId() { static FName Type(TEXT(#TYPE)); return Type; } \\\n\tvirtual bool IsMeshFactoryOfType(const FName& Type) const override { return GetMeshFactoryTypeId() == Type; }\n\nclass FAIRYGUI_API IMeshFactory\n{\npublic:\n    virtual void OnPopulateMesh(FVertexHelper& Helper) = 0;\n    virtual bool IsMeshFactoryOfType(const FName& Type) const = 0;\n};\n\nclass FAIRYGUI_API FMeshFactory : public  IMeshFactory\n{\npublic:\n    FMeshFactory(IMeshFactory* InSourceFactory)\n    {\n        SourceFactory = InSourceFactory;\n    }\n\n    inline virtual void OnPopulateMesh(FVertexHelper& Helper) override\n    {\n        SourceFactory->OnPopulateMesh(Helper);\n    }\n\n    inline virtual bool IsMeshFactoryOfType(const FName& Type) const override\n    {\n        return SourceFactory->IsMeshFactoryOfType(Type);\n    }\n\n    IMeshFactory* SourceFactory;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/NGraphics.h",
    "content": "#pragma once\n\n#include \"Mesh/MeshFactory.h\"\n#include \"NTexture.h\"\n#include \"UI/FieldTypes.h\"\n\nclass FAIRYGUI_API FNGraphics : public FGCObject\n{\npublic:\n    FNGraphics();\n    virtual ~FNGraphics();\n\n    const FColor& GetColor() const { return Color; }\n    void SetColor(const FColor& InColor);\n\n    EFlipType GetFlip() const { return Flip; }\n    void SetFlip(EFlipType Value);\n\n    void SetTexture(UNTexture* InTexture);\n    UNTexture* GetTexture() const { return Texture; }\n\n    void SetMeshFactory(const TSharedPtr<IMeshFactory>& InMeshFactory);\n    const TSharedPtr<IMeshFactory>& GetMeshFactory() { return MeshFactory; }\n    template <typename T> T& GetMeshFactory();\n\n    void SetMeshDirty() { bMeshDirty = true; }\n\n    void Paint(const FGeometry& AllottedGeometry,\n        FSlateWindowElementList& OutDrawElements,\n        int32 LayerId,\n        float Alpha,\n        bool bEnabled);\n\n    void PopulateDefaultMesh(FVertexHelper& Helper);\n\n    virtual void AddReferencedObjects(FReferenceCollector& Collector) override;\n\nprivate:\n    void UpdateMeshNow();\n\n    FVector2D Size;\n    FColor Color;\n    EFlipType Flip;\n\n    UNTexture* Texture;\n    FSlateBrush Brush;\n    FSlateResourceHandle ResourceHandle;\n    TSharedPtr<IMeshFactory> MeshFactory;\n\n    TArray<FSlateVertex> Vertices;\n    TArray<SlateIndex> Triangles;\n    TArray<FVector2D> PositionsBackup;\n    TArray<float> AlphaBackup;\n    float UsingAlpha;\n    bool bMeshDirty;\n};\n\ntemplate <typename T>\ninline T& FNGraphics::GetMeshFactory()\n{\n    if (MeshFactory.IsValid() && MeshFactory->IsMeshFactoryOfType(T::GetMeshFactoryTypeId()))\n        return *static_cast<T*>(MeshFactory.Get());\n\n    T* Ret = new T();\n    MeshFactory = MakeShareable(Ret);\n    return *Ret;\n}"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/NTextFormat.h",
    "content": "#pragma once\n\n#include \"Slate.h\"\n#include \"UI/FieldTypes.h\"\n#include \"NTextFormat.generated.h\"\n\nUSTRUCT(BlueprintType)\nstruct FAIRYGUI_API FNTextFormat\n{\n    GENERATED_USTRUCT_BODY()\npublic:\n    FNTextFormat();\n    bool EqualStyle(const FNTextFormat& AnotherFormat) const;\n    FTextBlockStyle GetStyle() const;\n\npublic:\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FString Face;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 Size;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FColor Color;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bBold;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bItalic;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    bool bUnderline;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 LineSpacing;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 LetterSpacing;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    EAlignType Align;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    EVerticalAlignType VerticalAlign;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FColor OutlineColor;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    int32 OutlineSize;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FColor ShadowColor;\n\n    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = \"FairyGUI\")\n    FVector2D ShadowOffset;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/NTexture.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Runtime/Engine/Classes/Engine/Texture2D.h\"\n#include \"NTexture.generated.h\"\n\nUCLASS()\nclass FAIRYGUI_API UNTexture : public UObject\n{\n    GENERATED_BODY()\n\npublic:\n    static UNTexture* GetWhiteTexture();\n    static void DestroyWhiteTexture();\n\n    UNTexture();\n\n    UPROPERTY(Transient)\n    UNTexture* Root;\n    UPROPERTY(Transient)\n    UTexture2D* NativeTexture;\n\n    FBox2D UVRect;\n    bool bRotated;\n    FBox2D Region;\n    FVector2D Offset;\n    FVector2D OriginalSize;\n\n    void Init(UTexture2D* NewNativeTexture);\n    void Init(UTexture2D* NewNativeTexture, float ScaleX, float ScaleY);\n    void Init(UTexture2D* NewNativeTexture, const FBox2D& NewRegion);\n    void Init(UNTexture* NewRoot, const FBox2D& NewRegion, bool bNewRotated);\n    void Init(UNTexture* NewRoot, const FBox2D& NewRegion, bool bNewRotated, const FVector2D& NewOriginalSize, const FVector2D& NewOffset);\n\n    FVector2D GetSize() const;\n    FBox2D GetDrawRect(FBox2D& InDrawRect) const;\n\nprivate:\n    static UNTexture* WhiteTexture;\n\n    friend class UFairyApplication;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/SContainer.h",
    "content": "#pragma once\n\n#include \"SDisplayObject.h\"\n\nclass FAIRYGUI_API SContainer : public SDisplayObject\n{\npublic:\n    SLATE_BEGIN_ARGS(SContainer) :\n        _GObject(nullptr)\n    {}\n    SLATE_ARGUMENT(UGObject*, GObject)\n    SLATE_END_ARGS()\n\n    SContainer();\n\n    void Construct(const FArguments& InArgs);\n\n    void AddChild(const TSharedRef<SWidget>& SlotWidget);\n    void AddChildAt(const TSharedRef<SWidget>& SlotWidget, int32 Index);\n    int32 GetChildIndex(const TSharedRef<SWidget>& SlotWidget) const;\n    void SetChildIndex(const TSharedRef<SWidget>& SlotWidget, int32 Index);\n    void RemoveChild(const TSharedRef<SWidget>& SlotWidget);\n    void RemoveChildAt(int32 Index);\n    void RemoveChildren(int32 BeginIndex = 0, int32 EndIndex = -1);\n    int32 NumChildren() const;\n\npublic:\n    virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n    virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n    virtual FChildren* GetChildren() override;\n\nprotected:\n    TPanelChildren<FSlotBase> Children;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/SDisplayObject.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"UObject/NoExportTypes.h\"\n#include \"Slate.h\"\n\nclass UGObject;\n\nclass FAIRYGUI_API SDisplayObject : public SWidget\n{\npublic:\n    SLATE_BEGIN_ARGS(SDisplayObject) :\n        _GObject(nullptr),\n        _Tag(SDisplayObject::SDisplayObjectTag)\n    {\n    }\n    SLATE_ARGUMENT(UGObject*, GObject)\n    SLATE_ARGUMENT(FName, Tag)\n    SLATE_END_ARGS()\n\n    static FName SDisplayObjectTag;\n\n    SDisplayObject();\n    void Construct(const FArguments& InArgs);\n\n    const FVector2D& GetPosition() const;\n    void SetPosition(const FVector2D& InPosition);\n    void SetX(float InX);\n    void SetY(float InY);\n\n    void SetSize(const FVector2D& InSize);\n    FVector2D GetSize() const { return Size; }\n\n    void SetVisible(bool bInVisible);\n    bool IsVisible() const { return bVisible; }\n\n    void SetTouchable(bool bInTouchable);\n    bool IsTouchable() const { return bTouchable; }\n\n    void SetOpaque(bool bInOpaque);\n    bool IsOpaque() const { return bOpaque; }\n\n    void SetInteractable(bool bInInteractable);\n    virtual bool IsInteractable() const override { return bInteractable; }\n\n    void UpdateVisibilityFlags();\n\n    virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;\n    virtual FReply OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;\n    virtual FReply OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;\n    virtual FReply OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;\n    virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;\n    virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override;\n    virtual FReply OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;\n\n    TWeakObjectPtr<class UGObject> GObject;\n\n    static bool IsWidgetOnStage(const TSharedPtr<SWidget>& InWidget);\n    static UGObject* GetWidgetGObject(const TSharedPtr<SWidget>& InWidget);\n    static UGObject* GetWidgetGObjectIfOnStage(const TSharedPtr<SWidget>& InWidget);\n    static void GetWidgetDescendants(const TSharedRef<SWidget>& InWidget, TArray<UGObject*>& OutArray);\n    static void GetWidgetPathToRoot(const TSharedRef<SWidget>& InWidget, TArray<UGObject*>& OutArray);\n\nprotected:\n    virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override;\n    virtual FChildren* GetChildren() override;\n    virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n    virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n\n    EVisibility GetVisibilityFlags() const;\n\nprotected:\n    uint8 bVisible : 1;\n    uint8 bInteractable : 1;\n    uint8 bTouchable : 1;\n    uint8 bOpaque : 1;\n    FVector2D Size;\n\n    static bool bMindVisibleOnly;\n\nprivate:\n    static FNoChildren NoChildrenInstance;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/SFImage.h",
    "content": "#pragma once\n\n#include \"SDisplayObject.h\"\n#include \"UI/FieldTypes.h\"\n#include \"Mesh/FillMesh.h\"\n#include \"NTexture.h\"\n#include \"NGraphics.h\"\n\nclass FAIRYGUI_API SFImage : public SDisplayObject, public IMeshFactory\n{\npublic:\n    SLATE_BEGIN_ARGS(SFImage) :\n        _GObject(nullptr)\n    {}\n    SLATE_ARGUMENT(UGObject*, GObject)\n    SLATE_END_ARGS()\n\n    MESHFACTORY_TYPE(SFImage, nullptr)\n\n    SFImage();\n\n\tvoid Construct(const FArguments& InArgs);\n\n    void SetTexture(UNTexture* InTexture);\n    UNTexture* GetTexture() const { return Graphics.GetTexture();  }\n    void SetNativeSize();\n    void SetScale9Grid(const TOptional<FBox2D>& GridRect);\n    void SetScaleByTile(bool bInScaleByTile);\n    void SetTileGridIndice(int32 InTileGridIndex);\n\n    EFillMethod GetFillMethod() const;\n    void SetFillMethod(EFillMethod Method);\n    int32 GetFillOrigin() const;\n    void SetFillOrigin(int32 Origin);\n    bool IsFillClockwise() const;\n    void SetFillClockwise(bool bClockwise);\n    float GetFillAmount() const;\n    void SetFillAmount(float Amount);\n\n    FNGraphics Graphics;\npublic:\n\n\t// SWidget overrides\n\tvirtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n    virtual void OnPopulateMesh(FVertexHelper& Helper) override;\n\nprotected:\n    void TileFill(FVertexHelper& Helper, const FBox2D& ContentRect, const FBox2D& UVRect, const FVector2D& TextureSize);\n    void SliceFill(FVertexHelper& Helper);\n\nprotected:\n    TOptional<FBox2D> Scale9Grid;\n    bool bScaleByTile;\n    FVector2D TextureScale;\n    int32 TileGridIndice;\n    TUniquePtr<FFillMesh> FillMesh;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/SMovieClip.h",
    "content": "#pragma once\n\n#include \"SFImage.h\"\n\nstruct FAIRYGUI_API FMovieClipData : public FGCObject\n{\n    struct Frame\n    {\n        UNTexture *Texture;\n        float AddDelay;\n    };\n\n    TArray<Frame> Frames;\n    float Interval;\n    float RepeatDelay;\n    bool bSwing;\n\n    FMovieClipData();\n    virtual void AddReferencedObjects(FReferenceCollector& Collector) override;\n};\n\nclass FAIRYGUI_API SMovieClip : public SFImage\n{\npublic:\n    SLATE_BEGIN_ARGS(SMovieClip) :\n        _GObject(nullptr)\n    {}\n    SLATE_ARGUMENT(UGObject*, GObject)\n    SLATE_END_ARGS()\n\n        SMovieClip();\n\n    void Construct(const FArguments& InArgs);\n\n    void SetClipData(TSharedPtr<FMovieClipData> InData);\n    const TSharedPtr<FMovieClipData>& GetClipData() const { return Data; }\n\n    bool IsPlaying() const { return bPlaying; }\n    void SetPlaying(bool bInPlaying);\n\n    int32 GetFrame() const { return Frame; }\n    void SetFrame(int32 InFrame);\n\n    float GetTimeScale() const { return TimeScale; }\n    void SetTimeScale(float InTimeScale);\n\n    void Advance(float Time);\n\n    //from start to end(-1 means ending) repeat times(0 means infinite loop) when all is over, stopping at endAt(-1 means same value of end)\n    void SetPlaySettings(int32 InStart = 0, int32 InEnd = -1, int32 InTimes = 0, int32 InEndAt = -1, const FSimpleDelegate& InCompleteCallback = FSimpleDelegate());\n\npublic:\n\n    // SWidget overrides\n    virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;\n\nprotected:\n    void DrawFrame();\n\n    TSharedPtr<FMovieClipData> Data;\n    int32 Frame;\n    bool bPlaying;\n    float TimeScale;\n    int32 Start;\n    int32 End;\n    int32 Times;\n    int32 EndAt;\n    int32 Status; //0-none, 1-next loop, 2-ending, 3-ended\n    FSimpleDelegate CompleteCallback;\n\n    float FrameElapsed;\n    bool bReversed;\n    int32 RepeatedCount;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/SShape.h",
    "content": "#pragma once\n\n#include \"SDisplayObject.h\"\n#include \"NTexture.h\"\n#include \"NGraphics.h\"\n\nclass FAIRYGUI_API SShape : public SDisplayObject\n{\npublic:\n    SLATE_BEGIN_ARGS(SShape) :\n        _GObject(nullptr)\n    {}\n    SLATE_ARGUMENT(UGObject*, GObject)\n    SLATE_END_ARGS()\n\n    SShape();\n\n\tvoid Construct(const FArguments& InArgs);\n\n    FNGraphics Graphics;\npublic:\n\n\t// SWidget overrides\n\tvirtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/STextField.h",
    "content": "#pragma once\n\n#include \"SDisplayObject.h\"\n#include \"UI/FieldTypes.h\"\n#include \"NTextFormat.h\"\n#include \"Utils/HTMLElement.h\"\n\nclass FSlateTextLayout;\nclass FSlateTextUnderlineLineHighlighter;\n\nclass FAIRYGUI_API STextField : public SDisplayObject\n{\npublic:\n    SLATE_BEGIN_ARGS(STextField) :\n        _GObject(nullptr)\n    {}\n    SLATE_ARGUMENT(UGObject*, GObject)\n        SLATE_END_ARGS()\n\n        STextField();\n    void Construct(const FArguments& InArgs);\n\n    const FString& GetText() const { return Text; }\n    void SetText(const FString& InText, bool bInHTML = false);\n\n    EAutoSizeType GetAutoSize() const { return AutoSize; };\n    void SetAutoSize(EAutoSizeType InAutoSize);\n\n    bool IsSingleLine() const { return bSingleLine; }\n    void SetSingleLine(bool InSingleLine);\n\n    FNTextFormat& GetTextFormat() { return TextFormat; }\n    void SetTextFormat(const FNTextFormat& InFormat);\n\n    float GetMaxWidth() const { return MaxWidth; }\n    void SetMaxWidth(float InMaxWidth);\n\n    FVector2D GetTextSize();\n\n    virtual FChildren* GetChildren() override;\n    virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n\nprotected:\n    virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const override;\n    virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n    virtual bool ComputeVolatility() const override { return true; }\n    void UpdateTextLayout();\n\n    void BuildLines();\n\nprotected:\n    FString Text;\n    bool bHTML;\n    EAutoSizeType AutoSize;\n    bool bSingleLine;\n    float MaxWidth;\n    FNTextFormat TextFormat;\n\n    TSharedRef<FSlateTextLayout> TextLayout;\n    TArray<FHTMLElement> HTMLElements;\n};"
  },
  {
    "path": "Source/FairyGUI/Public/Widgets/STextInput.h",
    "content": "#pragma once\n\n#include \"SDisplayObject.h\"\n#include \"NTextFormat.h\"\n\nclass FAIRYGUI_API STextInput : public SDisplayObject\n{\npublic:\n    SLATE_BEGIN_ARGS(STextInput) :\n        _GObject(nullptr)\n    {}\n    SLATE_ARGUMENT(UGObject*, GObject)\n    SLATE_END_ARGS()\n\n    STextInput();\n    void Construct(const FArguments& InArgs);\n\n    void SetPassword(bool bInPassword);\n    void SetSingleLine(bool bInSingleLine);\n    void SetTextFormat(const FNTextFormat& InTextFormat);\n    void SetOnTextChanged(FOnTextChanged Callback);\n    void SetOnTextCommitted(FOnTextCommitted Callback);\n\n    virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;\n    virtual FChildren* GetChildren() override;\n    virtual void OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const override;\n\n    TSharedRef<class SMultiLineEditableText> Widget;\n\nprotected:\n    FSimpleSlot ChildSlot;\n};"
  },
  {
    "path": "Source/FairyGUIEditor/FairyGUIEditor.Build.cs",
    "content": "// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.\n\nusing UnrealBuildTool;\n\npublic class FairyGUIEditor : ModuleRules\n{\n\tpublic FairyGUIEditor(ReadOnlyTargetRules Target) : base(Target)\n\t{\n\t\tPCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;\n\t\t\n\t\tPublicIncludePaths.AddRange(\n\t\t\tnew string[] {\n\t\t\t\t// ... add public include paths required here ...\n\t\t\t}\n\t\t\t);\n\t\t\t\t\n\t\t\n\t\tPrivateIncludePaths.AddRange(\n\t\t\tnew string[] {\n\t\t\t\t// ... add other private include paths required here ...\n\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\n\t\tPublicDependencyModuleNames.AddRange(\n\t\t\tnew string[]\n\t\t\t{\n\t\t\t\t\"Core\",\n\t\t\t\t// ... add other public dependencies that you statically link with here ...\n\t\t\t}\n\t\t\t);\n\t\t\t\n\t\t\n\t\tPrivateDependencyModuleNames.AddRange(\n\t\t\tnew string[]\n\t\t\t{\n\t\t\t\t\"FairyGUI\",\n\t\t\t\t\"CoreUObject\",\n\t\t\t\t\"Engine\",\n\t\t\t\t\"Slate\",\n\t\t\t\t\"SlateCore\",\n                \"UnrealEd\",\n\t\t\t\t// ... add private dependencies that you statically link with here ...\t\n\t\t\t}\n\t\t\t);\n\t\t\n\t\t\n\t\tDynamicallyLoadedModuleNames.AddRange(\n\t\t\tnew string[]\n\t\t\t{\n\t\t\t\t// ... add any modules that your module loads dynamically here ...\n\t\t\t}\n\t\t\t);\n\t}\n}\n"
  },
  {
    "path": "Source/FairyGUIEditor/Private/FairyGUIEditor.cpp",
    "content": "// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.\n\n#include \"FairyGUIEditor.h\"\n#include \"Editor.h\"\n\n#define LOCTEXT_NAMESPACE \"FFairyGUIEditorModule\"\n\nvoid FFairyGUIEditorModule::StartupModule()\n{\n\t// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module\n}\n\nvoid FFairyGUIEditorModule::ShutdownModule()\n{\n\t// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,\n\t// we call this function before unloading the module.\n}\n\n#undef LOCTEXT_NAMESPACE\n\t\nIMPLEMENT_MODULE(FFairyGUIEditorModule, FairyGUIEditor)"
  },
  {
    "path": "Source/FairyGUIEditor/Private/FairyGUIFactory.cpp",
    "content": "#include \"FairyGUIFactory.h\"\n#include \"Serialization/BufferArchive.h\"\n#include \"EditorFramework/AssetImportData.h\"\n#include \"Misc/Paths.h\"\n#include \"Misc/FileHelper.h\"\n#include \"UIPackageAsset.h\"\n\nUFairyGUIFactory::UFairyGUIFactory()\n{\n    SupportedClass = UUIPackageAsset::StaticClass();\n    bEditorImport = true;\n    bCreateNew = false;\n    bText = false;\n    Formats.Add(TEXT(\"fui;FairyGUI package files\"));\n}\n\nUObject* UFairyGUIFactory::FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn)\n{\n    UUIPackageAsset* UIAsset = NewObject<UUIPackageAsset>(InParent, InName, Flags);\n\n    const int32 InDataSize = BufferEnd - Buffer;\n    UIAsset->Data.Empty(InDataSize);\n    UIAsset->Data.AddUninitialized(InDataSize);\n    FMemory::Memcpy(UIAsset->Data.GetData(), Buffer, InDataSize);\n\n    if (!UIAsset->AssetImportData)\n    {\n        UIAsset->AssetImportData = NewObject<UAssetImportData>(UIAsset, UAssetImportData::StaticClass());\n    }\n    UIAsset->AssetImportData->Update(CurrentFilename);\n\n    return UIAsset;\n}\n\nbool UFairyGUIFactory::CanReimport(UObject* Obj, TArray<FString>& OutFilenames)\n{\n    UUIPackageAsset* UIAsset = Cast<UUIPackageAsset>(Obj);\n    if (UIAsset && UIAsset->AssetImportData)\n    {\n        UIAsset->AssetImportData->ExtractFilenames(OutFilenames);\n        return true;\n    }\n    return false;\n}\n\nvoid UFairyGUIFactory::SetReimportPaths(UObject* Obj, const TArray<FString>& NewReimportPaths)\n{\n    UUIPackageAsset* UIAsset = Cast<UUIPackageAsset>(Obj);\n    if (UIAsset && ensure(NewReimportPaths.Num() == 1))\n    {\n        UIAsset->AssetImportData->UpdateFilenameOnly(NewReimportPaths[0]);\n    }\n}\n\nEReimportResult::Type UFairyGUIFactory::Reimport(UObject* Obj)\n{\n    UUIPackageAsset* UIAsset = Cast<UUIPackageAsset>(Obj);\n    if (!UIAsset)\n    {\n        return EReimportResult::Failed;\n    }\n\n    const FString Filename = UIAsset->AssetImportData->GetFirstFilename();\n\n    if (!Filename.Len() || IFileManager::Get().FileSize(*Filename) == INDEX_NONE)\n    {\n        return EReimportResult::Failed;\n    }\n\n    if (UFactory::StaticImportObject(\n        UIAsset->GetClass(),\n        UIAsset->GetOuter(),\n        *UIAsset->GetName(),\n        RF_Public | RF_Standalone,\n        *Filename,\n        NULL,\n        this))\n    {\n        if (UIAsset->GetOuter())\n        {\n            UIAsset->GetOuter()->MarkPackageDirty();\n        }\n        else\n        {\n            UIAsset->MarkPackageDirty();\n        }\n\n        return EReimportResult::Succeeded;\n    }\n    return EReimportResult::Failed;\n}"
  },
  {
    "path": "Source/FairyGUIEditor/Public/FairyGUIEditor.h",
    "content": "// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.\n\n#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Modules/ModuleManager.h\"\n\nclass FFairyGUIEditorModule : public IModuleInterface\n{\npublic:\n\n\t/** IModuleInterface implementation */\n\tvirtual void StartupModule() override;\n\tvirtual void ShutdownModule() override;\n};\n"
  },
  {
    "path": "Source/FairyGUIEditor/Public/FairyGUIFactory.h",
    "content": "#pragma once\n\n#include \"CoreMinimal.h\"\n#include \"Factories/Factory.h\"\n#include \"EditorReimportHandler.h\"\n#include \"FairyGUIFactory.generated.h\"\n\nUCLASS()\nclass FAIRYGUIEDITOR_API UFairyGUIFactory : public UFactory, public  FReimportHandler\n{\n\tGENERATED_BODY()\n\npublic:\n\tUFairyGUIFactory();\n\tvirtual UObject* FactoryCreateBinary(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn) override;\n\tvirtual bool CanReimport(UObject* Obj, TArray<FString>& OutFilenames)  override;\n\tvirtual void SetReimportPaths(UObject* Obj, const TArray<FString>&  NewReimportPaths) override;\n\tvirtual EReimportResult::Type Reimport(UObject* Obj) override;\n};\n"
  }
]